Arduino Nano焦耳计:将float/double格式化为SI单位或科学计数法
Arduino Nano焦耳计:能量值格式化问题
我正在基于Arduino Nano制作焦耳计,需要将float/double类型的能量值格式化为三种特定字符串格式,优先选择SI单位格式:
- 千分位用点、小数用逗号的格式(例如
13.453.123,25) - SI单位格式(例如
"J: 13,453M") - 科学计数法格式(例如
"J: 1,345E6")
生成的字符串需要适配0.96寸I2C显示屏,宽度限制为10字符,精确数据将存储在uSD卡中。
我尝试使用dtostre()和sprintf()函数,但均出现字符串损坏问题:dtostre()可在Serial.println()中正常输出,但无法存入字符串。
现有代码
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define Pin_Enable 2 #define Pin_Red 11 #define Pin_Green 12 #define Pin_Blue 13 #define Timer_Prefill 59285 // 59285 100ms Set Timer PreFill = 65 535 - (16*10^6 * 0.1 sec / 256) TCNTn = 65535 - ( ( 16*10^6 x intervaltime in sec ) / Pre_Scaler Value ) = bool Running = false; bool Write = false; uint32_t Previous_Time = 0; uint16_t Current = 0; uint16_t Voltage = 0; uint8_t Count = 0; float Energy = 0; Adafruit_SSD1306 Display(128, 64, &Wire, -1); void setup() { // <> Setup Hardware Timer <> noInterrupts(); // Turn off interrupts during adjusting settings TCCR1A = 0; // Initialize the Timer TCCR1B = 0; TCNT1 = Timer_Prefill; // Prefill Timer TCCR1B |= (1 << CS12); // Set the pre scaler to 256 interrupts(); // Turn on interrruptsDisplay // </> Setup Hardware Timer </> // <> Setup Pins <> pinMode(Pin_Enable, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(Pin_Enable), Recording, CHANGE); pinMode(Pin_Red, OUTPUT); pinMode(Pin_Green, OUTPUT); pinMode(Pin_Blue, OUTPUT); digitalWrite(Pin_Green, HIGH); // </> Setup Pins </> displayString.reserve(15); // to avoid fragmenting memory when using String Display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //0x78 / 0x3C delay(2000); Display.setTextSize(2); Display.setTextColor(WHITE); // text color Display.setCursor(0, 10); // position to displ DisplayWrite("Joulemeter REDACTED"); delay(5000); Serial.begin(115200); } void loop() { if(Write) { Add_Record(); Write = false; } } void DisplayWrite(String text) { int16_t x1; int16_t y1; uint16_t width; uint16_t height; Display.getTextBounds(text, 0, 0, &x1, &y1, &width, &height); Display.clearDisplay(); // clear Display Display.setCursor((128 - width) / 2, (64 - height) / 2); Display.println(text); // text to Display Display.display(); } void Recording(){ // Gets called everytime the button changes state. if (Previous_Time + 250 < millis()) { // Check if atleast 250ms have passed since last changed. This is to filter out switch bounces. Previous_Time = millis(); // Store the current time to Previous_Time for the next press. Running = !Running; // Toggle Running. if (Running) { // Start recording noInterrupts(); TIMSK1 |= (1 << TOIE1); // Turn on timer interrupts (Enable timer) TCNT1 = Timer_Prefill; // Prefill the timer interrupts(); digitalWrite(Pin_Green, LOW); digitalWrite(Pin_Red, HIGH); Serial.println("Started"); } else { // Stop recording Serial.println("Stopping"); } } } String MakeXLong(String Text, uint8_t Length) { while(Text.length() < Length) { Text = "0" + Text; } return Text; } void Add_Record(){ Count++; digitalWrite(Pin_Blue, HIGH); Voltage = map(analogRead(A0), 0, 1023, 0, 60000); Current = map(analogRead(A1), 0, 1023, 0, 65000); Energy += Voltage * Current * 0.1 * 0.001 * 0.001; if (Count >= 10) { // <> Generate Output <> String Temp_A = MakeXLong(String(Voltage), 5); String Temp_B = MakeXLong(String(Current), 5); String Disp_Text = ""; Disp_Text += "V: " + String(Temp_A[0]) + String(Temp_A[1]) + "," + String(Temp_A[2]) + String(Temp_A[3]) + String(Temp_A[4]) + " "; Disp_Text += "A: " + String(Temp_B[0]) + String(Temp_B[1]) + "," + String(Temp_B[2]) + String(Temp_B[3]) + String(Temp_B[4]) + " "; Disp_Text += "J: "; // </> Generate Output </> // <> Display Output <> DisplayWrite(Disp_Text); Serial.println("Next"); Serial.println("R: " + String(Voltage) + " - " + String(Current) + " - " + String(Energy)); // </> Display Output </> Count = 0; } delay(100); digitalWrite(Pin_Blue, LOW); } // <> Timer Interrupt Service Routine <> ISR(TIMER1_OVF_vect) { TCNT1 = Timer_Prefill; // Prefill the timer digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ^ 1); // Toggle the build in led // <> Code to be executed <> Write = true; if (!Running) { noInterrupts(); TIMSK1 &= !(1 << TOIE1); // Turn off timer interrupts (Disable timer) interrupts(); digitalWrite(Pin_Green, HIGH); digitalWrite(Pin_Red, LOW); Serial.println("Stopped"); } // </> Code to be executed </> } //</> Timer Interrupt Service Routine </>
补充验证代码
我已在在线编译器中完成功能验证,以下是示例代码:
SI单位格式验证代码(概念验证)
#include <iostream> #include <string> using namespace std; int main() { double Energy = 14999.25; uint8_t Si_Count = 0; char Si[] = {' ', 'k', 'M', 'G', 'T', 'P', 'Z'}; while (Energy > 1000) { Si_Count++; Energy /= 1000; } string Output = to_string((int)Energy) + Si[Si_Count]; cout << Output; }
科学计数法格式验证代码
#include <iostream> #include <string> using namespace std; int main() { float Energy = 14999.25; char Buffer [8]; sprintf(Buffer, "%.1E", Energy); string Output = "J: "; for (int i = 0; i < 8; i++){ Output += Buffer[i]; } cout << Output; return 0; }
我将在今晚测试这些代码在Arduino硬件上的运行情况。
内容的提问来源于stack exchange,提问作者OADINC
相关产品推荐
相关产品推荐

