First thing today, we are building the
missing function from my last post, adj_seasons(). But before we
start doing this, we need to add a few more variables first. As usual
we start with the declaration part and this time we jump right down
into the “menu and user interface” section. There we add a few
lines to the msg_table:
//Storing some menu messages in the program memory prog_char msg_0[] PROGMEM = "Not Used"; prog_char msg_1[] PROGMEM = "Saving...."; prog_char msg_2[] PROGMEM = "Setup mode"; prog_char msg_3[] PROGMEM = "Starting...."; prog_char msg_4[] PROGMEM = "RMU 1.3.7"; prog_char msg_5[] PROGMEM = "Weekday"; prog_char msg_6[] PROGMEM = "On TIMER Off"; prog_char msg_7[] PROGMEM = "Off "; prog_char msg_8[] PROGMEM = "Active"; prog_char msg_9[] PROGMEM = "PIR Delay R"; prog_char msg_10[] PROGMEM = "T1 On/Off R"; prog_char msg_11[] PROGMEM = "T2 On/Off R"; prog_char msg_12[] PROGMEM = "T3 On/Off R"; prog_char msg_13[] PROGMEM = "ADJ Hour On"; prog_char msg_14[] PROGMEM = "ADJ Minute On"; prog_char msg_15[] PROGMEM = "ADJ Hour Off"; prog_char msg_16[] PROGMEM = "ADJ Minute Off"; prog_char msg_17[] PROGMEM = "Set Sensitivity"; prog_char msg_18[] PROGMEM = "Set photocell R"; prog_char msg_19[] PROGMEM = "Set photocell O"; prog_char msg_20[] PROGMEM = "ADJ Time Minute"; prog_char msg_21[] PROGMEM = "ADJ Time Hour"; prog_char msg_22[] PROGMEM = "ADJ Date Day"; prog_char msg_23[] PROGMEM = "ADJ Date Month"; prog_char msg_24[] PROGMEM = "ADJ Date Year"; prog_char msg_25[] PROGMEM = "T4 On/Off R"; prog_char msg_26[] PROGMEM = "ADJ AC Mode"; prog_char msg_27[] PROGMEM = "AC Set Temp"; prog_char msg_28[] PROGMEM = "AC Switch Delay"; //>>>>>>>>>>>>>Addition starts here<<<<<<<<<<<<<< prog_char msg_29[] PROGMEM = "AC Seas 1 Start"; prog_char msg_30[] PROGMEM = "AC Seas 1 End"; prog_char msg_31[] PROGMEM = "AC Seas 2 Start"; prog_char msg_32[] PROGMEM = "AC Seas 2 End"; prog_char msg_33[] PROGMEM = "AC Seas 3 Start"; prog_char msg_34[] PROGMEM = "AC Seas 3 End"; prog_char msg_35[] PROGMEM = "AC Seas 4 Start"; prog_char msg_36[] PROGMEM = "AC Seas 4 End"; //>>>>>>>>>>>>>ADDITION ends here<<<<<<<<<<<<< //Creating the table for the stored menu messages PROGMEM const char *msg_table[] = { msg_0, msg_1, msg_2, msg_3, msg_4, msg_5, msg_6, msg_7, msg_8, msg_9, msg_10, msg_11, msg_12, msg_13, msg_14, msg_15, msg_16, msg_17, msg_18, msg_19, msg_20, msg_21, msg_22, msg_23, msg_24, msg_25, msg_26, msg_27, msg_28, //<<<<<<<<<<<<<Don't forget to add ',' //>>>>>>>>>>>>>Addition starts here<<<<<<<<<<<<<< msg_29, msg_30, msg_31, msg_32, msg_33, msg_34, msg_35, msg_36 //>>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<< }; //storing some special char's in the program memory
While I was writing the Ac-menu part,
my little mix up with numbers caught me again. We all now arrays
start counting with a 0 and having 20 spaces in an array the last
count is 19. Going in to a counting routine, giving a min count of 0
and a max count of 20, it always will go through the 20 spaces in an
array from 0 to 19. But using the same routine and counting through
20 event, starting with 1 and giving it min count of 1 and a max
count of 20, we always will miss the last event. Doesn't make sense?
OK, lets look at the get_Timer function
get_Timer(varForInfoText, actValue, minCount, maxCount).
Lets forget about the first 2 variables
we are passing and concentrate on the minCount and maxCount.
The routine dealing with this values is
a if-statement:
if(reading >= startVal &&
reading < maxCount) reading++;
Lets get it apart. If the variable
reading is equal to or bigger than the var startVal (minCount) and
the variable reading is smaller than maxCount we add 1 to the
variable reading.
Back to our array example. If I pass
the numbers stepping through an array with a max count of 20 and a
min value of 0 because arrays start counting at 0, I always get my 20
values done since the last counter in the array is 19, matches with
smaller than 20 (maxCount).
If I need to count through other values
like days of a month, the first one is 1 and the last one is 31 and I
pass this in to my function minCount 1 and maxCount 31, with the same
routine my 31 day will never show since the we are stating “and the
variable reading is smaller than maxCount” (&& reading <
maxCount). If we want the same routine to step through 31 days we
need to pass as maxCount 32! The same goes for month. To step through
12 month, we need to pass as max count 13 cause of “&&
reading < maxCount”. Now it make sense I hope. Since we need to
change a couple of variables in the get_ac_setup() function and that
is also the reason why we are passing on a 13 as max count while
going through month etc.
Lets jump into the get_ac_setup()
function
void get_ac_setup(){ byte subButton = 0; acSetup = 1; //submenu counter (AC Mode) lcd.clear(); //clear screen //retrieving and printing first sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_setup_table[0])))); while(acSetup < acSetups){ //loop through the submenu points subButton = read_act_buttons(); //checking for pressed buttons if(subButton == btnMenu){ //if button menu was pressed acSetup++; //add 1 - move to the next point if(acSetup == 2){ //if we are at submenu 2 (Set Temp) lcd.clear(); //clear screen //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_setup_table[1])))); } if(acSetup == 3){ //if we are at submenu 3 (Seasons) lcd.clear(); //retrieving and printing the third sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_setup_table[2])))); } if(acSetup == 4){ //if we are at submenu 4 (Switch delay) lcd.clear(); //clear screen //retrieving and printing sub menu point 4 lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_setup_table[3])))); } } if(subButton == btnSelect){ //if btn select was pressed if(acSetup == 1){ //and sub menu is 1 //call function get_Timer ac_op_mode = get_Timer(26, ac_op_mode, 1, 3); //<<<<<<<<<<<<<CHANGE to get_Timer(26, ac_op_mode, 1, 4) return; } if(acSetup == 2){ //and sub menu is 2 //call function get_Timer ac_set_temp = get_Timer(27, ac_set_temp, 18, 32); return; } if(acSetup == 3){ //and submenu is 3 //call function adj_Seasons adj_seasons(); return; } if(acSetup == 4){ //call function get_Timer acSwitchDelay = get_Timer(28, acSwitchDelay, 1, 5); return; } } } }
OK, now we can go through the 3
available operating modes. Next task today is building the function
to adjust the seasonal boundaries.
void adj_seasons(){ byte subButton = 0; //set button var to 0 ac_periode[0][0] = get_Timer(29, ac_periode[0][0], 0, 13); //get the first value if(ac_periode[0][0] >= 0 && ac_periode[0][0] <= 12){ //check if it is within range if(ac_periode[0][0] == 12){ //predefine closing value ac_periode[0][1] = 1; ac_periode[0][1] = get_Timer(30, ac_periode[0][1], 1, 13); } else if(ac_periode[0][0] != 12){ ac_periode[0][1] = ac_periode[0][0] + 1; ac_periode[0][1] = get_Timer(30, ac_periode[0][1], ac_periode[0][1], 13); } if(ac_periode[0][1] >= 0 && ac_periode[0][1] <= 12){ ac_periode[1][0] = get_Timer(31, ac_periode[1][0], 0, 13); if(ac_periode[1][0] >= 0 && ac_periode[1][0] <= 12){ if(ac_periode[1][0] == 12){ ac_periode[1][1] = 1; ac_periode[1][1] = get_Timer(32, ac_periode[1][1], 1, 13); } else if(ac_periode[1][0] != 12){ ac_periode[1][1] = ac_periode[1][0] + 1; ac_periode[1][1] = get_Timer(32, ac_periode[1][1], ac_periode[0][1], 13); } if(ac_periode[1][1] >= 0 && ac_periode[1][1] <= 12){ ac_periode[2][0] = get_Timer(33, ac_periode[2][0], 0, 13); if(ac_periode[2][0] >= 0 && ac_periode[2][0] <= 12){ if(ac_periode[2][0] == 12){ ac_periode[2][1] = 1; ac_periode[2][1] = get_Timer(34, ac_periode[2][1], 1, 13); } else if(ac_periode[2][0] != 12){ ac_periode[2][1] = ac_periode[2][0] + 1; ac_periode[2][1] = get_Timer(34, ac_periode[2][1], ac_periode[2][1], 13); } if(ac_periode[2][1] >= 0 && ac_periode[2][1] <= 12){ ac_periode[3][0] = get_Timer(35, ac_periode[3][0], 0, 13); if(ac_periode[3][0] >= 0 && ac_periode[3][0] <= 12){ if(ac_periode[3][0] == 12){ ac_periode[3][1] = 1; ac_periode[3][1] = get_Timer(36, ac_periode[3][1], 1, 13); } else if(ac_periode[3][0] != 12){ ac_periode[3][1] = ac_periode[2][0] + 1; ac_periode[3][1] = get_Timer(36, ac_periode[3][1], ac_periode[3][1], 13); } lcd.clear(); if(ac_periode[0][0] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[0][0]); lcd.print(" | "); if(ac_periode[0][1] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[0][1]); lcd.print(" "); if(ac_periode[1][0] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[1][0]); lcd.print(" | "); if(ac_periode[1][1] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[1][1]); lcd.setCursor(0, 1); if(ac_periode[2][0] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[2][0]); lcd.print(" | "); if(ac_periode[2][1] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[2][1]); lcd.print(" "); if(ac_periode[3][0] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[3][0]); lcd.print(" | "); if(ac_periode[3][1] < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(ac_periode[3][1]); while(subButton != btnSelect){ lcd.clear(); lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[1])))); delay(1000); //save the values return; } } } } } } } } }
The basic structure is also nothing
new. We have used the same structure in the date and time adjustment
and in the timer adjustments. The only difference is that we add a
limitation. If we start a season at February (2) the count for the
end of that season will only allow to go through the remaining month
of the year March to December.
Let's carry on with the AC submenu and
jump back up into the declaration part of the sketch. There we have
to add a couple of variables and store the ac submenu points in the
program memory. We go right into the “menu and user interface”
section:
/////////////////////////////////////////////////////////////////////////// ///////////////////Menu and user interface///////////////////////////////// /////////////////////////////////////////////////////////////////////////// const byte btnMenu = 1; //defining the menu button – moves through the menu const byte btnSearch = 2; //defining the search button – moves through values const byte btnSelect = 3; //defining the select button – selects a menu or a value const byte btnNone = 0; //defining the non button pressed var int act_key_in = 0; //var holding the key related sensor reading byte menuOption = 0; //var to count current menu option const byte menuOptions = 21; //available menu options byte submenu = 0; //var to count current submenu option const byte submenus = 10; //available submenu options byte acSetup = 0; //var to count current ac setup menu options const byte acSetups = 4; //available ac setup menu options //>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<<< byte acSubOption = 0; //var to count current ac sub menu options const byte acSubOptions = 10; //available ac sub menu options //>>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<<<<
from here we go down to the msg_table[]
and add a couple of lines:
//Storing some menu messages in the program memory prog_char msg_0[] PROGMEM = "Not Used"; prog_char msg_1[] PROGMEM = "Saving...."; prog_char msg_2[] PROGMEM = "Setup mode"; prog_char msg_3[] PROGMEM = "Starting...."; prog_char msg_4[] PROGMEM = "RMU 1.3.8"; prog_char msg_5[] PROGMEM = "Weekday"; prog_char msg_6[] PROGMEM = "On TIMER Off"; prog_char msg_7[] PROGMEM = "Off "; prog_char msg_8[] PROGMEM = "Active"; prog_char msg_9[] PROGMEM = "PIR Delay R"; prog_char msg_10[] PROGMEM = "T1 On/Off R"; prog_char msg_11[] PROGMEM = "T2 On/Off R"; prog_char msg_12[] PROGMEM = "T3 On/Off R"; prog_char msg_13[] PROGMEM = "ADJ Hour On"; prog_char msg_14[] PROGMEM = "ADJ Minute On"; prog_char msg_15[] PROGMEM = "ADJ Hour Off"; prog_char msg_16[] PROGMEM = "ADJ Minute Off"; prog_char msg_17[] PROGMEM = "Set Sensitivity"; prog_char msg_18[] PROGMEM = "Set photocell R"; prog_char msg_19[] PROGMEM = "Set photocell O"; prog_char msg_20[] PROGMEM = "ADJ Time Minute"; prog_char msg_21[] PROGMEM = "ADJ Time Hour"; prog_char msg_22[] PROGMEM = "ADJ Date Day"; prog_char msg_23[] PROGMEM = "ADJ Date Month"; prog_char msg_24[] PROGMEM = "ADJ Date Year"; prog_char msg_25[] PROGMEM = "T4 On/Off R"; prog_char msg_26[] PROGMEM = "ADJ AC Mode"; prog_char msg_27[] PROGMEM = "AC Set Temp"; prog_char msg_28[] PROGMEM = "AC Switch Delay"; prog_char msg_29[] PROGMEM = "AC Seas 1 Start"; prog_char msg_30[] PROGMEM = "AC Seas 1 End"; prog_char msg_31[] PROGMEM = "AC Seas 2 Start"; prog_char msg_32[] PROGMEM = "AC Seas 2 End"; prog_char msg_33[] PROGMEM = "AC Seas 3 Start"; prog_char msg_34[] PROGMEM = "AC Seas 3 End"; prog_char msg_35[] PROGMEM = "AC Seas 4 Start"; prog_char msg_36[] PROGMEM = "AC Seas 4 End"; //>>>>>>>>>>>>>Addition starts here<<<<<<<<<<<<< prog_char msg_37[] PROGMEM = "AC Off delay"; prog_char msg_38[] PROGMEM = "AC master byp"; //>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<< //Creating the table for the stored menu messages PROGMEM const char *msg_table[] = { msg_0, msg_1, msg_2, msg_3, msg_4, msg_5, msg_6, msg_7, msg_8, msg_9, msg_10, msg_11, msg_12, msg_13, msg_14, msg_15, msg_16, msg_17, msg_18, msg_19, msg_20, msg_21, msg_22, msg_23, msg_24, msg_25, msg_26, msg_27, msg_28, msg_29, msg_30, msg_31, msg_32, msg_33, msg_34, msg_35, msg_36, //<<<<<<<<<<<<<Don't forget to add the ',' //>>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<< msg_37, msg_38 //>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<<< }; //storing some special char's in the program memory
Now we move down a little and just
after the ac_setup_table we start building the ac_sub_table:
//storing the AC sub menu prog_char ac_sub_0[] PROGMEM = "AC off delay R"; prog_char ac_sub_1[] PROGMEM = "AC Master byp R"; prog_char ac_sub_2[] PROGMEM = "AC ST1 Active R"; prog_char ac_sub_3[] PROGMEM = "AC Timer 1 R"; prog_char ac_sub_4[] PROGMEM = "AC ST2 Active R"; prog_char ac_sub_5[] PROGMEM = "AC Timer 2 R"; prog_char ac_sub_6[] PROGMEM = "AC ST3 Active R"; prog_char ac_sub_7[] PROGMEM = "AC Timer 3 R"; prog_char ac_sub_8[] PROGMEM = "AC ST4 Active R"; prog_char ac_sub_9[] PROGMEM = "AC Timer 4 R"; PROGMEM const char *ac_sub_table[] = { ac_sub_0, ac_sub_1, ac_sub_2, ac_sub_3, ac_sub_4, ac_sub_5, ac_sub_6, ac_sub_7, ac_sub_8, ac_sub_9 };
So far so good, a big jump now, to the
end of the selectMenu() function where we have to add also a few
statements:
if(menuOption == 16){ //and menu option is 16 (room 10) get_submenu(9); }//submenu end if(menuOption == 17){ //and menu option is 17 (AC setup) get_ac_setup(); //submenu end } //>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<< if(menuOption == 18){ //and menu option is 18 (AC room 1) get_ac_sub(10); //submenu end } if(menuOption == 19){ //and menu option is 19 (AC room 2) get_ac_sub(11); //submenu end } if(menuOption == 20){ //and menu option is 20 (AC room 3) get_ac_sub(12); //submenu end } if(menuOption == 21){ //and menu option is 21 (AC room 4) get_ac_sub(13); //submenu end } //>>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<<< } } } void get_submenu(byte room){
From here we move down to the end of
the get_ac_setup() function where we build the new get_ac_sub()
function
void get_ac_sub(byte room){ byte subButton = 0; //resetting the button var acSubOption = 1; //submenu counter lcd.clear(); //clear screen //retrieving and printing first submenu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[0])))); lcd.print(room - 9); //printing assigned room number while(acSubOption < acSubOptions){ //loop through the submenu points subButton = read_act_buttons(); //checking for pressed buttons if(subButton == btnMenu){ //if btn menu was pressed acSubOption++; // add 1 to move to the next sub menu point if(acSubOption == 2){ //if we are at sub menu 2 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[1])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 3){ //if we are at sub menu 3 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[2])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 4){ //if we are at sub menu 4 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[3])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 5){ //if we are at sub menu 5 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[4])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 6){ //if we are at sub menu 6 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[5])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 7){ //if we are at sub menu 7 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[6])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 8){ //if we are at sub menu 8 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[7])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 9){ //if we are at sub menu 9 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[8])))); lcd.print(room - 9); //printing assigned room number } if(acSubOption == 10){ //if we are at sub menu 10 lcd.clear(); //retrieving and printing second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[9])))); lcd.print(room - 9); //printing assigned room number } } if(subButton == btnSelect){ //if btn select was pressed if(acSubOption == 1){ //and submenu point is 1 //call the function get_delay() to change the setting delayTime[room] = get_delay(37, room, delayTime[room]); return; } if(acSubOption == 2){ //and sub menu point is 2 //call the function get_offon to change setting ac_master_bypass[room - 10] = get_offon(38, room, ac_master_bypass[room - 10]); return; } if(acSubOption == 3){ //and sub menu point is 3 //call the function get_offon to change setting timer_active[room][0] = get_offon(10, room, timer_active[room][0]); return; } if(submenu == 4){ //and submenu is 4 //call the function get_setTime() to change timer 1 get_setTime(room_timers[room][0][0], room_timers[room][0][1], room_timers[room][0][2], room_timers[room][0][3], room, 0); return; } if(submenu == 5){ //and submenu is 5 //call the function get_offon() to change the setting timer_active[room][1] = get_offon(11, room, timer_active[room][1]); return; } if(submenu == 6){ //and submenu is 6 //call the function get_setTime() to change timer 2 get_setTime(room_timers[room][1][0], room_timers[room][1][1], room_timers[room][1][2], room_timers[room][1][3], room, 1); return; } if(submenu == 7 && timer_active[room][2] != 2){ //and submenu is 7 //call the function get_offon() to change the setting timer_active[room][2] = get_offon(12, room, timer_active[room][2]); return; } if(submenu == 8 && timer_active[room][2] != 2){ //and submenu == 8 //call function get_setTime() to change timer 3 get_setTime(room_timers[room][2][0], room_timers[room][2][1], room_timers[room][2][2], room_timers[room][2][3], room, 2); return; } if(submenu == 9 && timer_active[room][3] != 2){ //and submenu is 9 //call the function get_offon() to change the setting timer_active[room][3] = get_offon(25, room, timer_active[room][3]); return; } if(submenu == 10 && timer_active[room][3] != 2){ //and submenu == 10 //call function get_setTime() to change timer 3 get_setTime(room_timers[room][3][0], room_timers[room][3][1], room_timers[room][3][2], room_timers[room][3][3], room, 3); return; } } } }