Hello everyone,
I am building an Energy meter with automatic price calculation, reset function and recovery whenever a power cut occurs.
Now, I am facing a very strange problem with my setup (a NANO (connected to a SD card reader) and IDE 2.3.2).
The local variable usage is massively increased if I add a line such as "cut = cut + 1;", hence making my sketch unusable.
I wonder if I just discovered a bug... (or maybe I am the bug in the whole story)
(for 2 days I am trying to modify my sketch, make it smaller, more compact... but nothing seems to change the result)
It would be fantastic if somebody could try to figure out what happens and maybe tell me how to resolve the issue,
Please see below my sketch.
I marked the interesting lines with "**"...
The first one without the line "cut = cut + 1;"
and
the second one with the line "cut = cut + 1;"... and this is where the massive memory increase occurs.
How to increase the "cut" of 1 without increasing the memory usage massively?
Another possibility would be to completely leave the variable "cut" and all its corresponding lines out of the sketch... but strange fully, without the variable "cut", the memory usage increases also...
#include <SD.h>
#include "LiquidCrystal_I2C.h"
LiquidCrystal_I2C lcd(0x27, 20, 4);
const int buttonPin = 8;
unsigned long startMillis[3];
unsigned long endMillis[3];
double calib[3] = { 0.8646, 1.3125, 1.16 }; //without Resistor 33 Ohm (25 June 2024)
double kilos[3];
float pay[3];
float payt = 0;
float RMSCurrent[3];
float RMSPower[3];
float kilot = 0;
float lt = 0;
float mt = 0;
float ht = 0;
int currentPins[3] = { 1, 2, 3 };
int buttonState = 0;
int low = 0;
int medium = 0;
int high = 0;
int count = 1;
**int cut = 0; // problem: if cut = 0, and "line 164" is not present, then Global variables use 1584 bytes (77%) of dynamic memory, leaving 464 bytes for local variables. Maximum is 2048 bytes.**
int reset = 0;
byte one[8] = { 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x00 };
byte two[8] = { 0x00, 0x00, 0x18, 0x04, 0x08, 0x10, 0x1C, 0x00 };
byte three[8] = { 0x00, 0x00, 0x18, 0x04, 0x08, 0x04, 0x18, 0x00 };
byte baht[8] = { 0x04, 0x1E, 0x15, 0x1E, 0x15, 0x15, 0x1E, 0x04 };
byte aleft[8] = { 0x00, 0x00, 0x00, 0x01, 0x12, 0x14, 0x18, 0x1E };
File myFile0;
File myFile1;
File myFile2;
void setup() {
Serial.begin(115200);
SD.begin(4);
lcd.begin(20, 4);
lcd.init();
lcd.backlight();
lcd.createChar(1, one);
lcd.createChar(2, two);
lcd.createChar(3, three);
lcd.createChar(4, baht);
lcd.createChar(5, aleft);
pinMode(8, INPUT_PULLUP);
lcd.clear();
lcd.setCursor(6, 1);
lcd.print("3 Phase");
lcd.setCursor(4, 2);
lcd.print("Energy Meter");
lcd.setCursor(16, 3);
lcd.print("v30a");
delay(3000);
lcd.clear();
lcd.setCursor(4, 1);
lcd.print("PLEASE WAIT");
delay(1000);
lcd.setCursor(2, 2);
lcd.print("Retrieving Data");
lcd.setCursor(0, 3);
for (int i = 1; i <= 20; i++) {
delay(200);
lcd.print("x");
}
File myFile0;
myFile0 = SD.open("L0.txt", FILE_READ);
if (myFile0) {
lt = myFile0.parseFloat();
}
myFile0.close();
File myFile1;
myFile1 = SD.open("L1.txt", FILE_READ);
if (myFile1) {
mt = myFile1.parseFloat();
}
myFile1.close();
File myFile2;
myFile2 = SD.open("L2.txt", FILE_READ);
if (myFile2) {
ht = myFile2.parseFloat();
}
myFile2.close();
kilos[0] = lt;
kilos[1] = mt;
kilos[2] = ht;
lt = 0;
mt = 0;
ht = 0;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("DATA retrieved");
lcd.setCursor(0, 1);
lcd.print(kilos[0], 3);
lcd.print(" kW/h =L"
"\1");
lcd.setCursor(0, 2);
lcd.print(kilos[1], 3);
lcd.print(" kW/h =L"
"\2");
lcd.setCursor(0, 3);
lcd.print(kilos[2], 3);
lcd.print(" kW/h =L"
"\3");
delay(1000);
}
void readPhase() //Method to read information from CTs
{
for (int i = 0; i <= 2; i++) {
float current = 0;
float maxCurrent = 0;
float minCurrent = 1000;
for (int j = 0; j <= 200; j++) {
delay(4);
current = analogRead(currentPins[i]);
if (current >= maxCurrent)
maxCurrent = current;
else if (current <= minCurrent)
minCurrent = current;
}
if (maxCurrent <= 517) {
maxCurrent = 516;
}
RMSCurrent[i] = ((maxCurrent - 516) * 0.707107) / calib[i];
RMSPower[i] = 220 * RMSCurrent[i];
endMillis[i] = millis();
unsigned long time = (endMillis[i] - startMillis[i]);
kilos[i] = kilos[i] + ((double)RMSPower[i] * ((double)time / 60 / 60 / 1000000));
startMillis[i] = millis();
}
}
void loop() {
readPhase();
DResetscreen();
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
DKilowattHours();
**if (cut == 1) {**
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
}
delay(2300);
DRMSPower();
**if (cut == 1) {**
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
}
delay(2300);
DTotals();
**if (cut == 1) {**
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
}
delay(2300);
Dsavedata();
//De();
Resetnow();
}
void DResetscreen() {
**if (cut == 1) {**
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("RESET ? [v30a]");
delay(400);
lcd.setCursor(1, 1);
lcd.print("press 'RED' button");
lcd.setCursor(1, 2);
lcd.print("and hold for 3 sec");
delay(400);
for (int i = 0; i <= 3; i++)
lcd.setCursor(3, 3);
lcd.print("\5"
"--- NOW");
delay(500);
lcd.setCursor(3, 3);
lcd.print(" ");
delay(500);
}
}
void DKilowattHours() {
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Energy [kW/h]");
lcd.setCursor(0, 1);
lcd.print("L"
"\1"
" ");
lcd.print(kilos[0], 3);
lcd.print(" kW/h");
lcd.setCursor(0, 2);
lcd.print("L"
"\2"
" ");
lcd.print(kilos[1], 3);
lcd.print(" kW/h");
lcd.setCursor(0, 3);
lcd.print("L"
"\3"
" ");
lcd.print(kilos[2], 3);
lcd.print(" kW/h");
}
void DRMSPower() {
lcd.clear();
lcd.setCursor(7, 0);
lcd.print("Power [W]");
lcd.setCursor(0, 1);
lcd.print("L"
"\1"
" ");
lcd.print(RMSPower[0], 3);
lcd.print(" W");
lcd.setCursor(0, 2);
lcd.print("L"
"\2"
" ");
lcd.print(RMSPower[1], 3);
lcd.print(" W");
lcd.setCursor(0, 3);
lcd.print("L"
"\3"
" ");
lcd.print(RMSPower[2], 3);
lcd.print(" W");
}
void DTotals() {
lcd.clear();
kilot = kilos[0] + kilos[1] + kilos[2];
for (int i = 0; i <= 2; i++) {
if (kilos[i] < 150) {
lt = kilos[i];
low = 1;
medium = 0;
high = 0;
}
if (kilos[i] - 150 > 0) {
lt = 150;
mt = kilos[i] - 150;
low = 1;
medium = 1;
high = 0;
}
if (kilos[i] - 400 > 0) {
lt = 150;
mt = 250;
ht = kilos[i] - 400;
low = 1;
medium = 1;
high = 1;
}
pay[i] = (lt * 3.2484 * low) + (mt * 4.2218 * medium) + (ht * 4.4217 * high);
lt = 0;
mt = 0;
ht = 0;
low = 0;
medium = 0;
high = 0;
}
payt = pay[0] + pay[1] + pay[2];
lcd.setCursor(1, 0);
lcd.print("Total consumption");
lcd.setCursor(3, 1);
lcd.print("\xF6"
" (L"
"\1"
", L"
"\2"
", L"
"\3)");
lcd.setCursor(6, 2);
lcd.print(kilot, 3);
lcd.print(" kW/h");
lcd.setCursor(3, 3);
lcd.print("+/- ");
lcd.print(payt, 2);
lcd.print(" "
"\4");
}
void Dsavedata() {
count = count + 1;
if (count == 100) {
count = 1;
File myfile0 = SD.open("L0.txt", FILE_WRITE | O_TRUNC);
myFile0 = SD.open("L0.txt", FILE_WRITE);
if (myFile0) {
myFile0.print(kilos[0], 3);
}
myFile0.close();
File myfile1 = SD.open("L1.txt", FILE_WRITE | O_TRUNC);
myFile1 = SD.open("L1.txt", FILE_WRITE);
if (myFile1) {
myFile1.print(kilos[1], 3);
}
myFile1.close();
File myfile2 = SD.open("L2.txt", FILE_WRITE | O_TRUNC);
myFile2 = SD.open("L2.txt", FILE_WRITE);
if (myFile2) {
myFile2.print(kilos[2], 3);
}
myFile2.close();
lcd.clear();
lcd.setCursor(1, 1);
lcd.print("Successfully saved");
lcd.setCursor(4, 2);
lcd.print("to 'SD' card");
delay(600);
}
}
void Resetnow() {
if (reset == 1) {
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("!!! RESET !!!");
reset = 0;
for (int i = 0; i <= 2; i++) {
kilos[i] = 0;
}
lcd.setCursor(1, 2);
lcd.print("Counters all Reset");
}
}
#include <SD.h>
#include "LiquidCrystal_I2C.h"
LiquidCrystal_I2C lcd(0x27, 20, 4);
const int buttonPin = 8;
unsigned long startMillis[3];
unsigned long endMillis[3];
double calib[3] = { 0.8646, 1.3125, 1.16 }; //without Resistor 33 Ohm (25 June 2024)
double kilos[3];
float pay[3];
float payt = 0;
float RMSCurrent[3];
float RMSPower[3];
float kilot = 0;
float lt = 0;
float mt = 0;
float ht = 0;
int currentPins[3] = { 1, 2, 3 };
int buttonState = 0;
int low = 0;
int medium = 0;
int high = 0;
int count = 1;
**int cut = 0; // problem: if cut = 0, and "line 164" is not present, then Global variables use 1584 bytes (77%) of dynamic memory, leaving 464 bytes for local variables. Maximum is 2048 bytes.**
int reset = 0;
byte one[8] = { 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x00 };
byte two[8] = { 0x00, 0x00, 0x18, 0x04, 0x08, 0x10, 0x1C, 0x00 };
byte three[8] = { 0x00, 0x00, 0x18, 0x04, 0x08, 0x04, 0x18, 0x00 };
byte baht[8] = { 0x04, 0x1E, 0x15, 0x1E, 0x15, 0x15, 0x1E, 0x04 };
byte aleft[8] = { 0x00, 0x00, 0x00, 0x01, 0x12, 0x14, 0x18, 0x1E };
File myFile0;
File myFile1;
File myFile2;
void setup() {
Serial.begin(115200);
SD.begin(4);
lcd.begin(20, 4);
lcd.init();
lcd.backlight();
lcd.createChar(1, one);
lcd.createChar(2, two);
lcd.createChar(3, three);
lcd.createChar(4, baht);
lcd.createChar(5, aleft);
pinMode(8, INPUT_PULLUP);
lcd.clear();
lcd.setCursor(6, 1);
lcd.print("3 Phase");
lcd.setCursor(4, 2);
lcd.print("Energy Meter");
lcd.setCursor(16, 3);
lcd.print("v30a");
delay(3000);
lcd.clear();
lcd.setCursor(4, 1);
lcd.print("PLEASE WAIT");
delay(1000);
lcd.setCursor(2, 2);
lcd.print("Retrieving Data");
lcd.setCursor(0, 3);
for (int i = 1; i <= 20; i++) {
delay(200);
lcd.print("x");
}
File myFile0;
myFile0 = SD.open("L0.txt", FILE_READ);
if (myFile0) {
lt = myFile0.parseFloat();
}
myFile0.close();
File myFile1;
myFile1 = SD.open("L1.txt", FILE_READ);
if (myFile1) {
mt = myFile1.parseFloat();
}
myFile1.close();
File myFile2;
myFile2 = SD.open("L2.txt", FILE_READ);
if (myFile2) {
ht = myFile2.parseFloat();
}
myFile2.close();
kilos[0] = lt;
kilos[1] = mt;
kilos[2] = ht;
lt = 0;
mt = 0;
ht = 0;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("DATA retrieved");
lcd.setCursor(0, 1);
lcd.print(kilos[0], 3);
lcd.print(" kW/h =L"
"\1");
lcd.setCursor(0, 2);
lcd.print(kilos[1], 3);
lcd.print(" kW/h =L"
"\2");
lcd.setCursor(0, 3);
lcd.print(kilos[2], 3);
lcd.print(" kW/h =L"
"\3");
delay(1000);
}
void readPhase() //Method to read information from CTs
{
for (int i = 0; i <= 2; i++) {
float current = 0;
float maxCurrent = 0;
float minCurrent = 1000;
for (int j = 0; j <= 200; j++) {
delay(4);
current = analogRead(currentPins[i]);
if (current >= maxCurrent)
maxCurrent = current;
else if (current <= minCurrent)
minCurrent = current;
}
if (maxCurrent <= 517) {
maxCurrent = 516;
}
RMSCurrent[i] = ((maxCurrent - 516) * 0.707107) / calib[i];
RMSPower[i] = 220 * RMSCurrent[i];
endMillis[i] = millis();
unsigned long time = (endMillis[i] - startMillis[i]);
kilos[i] = kilos[i] + ((double)RMSPower[i] * ((double)time / 60 / 60 / 1000000));
startMillis[i] = millis();
}
}
void loop() {
readPhase();
DResetscreen();
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
DKilowattHours();
**if (cut == 1) {**
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
}
delay(2300);
DRMSPower();
**if (cut == 1) {**
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
}
delay(2300);
DTotals();
**if (cut == 1) {**
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
reset = 1;
}
}
delay(2300);
Dsavedata();
//De();
Resetnow();
**cut = cut + 1; // Problem: this line creates Global variables to use 1660 bytes or (81%) of dynamic memory, leaving 388 bytes for local variables. Maximum is 2048 bytes.**
}
void DResetscreen() {
** if (cut == 1) {**
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("RESET ? [v30a]");
delay(400);
lcd.setCursor(1, 1);
lcd.print("press 'RED' button");
lcd.setCursor(1, 2);
lcd.print("and hold for 3 sec");
delay(400);
for (int i = 0; i <= 3; i++)
lcd.setCursor(3, 3);
lcd.print("\5"
"--- NOW");
delay(500);
lcd.setCursor(3, 3);
lcd.print(" ");
delay(500);
}
}
void DKilowattHours() {
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Energy [kW/h]");
lcd.setCursor(0, 1);
lcd.print("L"
"\1"
" ");
lcd.print(kilos[0], 3);
lcd.print(" kW/h");
lcd.setCursor(0, 2);
lcd.print("L"
"\2"
" ");
lcd.print(kilos[1], 3);
lcd.print(" kW/h");
lcd.setCursor(0, 3);
lcd.print("L"
"\3"
" ");
lcd.print(kilos[2], 3);
lcd.print(" kW/h");
}
void DRMSPower() {
lcd.clear();
lcd.setCursor(7, 0);
lcd.print("Power [W]");
lcd.setCursor(0, 1);
lcd.print("L"
"\1"
" ");
lcd.print(RMSPower[0], 3);
lcd.print(" W");
lcd.setCursor(0, 2);
lcd.print("L"
"\2"
" ");
lcd.print(RMSPower[1], 3);
lcd.print(" W");
lcd.setCursor(0, 3);
lcd.print("L"
"\3"
" ");
lcd.print(RMSPower[2], 3);
lcd.print(" W");
}
void DTotals() {
lcd.clear();
kilot = kilos[0] + kilos[1] + kilos[2];
for (int i = 0; i <= 2; i++) {
if (kilos[i] < 150) {
lt = kilos[i];
low = 1;
medium = 0;
high = 0;
}
if (kilos[i] - 150 > 0) {
lt = 150;
mt = kilos[i] - 150;
low = 1;
medium = 1;
high = 0;
}
if (kilos[i] - 400 > 0) {
lt = 150;
mt = 250;
ht = kilos[i] - 400;
low = 1;
medium = 1;
high = 1;
}
pay[i] = (lt * 3.2484 * low) + (mt * 4.2218 * medium) + (ht * 4.4217 * high);
lt = 0;
mt = 0;
ht = 0;
low = 0;
medium = 0;
high = 0;
}
payt = pay[0] + pay[1] + pay[2];
lcd.setCursor(1, 0);
lcd.print("Total consumption");
lcd.setCursor(3, 1);
lcd.print("\xF6"
" (L"
"\1"
", L"
"\2"
", L"
"\3)");
lcd.setCursor(6, 2);
lcd.print(kilot, 3);
lcd.print(" kW/h");
lcd.setCursor(3, 3);
lcd.print("+/- ");
lcd.print(payt, 2);
lcd.print(" "
"\4");
}
void Dsavedata() {
count = count + 1;
if (count == 100) {
count = 1;
File myfile0 = SD.open("L0.txt", FILE_WRITE | O_TRUNC);
myFile0 = SD.open("L0.txt", FILE_WRITE);
if (myFile0) {
myFile0.print(kilos[0], 3);
}
myFile0.close();
File myfile1 = SD.open("L1.txt", FILE_WRITE | O_TRUNC);
myFile1 = SD.open("L1.txt", FILE_WRITE);
if (myFile1) {
myFile1.print(kilos[1], 3);
}
myFile1.close();
File myfile2 = SD.open("L2.txt", FILE_WRITE | O_TRUNC);
myFile2 = SD.open("L2.txt", FILE_WRITE);
if (myFile2) {
myFile2.print(kilos[2], 3);
}
myFile2.close();
lcd.clear();
lcd.setCursor(1, 1);
lcd.print("Successfully saved");
lcd.setCursor(4, 2);
lcd.print("to 'SD' card");
delay(600);
}
}
void Resetnow() {
if (reset == 1) {
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("!!! RESET !!!");
reset = 0;
for (int i = 0; i <= 2; i++) {
kilos[i] = 0;
}
lcd.setCursor(1, 2);
lcd.print("Counters all Reset");
}
}
By the way, I want also to thank all the authors of the sketch which I used to create mine.








