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();
}
}
String
s often fragment available RAM into unusably small pieces; C strings - null-terminated character arrays - are much more RAM-friendly. Any constants, constant strings, constant members of objects, can be moved to Flash too, to free more of the limited RAM. Search "PROGMEM Arduino" for tutorials. Practice with them until you can apply the principles to your code.Link is to stack Overflow where code can pase normaly
... the code parses the same way here ... readSyntax highlighting for code
here arduino.stackexchange.com/editing-help ...