1

Hello there C++ and arduino gurus! I need some hand here. I wrote some code for a small arduino console-like device that has five pushbuttons, 128x64 I2C OLED display and arduino nano. And it doesn't work when uploaded to arduino nano - display goes blank.

Anamnesis: The Code includes two classes: menu class and button class. When I upload the code on my device - it doesn’t display anything on oled but arduino still executes the code. Wiring is not an issue. But when I remove games_menu or pongLevel_menu or settings_menu and sound_menu from class objects and comment lines where these objects are used, the code works just fine.

Question: Maybe the thing is that arduino nano has some kind of memory, where it stores class objects, and my code uses too much of this memory. Since I am kinda new to arduino and programming - I can make mistakes. Can you please help me with this problem? Minimum reproducible code (sorry, I know that it looks like a big chunk of code but that's what I can shrink it to so that it still reproduces the problem):

#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
Adafruit_SSD1306 display(128, 64, &Wire, -1);
//------------variables-------------
    //--------menu variables--------
    unsigned long sec;
    byte selY = 12;
    boolean up;
    boolean down;
    boolean left;
    boolean right;
    boolean a;
    boolean b;
    int location = 0;
    
    //--------stopwatch variables--------
    unsigned long startTime;
    bool stTimeB = 1;
    unsigned long millisec;
    byte seconds;
    byte minutes;
    byte hours;
//--------classes-------
    //----class menu----
    class menu {
    public:
      menu(String caption, String item1, String item2, String item3, String item4, unsigned int minn, unsigned int maxx);
      void play();
      
    private:
     String cap;
     String it1;
     String it2;
     String it3;
     String it4;
     unsigned int _min;
     unsigned int _max;
  };
  menu::menu(String caption, String item1, String item2, String item3, String item4, unsigned int minn, unsigned int maxx){
    cap = caption;
    it1 = item1;
    it2 = item2;
    it3 = item3;
    it4 = item4;
    _min = minn;
    _max = maxx;
    
    }
  
  void menu::play(){
    if(up == 1 && millis() - sec > 199){
      selY -= 10;
      sec = millis();
    }
    if(down == 1 && millis() - sec > 199){
      selY += 10;
      sec = millis();
    }
    if(selY < _min){
      selY = _max;
    }
    if(selY > _max){
      selY = _min;
    }
    
    display.clearDisplay();
    display.setTextSize(1); 
    display.setTextColor(WHITE); 
    display.setCursor(50, 0);  
    display.print(cap);
    display.drawLine(0, 9, 128, 9, WHITE);
    display.setCursor(6, 13);  
    display.print(it1);
    display.setCursor(6, 23);  
    display.print(it2);
    display.setCursor(6, 33);  
    display.print(it3);
    display.setCursor(6, 43);  
    display.print(it4);
    display.drawRoundRect(1, selY, 122, 11, 4, WHITE);
    display.display();
    
  }
    //--------class button--------
    class button {
  public:
    button(byte xx, byte yy, byte rr, byte var, String caption11, String caption22, String type_, byte tSize);
    void disp();
    void changeCap(bool caption);
    bool getStatus();
    void update_();
    

  private:
   byte x;
   byte y;
   byte r;
   byte txtSize;
   bool capB = 0; // 1
   bool pres = 0;
   byte btnPin;
   String caption1;
   String caption2;
   String type;
};
button::button(byte xx, byte yy, byte rr, byte var, String caption11, String caption22, String type_, byte tSize){
  x = xx;
  y = yy;
  r = rr;
  btnPin = var;
  caption1 = caption11;
  caption2 = caption22;
  type = type_;
  txtSize = tSize;
  }

void button::disp(){
  display.setTextSize(txtSize);
  if(pres == 0){
    display.drawRoundRect(x, y, (((caption1.length() + 2)*(5*txtSize)) + (caption1.length() - 1)), ((7+4)*txtSize), r, WHITE); 
    display.setTextColor(WHITE);
  }
  else{
    display.fillRoundRect(x, y, (((caption2.length() + 2)*(5*txtSize)) + (caption2.length() - 1)), ((7+4)*txtSize), r, WHITE);
    display.setTextColor(BLACK);
  }
  
  
  if(pres == 0){display.setTextColor(WHITE); }
  if(pres == 1){display.setTextColor(BLACK);}
  
  if(capB == 0){
    if(pres == 1){display.setTextColor(BLACK);}
    if(pres == 0){display.setTextColor(WHITE);}
    display.setCursor(x+(5*txtSize), y+(2*txtSize));
    display.print(caption1);
  }
  else{
    display.setCursor(x+(5*txtSize), y+(2*txtSize));
    display.print(caption2);
  }
}

bool button::getStatus(){
  return pres;
}
void button::update_(){
  if(type == "push_button"){
    if(!digitalRead(btnPin) == 1 && millis() - sec > 19){
      pres = 1;
      sec = millis();
    }
    if(!digitalRead(btnPin) == 0){
      pres = 0;
    }
  }
  if(type == "switch"){
    if(!digitalRead(btnPin) == 1 && millis() - sec > 189){
      pres = !pres;
      sec = millis();
    }
  }
}

void button::changeCap(bool captionB){
  capB = captionB;
}
//--------class objects--------
menu main_menu("main", "games", "stopwatch", "timer...", "settings", 12, 42);
    menu games_menu("games", "pong", "guess a number...", " ", " ", 12, 22);
      menu pongLevel_menu("level", "easy", "hard", "expert", "impossible ", 12, 42);
    menu settings_menu("settings", "sound", "credits", " ", " ", 12, 22);
        menu sound_menu("sound", "on", "off", " ", " ", 12, 22);
      
button startB(25, 32, 6, 14, "start", "stop", "switch", 2);

//--------functions-----------
void buttonsUpdate(){
  up = !digitalRead(A0);
  down = !digitalRead(A2);
  left = !digitalRead(12);
  right = !digitalRead(A1);
  a = !digitalRead(4);
}
void resetTime(){ 
    millisec = 0;
    seconds = 0;
    minutes = 0;
    hours = 0;
}
void cookTime(){ // logic for stopwatch and calcuulating milliseconds, seconds, minutes and hours 
  startB.update_();
  if(startB.getStatus() == 1){startB.changeCap(1);digitalWrite(13,1);}
  if(startB.getStatus() == 0){startB.changeCap(0);stTimeB = 1;digitalWrite(13,0);}
 
  if(startB.getStatus() == 1){
    if(stTimeB == 1){resetTime(); startTime = millis(); stTimeB = 0; }
    millisec = ((millis()-startTime)/10) % 100;
    seconds = ((millis()-startTime)/1000)%60;
    minutes = ((millis()-startTime)/(1000*60))%60;
    hours = ((millis()-startTime)/(1000*60*60))%60;
  }
}

void dispStopwatch(){ // display stopwatch
  cookTime();
  display.clearDisplay(); 
  startB.disp();
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.setCursor(8, 10);
  display.print(hours);
  display.print("|");
  display.print(minutes);
  display.print("|");
  display.print(seconds);
  display.print("|");
  display.print(millisec);
  display.display();
}

void setup() {
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay(); 
  pinMode(13, OUTPUT); 
  // buttons' pins setup
  pinMode(A0, INPUT_PULLUP); // up
  pinMode(A1, INPUT_PULLUP); // right
  pinMode(12, INPUT_PULLUP); // left
  pinMode(A2, INPUT_PULLUP); // down

  pinMode(4, INPUT_PULLUP);  // a
 }

void loop() {
 buttonsUpdate();
  if(up == 1 && down == 1){location = 0;}
  
  if(location == 0){//main menu
    main_menu.play(); 
    if(a == 1 && selY == 12/*if a btn is clicked while selected first item*/ && millis() - sec > 199){location = 1/*games*/; sec = millis();}
    if(a == 1 && selY == 22/*if a btn is clicked while selected first second*/ && millis() - sec > 199){location = 2/*stopwatch*/; sec = millis();}
    //if(a == 1 && selY == 32 && millis() - sec > 199){location = 3/*timer*/; sec = millis();}
    if(a == 1 && selY == 42/*if a btn is clicked while selected first fourth*/ && millis() - sec > 199){location = 4/*settings*/; sec = millis();}
  }

  if(location == 1){//game menu
        games_menu.play();
        if(a == 1 && selY == 12 && millis() - sec > 199){location = 11/*pong*/; sec = millis();}
      }
          if(location == 11){//pong levels
          pongLevel_menu.play();
          }
  
  if(location == 2){//stopwatch
        dispStopwatch();
  }
  if(location == 4){//settings
        settings_menu.play();
        if(a == 1 && selY == 12 && millis() - sec > 199){location = 41/*sound*/; sec = millis();}
        if(a == 1 && selY == 22 && millis() - sec > 199){location = 42/*credits*/; sec = millis();}
      }
          if(location == 41){// sound menu
            sound_menu.play();
          }
          if(location == 42){// credits
           // drawBitmap();
          }
}
Demko
  • 11
  • 2
  • the first thing to do would be to create a [mre]. You might just need to pass your strings by reference rather than copying them – Alan Birtles May 19 '23 at 12:28
  • Hello,thanks for the response, I already removed lots of code to make it easier to read. To be honest I don’t really understand what do you mean by “passing strings by reference” – Demko May 19 '23 at 12:46
  • https://stackoverflow.com/questions/10789740/passing-stdstring-by-value-or-reference – Alan Birtles May 19 '23 at 13:01
  • If you are using ATmega328 based AVR, learn how to keep the string literal in the flash memory with [PROGMEM](https://reference.arduino.cc/reference/en/language/variables/utilities/progmem/). – hcheung May 19 '23 at 13:02
  • Thanks for the advice you gave me. I spent lots of time finding what PROGMEM is used for, like I stored there bitmaps but I don’t really understand where else I should use it. – Demko May 21 '23 at 11:00

0 Answers0