Menu rewrite, clock setting prompt

I have a series of menus for a 16x2 display in my thermostat setup. Im looking to reduce their bulk, maybe with more arrays or something but have limited experience. I tried to comment it well. Each level of the menu is a function which uses buttons read with the Bounce library. They work as is and while some bits are copied the bulk is my creation.

Any tips on shrinking or simplifing?

Here is the main one which calls the others.

void mainMenu(void) {

int menulvl = 0; // 0 is the first of 3 sets of menus, each set starts with the bottom option of the last creating a scrolling effect
char* menus[] = {"Program","Heat/Cool","Set Date/Time","Backlight"}; // Menu text to write to lcd
arrow = 0; // Position of selection arrow, 0 is top line, 1 is bottom. I use it later to determine selection
lcd.clear();
lcd.setCursor(1,0);
lcd.print(menus[0]); // This block writes the initial view of the menu.
lcd.setCursor(1,1); // The delay is time for user to release button the brought the menu up.
lcd.print(menus[1]);
delay(200);

for(int i = 0; i < 40; i++) { // Button checking loop. If center button is pressed, calls submenu.

lcd.setCursor(0,arrow);
lcd.print(">"); // This sets the arrow to the current selection and blanks out the previous arrow.
lcd.setCursor(0,!arrow);
lcd.print(" ");

up.update(); // If up is pushed
if( !up.read() ) {
if (arrow == 0 && menulvl > 0) { // If its the top option of the any but the top menu move up a lvl
menulvl--;
lcd.clear();
lcd.setCursor(1,0);
lcd.print(menus[menulvl]);
lcd.setCursor(1,1);
lcd.print(menus[menulvl + 1]);
i = 0;
delay(200);
}
else if ( arrow == 1) { // If its the bottom option of any menu move to the top option of that menu
arrow--;
i = 0;
delay(200);
}
else { // If its the top option of the top menu move to the bottom of the bottom menu
menulvl = 2;
lcd.clear();
lcd.setCursor(1,0);
lcd.print(menus[menulvl]);
lcd.setCursor(1,1);
lcd.print(menus[menulvl + 1]);
arrow = 1;
i = 0;
delay(200);
}
}
down.update(); // If down is pushed
if( !down.read() ) {
if ( arrow == 1 && menulvl < 2) { // If its the bottom of any but the bottom menu move down a lvl
menulvl++;
lcd.clear();
lcd.setCursor(1,0);
lcd.print(menus[menulvl]);
lcd.setCursor(1,1);
lcd.print(menus[menulvl + 1]);
i = 0;
delay(200);
}
else if ( arrow == 0 ){ // If its the top option of any menu move to the bottom option of that menu
arrow++;
i = 0;
delay(200);
}
else {
menulvl = 0; // If its the bottom of the bottom menu move to the top of the top menu
lcd.clear();
lcd.setCursor(1,0);
lcd.print(menus[menulvl]);
lcd.setCursor(1,1);
lcd.print(menus[menulvl +1]);
menulvl = 0;
i = 0;
arrow = 0;
delay(200);
}
}
center.update(); // If the "select" button is pressed
if( !center.read() ) {
switch (menulvl) { //check which menu your on
case 0:
if ( arrow ) {
systemSelect(); // 1st menu, 2nd option
break;
}
else {
programMenu(); // 1st menu, 1st option
break;
}
case 1:
if ( arrow ) {
timeMenu(); // 2nd menu, 2nd option
break;
}
else {
systemSelect(); // 2nd menu, 1st option
break;
}
case 2:
if ( arrow ) {
backlight(); // 3rd menu, 2nd option
break;
}
else {
timeMenu(); // 3rd menu, 1nd option
break;
}
}
break;
}
delay(100);
}
}

ill post my clock setting prompt next.

This is the clock setting code.
I edited out the part where is sends the data to an RTC all at once at the bottom for more space.

the code follows a basic repetitive pattern that Id love to find a way to loop!

void timeMenu(void) {
while (1) {

lcd.clear();
lcd.setCursor(1,0);
lcd.print("Year:"); // This block displays the current set year.
lcd.setCursor(6,1); // The Therm checks an RTC at startup to set it.
if (year < 10 ) {
lcd.print("200");
}
else {
lcd.print("20");
}
lcd.print(year);
delay(200);

up.update();
if ( !up.read() ) {
if ( year < 99 ) {
year++;
delay(200);
} // if up is pressed than year++. Rolls over at 99.
else {
year = 1;
delay(200);
}
}
down.update();
if ( !down.read() ) {
if ( year > 1 ) {
year--;
delay(200);
}
else {
year = 99;
delay(200);
}
}
center.update();
if ( !center.read() ) {
break; // this design means you have to press center (or reset) to move on or back and thats ok
}
}
while (1) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Month:");
lcd.setCursor(8,1);
lcd.print(month);
delay(200);
up.update();
if ( !up.read() ) {
if ( month < 12 ) {
month++;
delay(200);
} // set the month. same as above but rolls at 12
else {
month = 1;
delay(200);
}
}
down.update();
if ( !down.read() ) {
if ( month > 1 ) {
month--;
delay(200);
}
else {
month = 12;
delay(200);
}
}
center.update();
if ( !center.read() ) {
break;
}
}
while (1) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Day of Month:");
lcd.setCursor(8,1);
lcd.print(dayOfMonth);
delay(200);
up.update();
if ( !up.read() ) {
if ( dayOfMonth < 31 ) {
dayOfMonth++;
delay(200);
} //set the day of the month. rolls at 31. may add code to determine month dependent boundries
else {
dayOfMonth = 1;
delay(200);
}
}
down.update();
if ( !down.read() ) {
if ( dayOfMonth > 1 ) {
dayOfMonth--;
delay(200);
}
else {
dayOfMonth = 31;
delay(200);
}
}
center.update();
if ( !center.read() ) {
break;
}
}
while (1) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Day of week:");
lcd.setCursor(8,1);
lcd.print(dayOfWeek);
delay(200);
up.update();
if ( !up.read() ) {
if ( dayOfWeek < 7 ) {
dayOfWeek++;
delay(200);
} //set day of week. rolls at 7.
else {
dayOfWeek = 1;
delay(200);
}
}
down.update();
if ( !down.read() ) {
if ( dayOfWeek > 1 ) {
dayOfWeek--;
delay(200);
}
else {
dayOfWeek = 7;
delay(200);
}
}
center.update();
if ( !center.read() ) {
break;
}
}
while (1) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Hour:");
lcd.setCursor(8,1);
lcd.print(hour);
delay(200);
up.update();
if ( !up.read() ) {
if ( hour < 23 ) {
hour++;
delay(200);
} //set hour, military style
else {
hour = 0;
delay(200);
}
}
down.update();
if ( !down.read() ) {
if ( hour > 0 ) {
hour--;
delay(200);
}
else {
hour = 23;
delay(200);
}
}
center.update();
if ( !center.read() ) {
break;
}
}
while (1) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Minute:");
lcd.setCursor(8,1);
lcd.print(minute);
delay(200);
up.update();
if ( !up.read() ) {
if ( minute < 59 ) {
minute++;
delay(200);
} //bored yet? set min, rolls at 59
else {
minute = 0;
delay(200);
}
}
down.update();
if ( !down.read() ) {
if ( minute > 0 ) {
minute--;
delay(200);
}
else {
minute = 60;
delay(200);
}
}
center.update();
if ( !center.read() ) {
break;
}
}
}

Thanks in advance guys!

Id love to find a way to loop!

It's screaming "array".

maybe 4 arrays:

one with the text
one with the variables
one with the boundaries
one with rollover values

mock/sudo code:

for ( int i = 0 ; i < 6 ; i++ ) { <-- six time variables to set
while ( centerbutton not pushed) {
display text from array1*;*

  • if ( up is pressed) {*
    if ( variable from array2 is less than array3 ) {
    _ variable from array2*++;
    delay(200);
    }
    else {_

    variable from array2 _= rollover value from array4;
    delay(200);
    }
    }
    ... and so on*

    am I close?_

heres a real rewrite. not that it works... :-[

trying to get the menu to work before I worry about using my new arrays elsewhere. The code brings up the text "year:" as expected but instead of displaying the variable year it just displays a blob. Whats my syntax error?

void timeMenu(void) {

char* unitlist[] = {"Year:","Month:","Day of Month:","Day of Week:","Hour:","Minute:"};
char values[] = {year, month, dayOfMonth, dayOfWeek, hour, minute};
char upperbound[] = {99,12,31,7,23,59};
char lowerbound[] = {10,1,1,1,};
center.update();
for ( int i = 0 ; i < 6 ; i++ ) {
delay(200);
while ( !center.read() ) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print(unitlist*);*

  • lcd.setCursor(8,0);*
    _ lcd.print(values*);_
    _
    up.update();_
    _
    if ( !up.read() ) {_
    if ( values < upperbound ) {
    _ values++;
    delay(200);
    }
    else {
    values = lowerbound;
    delay(200);
    }
    }
    down.update();
    if ( !down.read() ) {
    if ( values > lowerbound ) {
    values--;
    delay(200);
    }
    else {
    values = upperbound;
    delay(200);
    }
    }
    center.update();
    }
    }
    Wire.beginTransmission(RTCI2C);
    Wire.send(0x00);
    Wire.send(0x00);
    Wire.send(D2B(minute));
    Wire.send(D2B(hour));
    Wire.send(D2B(dayOfWeek)); //finally, send them off to the RTC*

    * Wire.send(D2B(dayOfMonth));
    Wire.send(D2B(month));
    Wire.send(D2B(year));
    Wire.endTransmission();
    dateset = true; //used in main loop to keep from displaying unset clock*

    }
    [/quote]_

Ive globalized an array for the time variables and changed them to ints.
now the year prompt kinda works, displaying everything right but exits to main loop on ANY button press...

side question: if I just define the length of date[] as 7 will it still initialize as all 0s?

int date[] = {0,0,0,0,0,0,0}; // [0] = year, all the way to [7] = second (this is global)

void getDate() {
Wire.beginTransmission(RTCI2C);
Wire.send(0x00);
Wire.endTransmission();
Wire.requestFrom(RTCI2C, 7);
date[6] = B2D(Wire.receive());
date[5] = B2D(Wire.receive());
date[4] = B2D(Wire.receive());
date[3] = B2D(Wire.receive());
date[2] = B2D(Wire.receive());
date[1] = B2D(Wire.receive());
date[0] = B2D(Wire.receive());
}

void timeMenu(void) {

char* unitlist[] = {"Year:","Month:","Day of Month:","Day of Week:","Hour:","Minute:"};
char upperbound[] = {99,12,31,7,23,59};
char lowerbound[] = {10,1,1,1,};
center.update();
for ( int i = 0 ; i < 6 ; i++ ) {
delay(200);
while ( !center.read() ) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print(unitlist*);*

  • lcd.setCursor(8,0);*
    _ lcd.print(date*);_
    _
    up.update();_
    _
    if ( !up.read() ) {_
    if ( date < upperbound ) {
    _ date++;
    delay(200);
    }
    else {
    date = lowerbound;
    delay(200);
    }
    }
    down.update();
    if ( !down.read() ) {
    if ( date > lowerbound ) {
    date--;
    delay(200);
    }
    else {
    date = upperbound;
    delay(200);
    }
    }
    center.update();
    }
    }
    /

    * Wire.beginTransmission(RTCI2C);
    Wire.send(0x00);
    Wire.send(0x00);
    Wire.send(D2B(date[5]));
    Wire.send(D2B(date[4]));
    Wire.send(D2B(date[3]));// setting time disabled til the menu works*

    * Wire.send(D2B(date[2]));
    Wire.send(D2B(date[1]));
    Wire.send(D2B(date[0]));
    Wire.endTransmission();
    dateset = true;
    /

    }
    byte D2B(byte val) {
    return ( (val/1016) + (val%10) );
    }
    byte B2D(byte val) {
    return ( (val/1610) + (val%16) );

    }
    [/quote]_

got it! remember that date is global for my other functions to use. [0] is year, [6] is seconds

void timeMenu(void) {

char* unitlist[] = {"Year:","Month:","Day of Month:","Day of Week:","Hour:","Minute:"};
char upperbound[] = {99,12,31,7,23,59};
char lowerbound[] = {10,1,1,1,};
for ( int i = 0 ; i < 6 ; i++ ) {
while ( true ) {
lcd.clear();
lcd.setCursor(1,0);
lcd.print(unitlist*);*

  • lcd.setCursor(8,1);*
    _ lcd.print(date*);_
    _
    delay(200);_
    _
    up.update();_
    _
    if ( !up.read() ) {_
    if ( date < upperbound ) {
    _ date++;
    delay(200);
    }
    else {
    date = lowerbound;
    delay(200);
    }
    }
    down.update();
    if ( !down.read() ) {
    if ( date > lowerbound ) {
    date--;
    delay(200);
    }
    else {
    date = upperbound;
    delay(200);
    }
    }
    center.update();
    if ( !center.read() ) {
    break;
    }
    }
    }
    Wire.beginTransmission(RTCI2C);
    Wire.send(0x00);
    Wire.send(0x00);
    Wire.send(D2B(date[5]));
    Wire.send(D2B(date[4]));
    Wire.send(D2B(date[3]));
    Wire.send(D2B(date[2]));
    Wire.send(D2B(date[1]));
    Wire.send(D2B(date[0]));
    Wire.endTransmission();
    dateset = true;
    }
    [/quote]*_