I am trying to make a seemingly simple piece of code that I am unable to get working.
It takes a double (or float) and formats it to a string in a specific way: E.g. 13.453.123,25
(Dots for thousands, commas for fractions? decimals? obligatory English not my first language etc…)
SI units "J: 13,453M"
or Scientific "J: 1,345E6"
Either is fine, although my preference is SI units. This string is going to be put on a tiny I2C 0,96″ display so it must be 10 chars wide. I am making a joulemeter with an Arduino Nano and I want to have a tally showing currently used energy on the display. And the actual accurate data will be stored on a uSD card.
I tried dtostre()
and sprintf()
but every time it would break the string. Dtostre()
did work in a Serial.println()
but not when trying to get it in a string.
Anyway here is my code so far:
#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 </>
If you need more info or anything else, feel free to ask!