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();
}
}