How do i do this test without bumping into memory limits

Hey All :slight_smile:

I need to test to see if 3 push-to-make switches that are connected to analog Arduino Nano ports are all pressed at start up. Before writing code to do the test, On compile, the IDE reports:
Sketch uses 7214 bytes (23%) of program storage space. Maximum is 30720 bytes.
Global variables use 1062 bytes (51%) of dynamic memory, leaving 986 bytes for local variables. Maximum is 2048 bytes.

When I use code like this to do the test:

if ( (analogRead(pushButtonSA) == 0) && (analogRead(pushButtonUp) == 0) && (analogRead(pushButtonDown) == 0) ) {
    enterDeleteMode();
};

then the IDE reports an almost 900 bytes increase in Global variable memory use:
Sketch uses 13740 bytes (44%) of program storage space. Maximum is 30720 bytes.
Global variables use 1954 bytes (95%) of dynamic memory, leaving 94 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

If I try:

int d = analogRead(pushButtonSA) + analogRead(pushButtonUp) + analogRead(pushButtonDown);
if ( d > 0 ) {
  enterDeleteMode();
};

then the IDE reports the same as above:

Low memory available, stability problems may occur.
Sketch uses 13740 bytes (44%) of program storage space. Maximum is 30720 bytes.
Global variables use 1954 bytes (95%) of dynamic memory, leaving 94 bytes for local variables. Maximum is 2048 bytes.

Is there a way to code the test that will consume far less lobal memory than that? I’m constrained to use the analog ports because I’ve got LEDs using up 12 digital input pins.

Any thoughts?

You can use the analog ṕins as digital inputs as well.

That’s good to know, DrDietrtrich. Thanks :)

While this is true, using digitalRead as opposed to using analogRead, actually uses more program memory.

void setup() {
  // put your setup code here, to run once:

  // blank sketch = 444 bytes PROGRAM MEM

  pinMode(1, INPUT_PULLUP);  // just pinMode called = 568 bytes PROGRAM MEM
}

void loop() {
  // if(!digitalRead(1)) // 736 bytes
  //   return;

  if (!analogRead(1))  // 602 bytes
    return;
}

Even more memory used if reading the ports directly.

void adc_init(void) {
  // Reference = AVcc, channel = 0 initially
  ADMUX = (1 << REFS0);

  // Enable ADC, prescaler = 128
  ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}

uint16_t adc_read(uint8_t channel) {
  // Select ADC channel (0–7)
  ADMUX = (ADMUX & 0xF0) | (channel & 0x0F);

  // Start conversion
  ADCSRA |= (1 << ADSC);

  // Wait for conversion to finish
  while (ADCSRA & (1 << ADSC))
    ;

  // Read result (must read ADCL first!)
  uint16_t low = ADCL;
  uint16_t high = ADCH;

  return (high << 8) | low;
}

void setup() {
  // put your setup code here, to run once:

  // blank sketch = 444 bytes PROGRAM MEM

  pinMode(1, INPUT_PULLUP);  // just pinMode called = 568 bytes PROGRAM MEM
  adc_init(); // 580 bytes 
}

void loop() {
  // if(!digitalRead(1)) // 736 bytes
  //   return;

  // if (!analogRead(1))  // 602 bytes
  //   return;

  if (!adc_read(1)) // 618 bytes 
    return;
}

Can you please post the full sketch? Please use the < CODE > tags, in the editor above.

The extra memory usage is not from the test, it is from the enterDeleteMode() function.

1 Like

If I use:

  if ( true ) {
    enterDeleteMode();
  };

Then I get:

Sketch uses 7214 bytes (23%) of program storage space. Maximum is 30720 bytes.
Global variables use 1062 bytes (51%) of dynamic memory, leaving 986 bytes for local variables. Maximum is 2048 bytes.

So it’s not the function, it really is the test involving the buttons. Thanks anyway david_2018 :)

There’s a lot of it and I’m not sure how it’ll help??? I will if you really think it’ll help, HazardsMind ….

What is the memory usage if you remove the IF statement and just have “enterDeleteMode()” ?

It’s always recommended to share the full code, this way we can all be on the same page. The more data we have to work with, the better we can help.

Commenting out the if statement gives:

Sketch uses 7214 bytes (23%) of program storage space. Maximum is 30720 bytes.
Global variables use 1062 bytes (51%) of dynamic memory, leaving 986 bytes for local variables. Maximum is 2048 bytes.

That’s the same result as using

  if ( true ) {
    enterDeleteMode();
  };

Here you go - it’s not yet fully debugged but mostly there.


#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
#include <EEPROM.h>;

const int maxNumReps = 10;
const int minNumReps = 1;
const int maxNumSets = 10;
const int minNumSets = 1;
const int maxRepDurn = 90;
const int minRepDurn = 5;
const int maxRestDurn = 30;
const int minRestDurn = 5;

bool atLeastOneNewSetAdded = false;
int goLed = 13;
int restLed = 12;
// Rep LEDs are never accessed by their variable name individually.
int repLed1 = 2;
int repLed2 = 3;
int repLed3 = 4;
int repLed4 = 5;
int repLed5 = 6;
int repLed6 = 7;
int repLed7 = 8;
int repLed8 = 9;
int repLed9 = 10;
int repLed10 = 11;
// Buttons are using pull up resistors so will be 0 when pressed (1023 when not pressed)
const int pushButtonDown = A0;
const int pushButtonUp = A1;
const int pushButtonSA = A2;

int setNum = 1;
int repNum = 1;

int repDuration;
float remainingRepTime;
float newRemainingRepTime;
int loopSize;
float flashRateChangeFactor = 1.1;
float flashRateDelay;

int numSets;
int numReps;
//const int blinkDelay = 1000u;
struct mySetSettingsStruct {
  int setNum;
  int numReps;
  int repDurn;
  int restDurn;
};
mySetSettingsStruct mySetSettingsNew, mySetSettingsOld, mySetSettingsDefault, mySetSettings;
// Variable to store settings object from / for EEPROM.

int scenarioNumSets = 3;

void resetEEPROM() {
  // The only addresses to hold values are the first two bytes and they hold the number of sets
  // presently stored in the EEPROM
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("    Resetting...");
  lcd.setCursor(0,1);
  lcd.print("Are you sure you");
  lcd.setCursor(0,2);
  lcd.print("want to wipe all..");
  lcd.setCursor(0,3);
  lcd.print("       (press Setup)");
//  Serial.println("165 press setup to continue message");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Sets? If not, switch");
  lcd.setCursor(0,1);
  lcd.print("off now, otherwise");
  lcd.setCursor(0,2);
  lcd.print("push the Setup/Apply");
  lcd.setCursor(0,3);
  lcd.print("button to wipe them");
//  Serial.println("178 press setup to wipe eeprom");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print("Wiping...");
  for (int i = 0 ; i < EEPROM.length() ; i++) { // start at 2 to skip over location where numSets is stored
    EEPROM.write(i, 255);
  }  
  lcd.clear();
  lcd.setCursor(0,0);
//  Serial.println("190 all sets wiped, switch off and on again");
  lcd.print("All Sets wiped so");
  lcd.setCursor(0,1);
  lcd.print("you can now start");
  lcd.setCursor(0,2);
  lcd.print("over when you switch");
  lcd.setCursor(0,3);
  lcd.print("off and on again.");
  while (1);
}
void enterDeleteMode() {
  bool finishedDeleting = false;
  bool buttonPressed = false;
  int mySetNum = 0;
  int numSets;
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("   DELETION MODE");
  lcd.setCursor(0,1);
  lcd.print("You can now move");
  lcd.setCursor(0,2);
  lcd.print("through the Sets..");
  lcd.setCursor(0,3);
  lcd.print("       (press Setup)");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("deleting those you");
  lcd.setCursor(0,1);
  lcd.print("no longer want.");
  lcd.setCursor(0,2);
  lcd.print("Later Sets will be..");
  lcd.setCursor(0,3);
  lcd.print("       (press Setup)");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("renumbered so no");
  lcd.setCursor(0,1);
  lcd.print("gaps are left.");
  lcd.setCursor(0,2);
  lcd.print("When done just..");
  lcd.setCursor(0,3);
  lcd.print("       (press Setup)");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("switch it off.");
  lcd.setCursor(0,1);
  lcd.print("When you're ready to");
  lcd.setCursor(0,2);
  lcd.print("start exercising..");
  lcd.setCursor(0,3);
  lcd.print("       (press Setup)");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("just switch it on");
  lcd.setCursor(0,1);
  lcd.print("again.");
  lcd.setCursor(0,3);
  lcd.print("       (press Setup)");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Down = next Set");
  lcd.setCursor(0,1);
  lcd.print("Up = previous Set");
  lcd.setCursor(0,2);
  lcd.print("Apply = delete Set");
  lcd.setCursor(0,3);
  lcd.print("       (press Setup)");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
  delay(10);
  while (analogRead(pushButtonSA) == 0); // wait for button to be released
  //numSets = 3 ;// EXPLORE read numSets from EEPROM : for testing, start with it set to 0, then test with 1, then 2
  EEPROM.get(0, numSets);
  if (numSets == 0) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("No Sets exist so");
    lcd.setCursor(0,1);
    lcd.print("can't delete");
    lcd.setCursor(0,2);
    lcd.print("anything.");
    lcd.setCursor(0,3);
    lcd.print("    (now switch off)");
    while (1);
  } else {
    mySetNum = 1; // if we get here, then there's at least 1 Set in EEPROM, so start with that
    readSetFromEEPROM(mySetNum);
    displaySetForDeletionMode(mySetNum);
  }
  while (!finishedDeleting) {
    if (analogRead(pushButtonUp) == 0) { 
      delay(10);
      while (analogRead(pushButtonUp) == 0); // wait for button to be released
      mySetNum-- ;
      if (mySetNum == 0) { mySetNum++ ;} // what if there are none left??? 
      readSetFromEEPROM(mySetNum);
      displaySetForDeletionMode(mySetNum);
    }
    if (analogRead(pushButtonDown) == 0) { 
      delay(10);
      while (analogRead(pushButtonDown) == 0); // wait for button to be released
      mySetNum++ ;
      if (mySetNum > numSets) { mySetNum-- ;}
      readSetFromEEPROM(mySetNum);
      displaySetForDeletionMode(mySetNum);
    }
    if (analogRead(pushButtonSA) == 0) { // delete the one showing - no need to read one from EEPROM
      delay(10);
      while (analogRead(pushButtonSA) == 0); // wait for button to be released


      if (numSets == 1){
//        Serial.println("numSets was 1 (ie the last Set) so deleting it");
        numSets--;
//        Serial.println("decremented numSets to 0 and written to loc 0 of EEPROM");
//        Serial.println("Only option now is to switch off");
        finishedDeleting = true ;
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("All Sets deleted.");
        lcd.setCursor(0,1);
        lcd.print("Now switch off and");
        lcd.setCursor(0,2);
        lcd.print("when you switch on..");
        lcd.setCursor(0,3);
        lcd.print("       (press Setup)");
        while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
        delay(10);
        while (analogRead(pushButtonSA) == 0); // wait for button to be released
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("again, Setup will");
        lcd.setCursor(0,1);
        lcd.print("start so you can");
        lcd.setCursor(0,2);
        lcd.print("re-add your Sets.");
        lcd.setCursor(0,3);
        lcd.print("    (now switch off)");
        while (1);
      }
      if (mySetNum < numSets){
//        Serial.println("not displaying last Set (could be on first if there's more than one)");
//        Serial.println("so all Sets from the one after this one to the last one need");
//        Serial.println("to be shifted higher in the list (ie lower in memory)");
        for (int i = mySetNum; i < numSets; i++){
//          Serial.print("moving set from location given by a set number of ");
//          Serial.print(i+1);
//          Serial.print(" to ");
//          Serial.println(i);
          readSetFromEEPROM(i + 1); // it gets read into mySetSettingsOld so will have that set's current setNum
          mySetSettingsOld.setNum--; // decrement it so it records its new position-to-be
          writeSetToEEPROM(mySetSettingsOld);
        }
      }
      clearSetFromEEPROM(numSets); // ie now they've all been shifted up, clear the last one in EEPROM
      numSets--;
//      Serial.print("decremented numSets to ");
//      Serial.print(numSets);
//      Serial.println(" and written it to loc 0 of EEPROM");
      EEPROM.put(0, numSets); // record the new numbere of sets
//      Serial.println("");
//      Serial.print("Set given by mySetNum of ");
//      Serial.print(mySetNum);
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Set deleted.");
      if ((numSets + 1) == mySetNum){
//        Serial.println(" has been deleted. There were none after it to renumber");
        mySetNum--; // just deleted the last set so have display the one before.
        lcd.setCursor(0,1);
        lcd.print("There were no later");
        lcd.setCursor(0,2);
        lcd.print("Sets to renumber");
      } else {
//        Serial.println(" has been deleted and replaced by the one just after it");
        lcd.setCursor(0,1);
        lcd.print("All later Sets have");
        lcd.setCursor(0,2);
        lcd.print("been renumbered");
      }
      lcd.setCursor(0,3);
      lcd.print("       (press Setup)");
      while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
      delay(10);
      while (analogRead(pushButtonSA) == 0); // wait for button to be released
//      Serial.print("Set given by ");
//      Serial.print(mySetNum);
//      Serial.println(" now on display ready for button presses / switchoff");
      readSetFromEEPROM(mySetNum);
      displaySetForDeletionMode(mySetNum);
    }
  }
  while(1);
}
void displaySetForDeletionMode(int mySetNum) {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Set         Value");
  lcd.setCursor(4,0);
  lcd.print(mySetNum);
  lcd.setCursor(0,1);
  lcd.print("Num Reps");
  lcd.setCursor(0,2);
  lcd.print("A Rep lasts");
  lcd.setCursor(0,3);
  lcd.print("A Rest lasts");
  showOldSettings();
}
void switchAllRepLeds(int status) {
  digitalWrite(repLed1, status);
  digitalWrite(repLed2, status);
  digitalWrite(repLed3, status);
  digitalWrite(repLed4, status);
  digitalWrite(repLed5, status);
  digitalWrite(repLed6, status);
  digitalWrite(repLed7, status);
  digitalWrite(repLed8, status);
  digitalWrite(repLed9, status);
  digitalWrite(repLed10, status);
}
void restAWhile(int duration) {
  digitalWrite(goLed, LOW);
  digitalWrite(restLed, HIGH);
  delay(1000 * duration);
  digitalWrite(restLed, LOW);
  digitalWrite(goLed, HIGH);
}
void prepRep() {
  digitalWrite(goLed, HIGH);
  digitalWrite(repNum+1, HIGH);
}
void displayInitialSetupInstructions() {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("   INITIAL SETUP");
    lcd.setCursor(0,1);
    lcd.print("Choose values for");
    lcd.setCursor(0,2);
    lcd.print("each of your Sets");
    lcd.setCursor(0,3);
    lcd.print("       (press Setup)");
  while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
    delay(10);
    while (analogRead(pushButtonSA) == 0); // wait for button to be released
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Keep adding sets up");
    lcd.setCursor(0,1);
    lcd.print("to a maximum of 10.");
    lcd.setCursor(0,2);
    lcd.print("For each Set...");
    lcd.setCursor(0,3);
    lcd.print("       (press Setup)");
    while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
    delay(10);
    while (analogRead(pushButtonSA) == 0); // wait for button to be released
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("choose values for");
    lcd.setCursor(0,1);
    lcd.print("- Number of Reps");
    lcd.setCursor(0,2);
    lcd.print("- Rep Duration...");
    lcd.setCursor(0,3);
    lcd.print("       (press Setup)");
    while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
    delay(10);
    while (analogRead(pushButtonSA) == 0); // wait for button to be released
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("- Rest Duration");
    lcd.setCursor(0,1);
    lcd.print("(rest between reps)");
    lcd.setCursor(0,2);
    lcd.print("");
    lcd.setCursor(0,3);
    lcd.print("hit Setup & continue");
    while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
    delay(10);
    while (analogRead(pushButtonSA) == 0); // wait for button to be released
}
void readSetFromEEPROM(int mySetNum) {
// this reads a set from EEPROM and places it into mySetSettingsOld
  int eeAddress = 2; // skip over numSets location
  int temp;
/*
EEPROM.put(0, 3);
mySetSettingsOld.setNum = 1;
mySetSettingsOld.numReps = 17;
mySetSettingsOld.repDurn = 16;
mySetSettingsOld.restDurn = 15;
EEPROM.put(eeAddress+2, mySetSettingsOld);
mySetSettingsOld.setNum = 2;
mySetSettingsOld.numReps = 23;
mySetSettingsOld.repDurn = 22;
mySetSettingsOld.restDurn = 21;
EEPROM.put(10, mySetSettingsOld);
mySetSettingsOld.setNum = 3;
mySetSettingsOld.numReps = 3;
mySetSettingsOld.repDurn = 32;
mySetSettingsOld.restDurn = 31;
EEPROM.put(18, mySetSettingsOld);
*/
  eeAddress = eeAddress + (mySetNum - 1) * sizeof(mySetSettingsDefault); //Move address to the location of the Set
  EEPROM.get(eeAddress, mySetSettingsOld);
  /*
  Serial.print("533 mySetNum is: ");
  Serial.println(mySetNum);
  Serial.print("eeaddress is: ");
  Serial.println(eeAddress);
  Serial.print("Old numreps is: ");
  Serial.println(mySetSettingsOld.numReps);
  Serial.print("Old repDurn is: ");
  Serial.println(mySetSettingsOld.repDurn);
  Serial.print("Old restDurn is: ");
  Serial.println(mySetSettingsOld.restDurn);
*/
  mySetSettings.setNum = mySetSettingsNew.setNum = mySetSettingsOld.setNum = mySetNum;
}
void writeSetToEEPROM(mySetSettingsStruct setToWrite) {
// this writes a set to EEPROM using the setNumber in the passed SetToWrite
  int eeAddress = 2; // skip over numSets location
  eeAddress = eeAddress + (setToWrite.setNum - 1) * sizeof(setToWrite); // Move address to the location where the Set is to be read from
  EEPROM.put(eeAddress, setToWrite);
//  Serial.print("eeAddress is ");
//  Serial.println(eeAddress);
//  Serial.print("setnumber being written is ");
//  Serial.println(setToWrite.setNum);
}
void clearSetFromEEPROM(int mySetNum) {
  int eeAddress = 2; // skip over numSets location
  eeAddress = eeAddress + (mySetNum - 1) * sizeof(mySetSettingsDefault); // Move address to the location where the Set is to be cleared
  for (int i = eeAddress; i < sizeof(mySetSettingsDefault); i++) {
    EEPROM.write(i, 0);
  }
}
void exerciseSetup() {
  static bool setupFinished = false;
  static bool setupNumRepsFinished = false;
  static bool setupRepDurnFinished = false;
  static bool setupRestDurnFinished = false;

  static bool addSetAbandoned;
  static int myAction;

  int myButton; // used to let manageBlink know what button was pushed, if one actually was
  int myCol;
  int myRow;
  bool newSetBeingCreated;
  setNum = 0;
  //numSets = scenarioNumSets; // read numsets from EEPROM
  // Set to positive integer for scenario where EEPROM contains sets
  // or set to 0 for scenario where EEPROM numSets is 0
  // NB Can't be -1 (ie cell 0 and 1 = 255) becasue that's dealt with
  // during startup
  lcd.backlight();
  if (numSets > 0) {
    //do nothing
  } else {
    // offer  choice of Abandon Setup or Continue
    // do nothing is equivalent to Continue
    displayInitialSetupInstructions();
  }
  //delay(3000);
  while (!setupFinished) {
    setNum++ ;
    if (numSets >= setNum) {
      // ok to read set from EEPROM as there's at least one more stored there
//      Serial.println("reading set from EEPROM");
      readSetFromEEPROM(setNum);
//      Serial.println("set now read from EEPROM");
      newSetBeingCreated = false;
    } else {
      if (numSets < maxNumSets) {
//        Serial.println("creating new settings object with default vals");
        newSetBeingCreated = true;
        mySetSettingsNew.setNum = setNum;
        mySetSettingsNew.numReps = mySetSettingsDefault.numReps;
        mySetSettingsNew.repDurn = mySetSettingsDefault.repDurn;
        mySetSettingsNew.restDurn = mySetSettingsDefault.restDurn;
        // also need to set mySetSettingsOld vals back to 0 - why ????
        mySetSettingsOld.setNum = 0;
        mySetSettingsOld.numReps = 0;
        mySetSettingsOld.repDurn = 0;
        mySetSettingsOld.restDurn = 0;
      } else {
        newSetBeingCreated = false;
        // tried to create new set but max reached
//        Serial.println("new settings object can't be created as max num sets reached");
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Maximum number of");
        lcd.setCursor(0,1);
        lcd.print("Sets reached.");
        lcd.setCursor(0,3);
        lcd.print("       (press Setup)");
        while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
        delay(10);
        while (analogRead(pushButtonSA) == 0); // wait for button to be released
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Switch off and when");
        lcd.setCursor(0,1);
        lcd.print("you're ready to");
        lcd.setCursor(0,2);
        lcd.print("start exercising...");
        lcd.setCursor(0,3);
        lcd.print("       (press Setup)");
        while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
        delay(10);
        while (analogRead(pushButtonSA) == 0); // wait for button to be released
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("just switch it on");
        lcd.setCursor(0,1);
        lcd.print("again to use your");
        lcd.setCursor(0,2);
        lcd.print("new setup");
        while(1);
      }
    }
    lcd.clear();
    lcd.setCursor(0,0);
    if (newSetBeingCreated) {
      lcd.print("Add Set      Old New");
      lcd.setCursor(8,0);
    } else {
      lcd.print("Edit Set     Old New");
      lcd.setCursor(9,0);
      // As it's not a new set being created, start with values for new the same as old
        mySetSettingsNew.setNum = mySetSettingsOld.setNum;
        mySetSettingsNew.numReps = mySetSettingsOld.numReps;
        mySetSettingsNew.repDurn = mySetSettingsOld.repDurn;
        mySetSettingsNew.restDurn = mySetSettingsOld.restDurn;
    }
    lcd.print(setNum);
    lcd.setCursor(0,1);
    lcd.print("Num Reps");
    lcd.setCursor(0,2);
    lcd.print("A Rep lasts");
    lcd.setCursor(0,3);
    lcd.print("A Rest lasts");
    showOldSettings();
    delay(500);
    while (!setupNumRepsFinished) {
      myAction = 0;
      myCol = 18;
      if (analogRead(pushButtonUp) == 0) { // it's pressed
        delay(1);
        myButton = pushButtonUp;
        myAction = 1;
        while (analogRead(pushButtonUp) == 0); // wait for button to be released
        mySetSettingsNew.numReps++;
        if (mySetSettingsNew.numReps > maxNumReps) {mySetSettingsNew.numReps--;}
      }
      if (analogRead(pushButtonDown) == 0) { // it's pressed
        delay(1);
        myButton = pushButtonDown;
        myAction = 1;
        while (analogRead(pushButtonDown) == 0); // wait for button to be released
        mySetSettingsNew.numReps--;
        if (mySetSettingsNew.numReps < minNumReps) {mySetSettingsNew.numReps++;}
      }
      manageBlink(myCol, 1, mySetSettingsNew.numReps, myAction, myButton);
      if (analogRead(pushButtonSA) == 0) {
        delay(10);
        while (analogRead(pushButtonSA) == 0);
        setupNumRepsFinished = true;
        if (mySetSettingsNew.numReps > 9) { myCol--;};
        lcd.setCursor(myCol, 1);
        lcd.print(mySetSettingsNew.numReps);
      }
    }
    if (mySetSettingsNew.numReps > 0) {
    // it'll be 0 setup / apply button was pushed while numReps was 0 and 
    // thus indicating new set not to be added.
    while (!setupRepDurnFinished) {
        myAction = 0;
        myCol = 18;
        if (analogRead(pushButtonUp) == 0) { // it's pressed
          delay(1);
          myButton = pushButtonUp;
          myAction = 1;
          while (analogRead(pushButtonUp) == 0); // wait for button to be released
          mySetSettingsNew.repDurn = mySetSettingsNew.repDurn + 5;
          if (mySetSettingsNew.repDurn > maxRepDurn) {mySetSettingsNew.repDurn = maxRepDurn;}
        }
        if (analogRead(pushButtonDown) == 0) { // it's pressed
          delay(1);
          myButton = pushButtonDown;
          myAction = 1;
          while (analogRead(pushButtonDown) == 0); // wait for button to be released
          mySetSettingsNew.repDurn = mySetSettingsNew.repDurn - 5;
          if (mySetSettingsNew.repDurn < minRepDurn) {mySetSettingsNew.repDurn = minRepDurn;}
        }
        manageBlink(myCol, 2, mySetSettingsNew.repDurn, myAction, myButton);
        if (analogRead(pushButtonSA) == 0) {
          delay(10);
          while (analogRead(pushButtonSA) == 0);
          setupRepDurnFinished = true;
          lcd.setCursor(myCol+1, 2);
          lcd.print("s");
          if (mySetSettingsNew.repDurn > 9) {myCol--;};
          lcd.setCursor(myCol, 2);
          lcd.print(mySetSettingsNew.repDurn);
        }
      }
      while (!setupRestDurnFinished) {
        myAction = 0;
        myCol = 18;
        if (analogRead(pushButtonUp) == 0) { // it's pressed
          delay(1);
          myButton = pushButtonUp;
          myAction = 1;
          while (analogRead(pushButtonUp) == 0); // wait for button to be released
          mySetSettingsNew.restDurn = mySetSettingsNew.restDurn + 5;
          if (mySetSettingsNew.restDurn > maxRestDurn) {mySetSettingsNew.restDurn = maxRestDurn;}
        }
        if (analogRead(pushButtonDown) == 0) { // it's pressed
          delay(1);
          myButton = pushButtonDown;
          myAction = 1;
          while (analogRead(pushButtonDown) == 0); // wait for button to be released
          mySetSettingsNew.restDurn = mySetSettingsNew.restDurn - 5;
          if (mySetSettingsNew.restDurn < minRestDurn) {mySetSettingsNew.restDurn = minRestDurn;}
        }
        manageBlink(myCol, 3, mySetSettingsNew.restDurn, myAction, myButton);
        if (analogRead(pushButtonSA) == 0) {
          delay(10);
          while (analogRead(pushButtonSA) == 0);
          setupRestDurnFinished = true;
          lcd.setCursor(myCol+1, 3);
          lcd.print("s");
          if (mySetSettingsNew.restDurn > 9) { myCol--;};
          lcd.setCursor(myCol, 3);
          lcd.print(mySetSettingsNew.restDurn);
        }
      }
    }
    // check that changes haven't been made
    if (
        (mySetSettingsOld.numReps == mySetSettingsNew.numReps && 
          mySetSettingsOld.repDurn == mySetSettingsNew.repDurn &&
          mySetSettingsOld.restDurn == mySetSettingsNew.restDurn)
          ||
        (mySetSettingsDefault.numReps == mySetSettingsNew.numReps && 
          mySetSettingsDefault.repDurn == mySetSettingsNew.repDurn &&
          mySetSettingsDefault.restDurn == mySetSettingsNew.restDurn)
       ) {
      // no changes made, so...
      if (newSetBeingCreated) {
      // if a new set was being created and no changes were made then the only possibilities are:
      // 1 - nothing in EEPROM and the first new set was about to be created but was abandoned
      // 2 - one or more sets in EEPROM, was creating a new set to add to the end but abandoned
      // In both cases there's nothing else to do except power off
        lcd.clear();
        lcd.backlight();
        if (atLeastOneNewSetAdded) {
          lcd.setCursor(0,0);
          lcd.print("Num Reps left at 0");
          lcd.setCursor(0,1);
          lcd.print("this time so this");
          lcd.setCursor(0,2);
          lcd.print("set wasn't added...");
          lcd.setCursor(0,3);
          lcd.print("       (press Setup)");
          while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
          delay(10);
          while (analogRead(pushButtonSA) == 0); // wait for button to be released
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("You can switch off");
          lcd.setCursor(0,1);
          lcd.print("now and when you are");
          lcd.setCursor(0,2);
          lcd.print("ready to start...");
          lcd.setCursor(0,3);
          lcd.print("       (press Setup)");
          while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
          delay(10);
          while (analogRead(pushButtonSA) == 0); // wait for button to be released
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("exercising, just");
          lcd.setCursor(0,1);
          lcd.print("switch it on again");
          lcd.setCursor(0,2);
          lcd.print("to use your new");
          lcd.setCursor(0,3);
          lcd.print("settings.");
        } else { // no new sets added
        // still to cater for wording to cover exisitng set being changed but no new set added
          lcd.setCursor(0,0);
          lcd.print("   Set Not Added");
          lcd.setCursor(0,1);
          lcd.print("because Num Reps was");
          lcd.setCursor(0,2);
          lcd.print("left at 0..");
          lcd.setCursor(0,3);
          lcd.print("       (press Setup)");
          while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
          delay(10);
          while (analogRead(pushButtonSA) == 0); // wait for button to be released
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("If you do want to");
          lcd.setCursor(0,1);
          lcd.print("add one, switch off");
          lcd.setCursor(0,2);
          lcd.print("and on and then go");
          lcd.setCursor(0,3);
          lcd.print("       (press Setup)");
          while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
          delay(10);
          while (analogRead(pushButtonSA) == 0); // wait for button to be released
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("into setup again.");
          lcd.setCursor(0,1);
          lcd.print("Make sure Num Reps");
          lcd.setCursor(0,2);
          lcd.print("is at least 1.");
          lcd.setCursor(0,3);
          lcd.print("    (now switch off)");
        }
        while(1);
      } else {
        // new set not being created - so must be a set just read from EEPROM
        // and changes were not made. There may be more sets in EEPROM that may need to be changed
      }
    } else {
      // changes have been made
      lcd.clear();
      if (newSetBeingCreated) {
        atLeastOneNewSetAdded = true;
        numSets++; // will need to write to EEPROM together with mySetSettingsNew
        // save new set to EEPROM
        lcd.setCursor(4,1);
        writeSetToEEPROM(mySetSettingsNew);
        EEPROM.put(0, setNum);
        lcd.print("New Set saved");
      } else {
        // save changes to EEPROM
        writeSetToEEPROM(mySetSettingsNew);
        lcd.setCursor(2,1);
        lcd.print("Changed Set saved");
      }
      lcd.setCursor(0,3);
      lcd.print("hit Setup & continue");
      while (analogRead(pushButtonSA) != 0); // wait for button to be pressed
      delay(10);
      while (analogRead(pushButtonSA) == 0); // wait for button to be released
    }
    // reset the while loop vars that control changing values
    setupNumRepsFinished = false;
    setupRepDurnFinished = false;
    setupRestDurnFinished = false;

  } // setupFinished while loop
  lcd.noBacklight();
}
void showOldSettings() {
  // Only show when the old settings have actual vals and not zeros
  if (mySetSettingsOld.setNum == 0){ return; }
  int myCol = 4;
  myCol = 14;
  if (mySetSettingsOld.numReps > 9) { myCol--;}
  lcd.setCursor(myCol,1);
  lcd.print(mySetSettingsOld.numReps);
  myCol = 14;
  if (mySetSettingsOld.repDurn > 9) { myCol--;}
  lcd.setCursor(myCol,2);
  lcd.print(mySetSettingsOld.repDurn);
  lcd.setCursor(15,2);
  lcd.print("s");
  myCol = 14;
  if (mySetSettingsOld.restDurn > 9) { myCol--;}
  lcd.setCursor(myCol,3);
  lcd.print(mySetSettingsOld.restDurn);
  lcd.setCursor(15,3);
  lcd.print("s");
}
void manageBlink(int myCol, int myRow, int myVal, int myAction, int myButton) {
// general approach: myVal assumed to be a single digit. If a double digit then col needs to be decremented
// also, don't allow up or down button pushes while a value is blanked out
  const int blinkAtCount = 400;//15000
  static int countForNextBlink = 0;
  static bool blankOutMyVal = true;
  delay(2);
//Serial.print("after remainder div, countForNextBlink: ");
//Serial.println(countForNextBlink);
  if (countForNextBlink == 0) {
    blankOutMyVal = !blankOutMyVal;
    // in case there was a double digit previously when blankOutMyVal was false
    // and so there was no opportunity to blank it out
    lcd.setCursor(myCol-1, myRow);
    lcd.print(" ");
    if (myVal > 9) {
      myCol--;
      lcd.setCursor(myCol, myRow);
      if (blankOutMyVal) {
        lcd.print("   "); // double digit and allow for seconds s
      } else {
        lcd.print(myVal); // double digit
        if (myRow == 2 or myRow == 3) {
          lcd.setCursor(myCol+2,myRow);
          lcd.print("s");
        }
      }
    } else { // single digit
      lcd.setCursor(myCol, myRow);
      if (blankOutMyVal) {
        lcd.print("  "); // single digit and allow for seconds s
      } else {
        lcd.print(myVal); // single digit
        if (myRow == 2 or myRow == 3) {
          lcd.setCursor(myCol+1,myRow);
          lcd.print("s");
        }
      }
    }
  }
  countForNextBlink++;
  countForNextBlink = countForNextBlink % blinkAtCount;
  if (myAction == 1) {
    // this is for when a button has been pushed 
    // It is to allow the new value to be updated immediately and the count to be started over
    countForNextBlink = 0; // restart count
    blankOutMyVal = true; // at start of next time round the loop it'll be inverted
    while(analogRead(myButton) == 0);
  }
}
void displayExerciseProgress(int mySetNum, int myRepNum, int myNumSets, int myNumReps) {
  lcd.setCursor(3,0);
  lcd.print("NOW EXERCISING");
  lcd.setCursor(4,1);
  lcd.print("Set: ");
  lcd.setCursor(9,1);
  lcd.print(mySetNum);
  lcd.setCursor(12,1);
  lcd.print("of");
  lcd.setCursor(15,1);
  lcd.print(myNumSets);
  lcd.setCursor(4,2);
  lcd.print("Rep: ");
  lcd.setCursor(9,2);
  lcd.print(myRepNum);
  lcd.setCursor(12,2);
  lcd.print("of");
  lcd.setCursor(15,2);
  lcd.print(myNumReps);
}
void setup() {
  bool stillAChanceToHitSA = true;
  int countDown = 2500;
  bool countdownCountOn = true;
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  // put your setup code here, to run once:
	pinMode(goLed, OUTPUT);
	pinMode(restLed, OUTPUT);
  pinMode(repLed1, OUTPUT);
  pinMode(repLed2, OUTPUT);
  pinMode(repLed3, OUTPUT);
  pinMode(repLed4, OUTPUT);
  pinMode(repLed5, OUTPUT);
  pinMode(repLed6, OUTPUT);
  pinMode(repLed7, OUTPUT);
  pinMode(repLed8, OUTPUT);
  pinMode(repLed9, OUTPUT);
  pinMode(repLed10, OUTPUT);
  pinMode(pushButtonDown, INPUT);
  pinMode(pushButtonUp, INPUT);
  pinMode(pushButtonSA, INPUT);
  mySetSettingsDefault.setNum = 0;
  mySetSettingsDefault.numReps = 0;
  mySetSettingsDefault.repDurn = 5;
  mySetSettingsDefault.restDurn = 5;
  switchAllRepLeds(LOW);
  lcd.noBacklight();
  lcd.setCursor(1,1);
  //numSets = scenarioNumSets; // EXPLORE read numsets from EEPROM with EEPROM.get(0, numSets);
  //readSetFromEEPROM_Old(1); // EXPLORE
  //writeSetToEEPROM(mySetSettings); // EXPLORE
  //readSetFromEEPROM_Old(2); // EXPLORE
  //writeSetToEEPROM(mySetSettings); // EXPLORE
  //readSetFromEEPROM_Old(3); // EXPLORE
  //writeSetToEEPROM(mySetSettings); // EXPLORE
//EEPROM.put(0,-1); // EXPLORE
// Now test delete
/* 
bool a = analogRead(pushButtonSA) == 0;
bool b = analogRead(pushButtonUp) == 0;
bool c = analogRead(pushButtonDown) == 0;
*/
//int d = analogRead(pushButtonSA) + analogRead(pushButtonUp) + analogRead(pushButtonDown);
//  if ( (analogRead(pushButtonSA) == 0) && (analogRead(pushButtonUp) == 0) && (analogRead(pushButtonDown) == 0) ) {
//  if ( true ) {
    enterDeleteMode();
//  };

// enterDeleteMode();
//clearSetFromEEPROM(1);
//clearSetFromEEPROM(2);
//clearSetFromEEPROM(3);
//clearSetFromEEPROM(4);
//while(1);


EEPROM.get(0, numSets);
//Serial.print("106: read numSets from EEPROM, got: ");
//Serial.println(numSets);
//while(1);
  if (numSets <= 0) {
  // 0 means numSets of 0 already stored, -1 means nothing yet stored for numSets
  // Either way, need to do exerciseSetup but only store 0 for numSets if it was -1
     //  if (numSets == -1) {EEPROM.write(0, 0);}; // make numSets location hold 0 WHY here?
//    exerciseSetupTemp(); // sets numSets to 0 and .puts it imto eeprom as well as storing a set of settings in EEPROM for this test
    exerciseSetup();
  } else {
    // give them the choice to change settings
    lcd.setCursor(0,0);
    lcd.print("Start Exercise in 5");
    lcd.setCursor(9,1);
    lcd.print("or");
    lcd.setCursor(2,2);
    lcd.print("Hit Setup button");
    lcd.setCursor(1,3);
    lcd.print("to change settings");
    // give chance for setup button to be pushed
    while (stillAChanceToHitSA) {
//      delay(2);
      countDown--;
      if (countDown % 250 == 0) {
        countdownCountOn = !countdownCountOn;
      }
      if (countdownCountOn) {
        lcd.setCursor(18,0);
        lcd.print(1 + countDown / 500);
        lcd.backlight();
      } else {
        lcd.setCursor(18,0);
        lcd.print(" ");
        lcd.noBacklight();
      }
//        Serial.println(countDown % 250);
      if (countDown == 0) {
        stillAChanceToHitSA = false;
        lcd.clear();
        lcd.backlight();
        lcd.setCursor(8,0);
        lcd.print("GO!");
        delay(1000);
        lcd.noBacklight();
      }
      if (analogRead(pushButtonSA) == 0) {
        delay(10);
        while (analogRead(pushButtonSA) == 0);
        stillAChanceToHitSA = false;
        exerciseSetup();
      }
    }
  }
}

void loop() {
//Serial.print("main: numSets is: ");
//Serial.println(numSets);
  for (int exerciseSetNum = 1; exerciseSetNum <= numSets; exerciseSetNum++ ) {
    readSetFromEEPROM(exerciseSetNum);
    switchAllRepLeds(LOW);
    loopSize = log(mySetSettingsOld.repDurn) / log(flashRateChangeFactor) + 0.5;
    for (int exerciseRepNum = 1; exerciseRepNum <= mySetSettingsOld.numReps; exerciseRepNum++) {
      displayExerciseProgress(exerciseSetNum, exerciseRepNum, numSets, mySetSettingsOld.numReps);
      prepRep();
      remainingRepTime = mySetSettingsOld.repDurn;
      for (int i = 0; i < loopSize; i++) {
        newRemainingRepTime = remainingRepTime / flashRateChangeFactor;
        flashRateDelay = remainingRepTime - newRemainingRepTime;
        remainingRepTime = newRemainingRepTime;
        delay(flashRateDelay*500);
        digitalWrite(exerciseRepNum+1, LOW);
        delay(flashRateDelay*500);
        digitalWrite(exerciseRepNum+1, HIGH);
      }
      if ( !((exerciseSetNum == numSets) and (exerciseRepNum == mySetSettingsOld.numReps)) ) {
        restAWhile(mySetSettingsOld.restDurn);
      }
    }
  }
 	digitalWrite(goLed, LOW);
	digitalWrite(restLed, LOW);
  switchAllRepLeds(LOW);
  lcd.clear();
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Exercise finished!");
  lcd.setCursor(3,1);
  lcd.print("Switch off and");
  lcd.setCursor(3,2);
  lcd.print(" save battery");
  while(1); // infnite loop
}

Lots and lots of strings.

Try using the F() macro.

Do you want more memory free?

simply change all lcd.print(“something”); to lcd.print(F(“something”)); and recompile :slight_smile:

(But just those, where is “string in qoutes”. For Serial.print it works too as well as for anything.println)

Thanks for the suggestion PaulRB - will do eventually :slight_smile: Still interested in an answer to that if statement question ;)

Thanks for the detail, gilhad - I’ll do that later :slight_smile: Still interested in an answer to that if statement question ;)

My guess is that the compiler figured out that enterDeleteMode() was never called, so ignored it. When you changed the code so that it could be called, the compiler could no longer ignore the function, so suddenly the memory use increased.

1 Like

I can't explain why you didn't get the problem in post #9, however....

I’m puzzled by that, PaulRB. WIth both versions of the memory-gobbling if statement, pressing and holding all three buttons while applying power resulted in the enterDeleteMode() function being called.

When you see that "low memory...instability" message, the code may or may not work as expected, it's very difficult to predict.

2 Likes