我正在尝试编写一段看似简单的代码,但我无法正常工作。
它需要一个双精度(或浮点)并以特定方式将其格式化为字符串:例如
13.453.123,25
(点代表千位,逗号代表分数?小数?必修英语不是我的母语等等......)
SI 单位 "J: 13,453M"
或科学 "J: 1,345E6"
两者都可以,尽管我更喜欢 SI 单位。该字符串将被放置在一个微型 I2C 0,96" 显示屏上,因此它必须有 10 个字符宽。我正在使用 Arduino Nano 制作焦耳计,我希望在显示屏上显示当前使用的能量的计数。实际准确的数据将存储在美元卡上。
我尝试了
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 <> // https://circuitdigest.com/microcontroller-projects/arduino-timer-tutorial 2023-04-13
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 </>
如果您需要更多信息或其他任何信息,请随时询问!
编辑: 我设法让它在在线编译器上运行(是的 w3schools.com)
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 上测试它。
这不完全是我想要的,但足够接近并且有效!
String Fomat_Si(double Input){
uint8_t Si_Count = 0;
char Si[] = {' ', 'k', 'M', 'G', 'T', 'P', 'Z'};
while (Input > 1000) {
Si_Count++;
Intput /= 1000;
}
return "J: " + String(Input) + Si[Si_Count];
}