Translate

Showing posts with label menu. Show all posts
Showing posts with label menu. Show all posts

Sunday, 15 June 2014

Room Management system – The Menu part 16 – with EEPROM


In the final menu post, we make changes permanent saving them back to the EEPROM. There fore we jump down to the selectMenu() function, where we add after every adjusting function call returning a value the command to update the value in the EEPROM like:

sensitivity = get_Timer(17, sensitivity, 0, 1000); //go to function 

In the above statement the function timer returns the updated value for sensitivity. Since the variable sensitivity is updated, we use it to also update the value stored in the EEPROM and because the value contained in sensitivity can be anything between 0 and 1000, we treat it as integer and call the function Mem_updateInt(Sensitivity_ADDR, sensitivity). Now the function Mem_updateInt checks if the value has changed and only writes the value to the EEPROM if it did. As variables we have to pass on the eeprom address holding the value which is easy since we used the variable name and added just a _ADDR to it to store the address in the eeprom holding the value and we need to pass the updated value. I this case the updated variable sensitivity. The whole statement reads like that:

sensitivity = get_Timer(17, sensitivity, 0, 1000); //go to function

Mem_updateInt(Sensitivity_ADDR, sensitivity);

This we have to do with all the adjusting functions returning a value:

case 21: //menu point with option arrow right

case 22: //menu point with option arrow right

lcd.setCursor(15,0); //set cursor column 15, row 0

//retrieve and print "arrow right"

lcd.write(pgm_read_byte(&char_table[0]));

break;

}

}

if(button == btnSelect){ //if the select button is pressed

if(menuOption == 1){ //amd menu option is 1

adjust_date_time(); //go to ajdust date and time

return;

}

if(menuOption == 2){ //and menu option is 2

sensitivity = get_Timer(17, sensitivity, 0, 1000); //go to function

Mem_updateInt(Sensitivity_ADDR, sensitivity);

return;

}

if(menuOption == 3){ //and menu option is 3

photoCellCutOff = get_Timer(18, photoCellCutOff, 0, 1024); //go to function

Mem_updateInt(photoCellCutOff_ADDR, photoCellCutOff);

return;

}

if(menuOption == 4) return; //and menu option is 4 return (not used)

if(menuOption == 5){ //and menu option is 5

photoOutsideOff = get_Timer(19, photoOutsideOff, 0, 1024); //go to function

Mem_updateInt(photoOutsideOff_ADDR, photoOutsideOff);

return;

}

if(menuOption == 6) return; //and menu option is 6 return (not used)

if(menuOption == 7){ //and menu option is 7 (room 1)

get_submenu(0);

}

if(menuOption == 8){ //and menu option is 8 (room 2)

get_submenu(1);

} //submenu end

if(menuOption == 9){ //and menu option is 9 (room 3)

get_submenu(2);

} //submenu end

if(menuOption == 10){ //and menu option is 9 (room 4)

get_submenu(3);

}

if(menuOption == 11){ //and menu option is 11 (room 5)

get_submenu(4);

}

if(menuOption == 12){ //and menu option is 12 (room 6)

get_submenu(5);

} //submenu end

if(menuOption == 13){ //and menu option is 13 (room 7)

get_submenu(6);

} //submenu end

if(menuOption == 14){ //and menu option is 14 (room 8)

get_submenu(7);

} //submenu end

if(menuOption == 15){ //and menu option is 15 (room 9)

get_submenu(8);

} //submenu end

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

}

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

}

if(menuOption == 22){ //and menu option is 16 (room 10)

get_submenu(15);

} //submenu end

}

}

}

in the function selectMenu() it effects the menu options 2, 3, and 5. In the get_submenu() function the submenu options 1, 2, 4, 6 and 8 are effected:

case 9: //menu point + checking timer 3 options

if(timer_active[room][3] == 2){ //if set to 2

lcd.setCursor(0, 1); //set cursor to column 0, row 1

//retrieve and print not used

lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[0])))); //print not used

}

break;

case 10:

lcd.setCursor(0, 1); //set cursor to column 0, row 1

//retrieve and print not used

lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(msg_table[0])))); //print not used

break;

}

}

if(subButton == btnSelect){ //if we pressed btnSelect

if(submenu == 1){ //and submenu is 1

//call the function get_delay() to change the setting

if(room == 15) return;

delayTime[room] = get_delay(9, room, delayTime[room]);

Mem_updateInt(delayTime_ADDR[room], delayTime[room]);

return;

}

if(submenu == 2){ //and sub menu is 2

//call the function get_offon to change the setting

timer_active[room][0] = get_offon(10, room, timer_active[room][0]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][0])), timer_active[room][0]);

return;

}

if(submenu == 3){ //and submenu is 3

//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 == 4){ //and submenu is 4

//call the function get_offon() to change the setting

timer_active[room][1] = get_offon(11, room, timer_active[room][1]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][1])), timer_active[room][1]);

return;

}

if(submenu == 5){ //and submenu is 5

//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 == 6 && timer_active[room][2] != 2){ //and submenu is 6

//call the function get_offon() to change the setting

timer_active[room][2] = get_offon(12, room, timer_active[room][2]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][2])), timer_active[room][2]);

return;

}

if(submenu == 7 && timer_active[room][2] != 2){ //and submenu == 7

//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 == 8 && timer_active[room][3] != 2){ //and submenu is 6

//call the function get_offon() to change the setting

timer_active[room][3] = get_offon(25, room, timer_active[room][3]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][3])), timer_active[room][3]);

return;

}

if(submenu == 9 && timer_active[room][3] != 2){ //and submenu == 7

//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;

}

if(submenu == 10) return;

}

}

} 

in the get_ac_setup() function all menu options need the update statement for the EEPROM.

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

lcd.clear();

//printing and retrieving the menu points

lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_setup_table[acSetup - 1]))));

}

if(subButton == btnSelect){ //if btn select was pressed

switch(acSetup){ //going right through the options

case 1:

//call the function get_timer() to update settings

ac_op_mode = get_Timer(26, ac_op_mode, 1, 4);

Mem_updateByte(ac_op_mode_ADDR, ac_op_mode);

return;

case 2:

//call the function get_timer() to update settings

ac_set_temp = get_Timer(27, ac_set_temp, 18, 32);

Mem_updateByte(ac_set_temp_ADDR, ac_set_temp);

return;

case 3:

adj_seasons();

return;

case 4:

//call the function get_timer() to update settings

acSwitchDelay = get_Timer(28, acSwitchDelay, 1, 5);

Mem_updateByte(acSwitchDelay_ADDR, acSwitchDelay);

return;

case 5:

//call the function get_offon() tu update settings

startDelay = get_offon(39, 0, startDelay);

Mem_updateByte(startDelay_ADDR, startDelay);

return;

}

}

}

}

In the get_ac_sub() function we need to add the update statement to the menu options 1, 2, 3, 5, 7 and 9.

lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(ac_sub_table[acSubOption - 1]))));

lcd.print(room - 9); //printing assigned room number

}

if(subButton == btnSelect){

switch(acSubOption){

case 1: //only sub menu point no option

//call the function get_delay() to change the setting

delayTime[room] = get_delay(37, room, delayTime[room]);

Mem_updateInt(pgm_read_byte(&(delayTime_ADDR[room])), delayTime[room]);

return;

case 2: //only sub menu point no option

//call the function get_offon to change setting

ac_master_bypass[room - 10] = get_offon(38, room, ac_master_bypass[room - 10]);

Mem_updateByte(pgm_read_byte(&(ac_master_bypass_ADDR[room - 10])), ac_master_bypass[room - 10]);

return;

case 3: //only sub menu point no option

//call the function get_offon to change setting

timer_active[room][0] = get_offon(10, room, timer_active[room][0]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][0])), timer_active[room][0]);

return;

case 4: //only sub menu point no option

//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;

case 5: //only sub menu point no option

//call the function get_offon() to change the setting

timer_active[room][1] = get_offon(11, room, timer_active[room][1]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][1])), timer_active[room][1]);

return;

case 6: //only sub menu point no option

//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;

case 7: //only sub menu point no option

//call the function get_offon() to change the setting

timer_active[room][2] = get_offon(12, room, timer_active[room][2]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][2])), timer_active[room][2]);

return;

case 8: //only sub menu point no option

//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;

case 9: //only sub menu point no option

//call the function get_offon() to change the setting

timer_active[room][3] = get_offon(25, room, timer_active[room][3]);

Mem_updateByte(pgm_read_byte(&(timer_active_ADDR[room][3])), timer_active[room][3]);

return;

case 10: //only sub menu point no option

//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;

}

}

}

}

Now we move down to the function adj_season(). Here we need to add the update statements for the EEPROM in the adjusting function:

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])))); //save the values

//>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[0][0])), ac_periode[0][0]);

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[0][1])), ac_periode[0][1]);

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[1][0])), ac_periode[1][0]);

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[1][1])), ac_periode[1][1]);

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[2][0])), ac_periode[2][0]);

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[2][1])), ac_periode[2][1]);

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[3][0])), ac_periode[3][0]);

Mem_updateByte(pgm_read_byte(&(ac_periode_ADDR[3][1])), ac_periode[3][1]);

//>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<<<

delay(1000);

return;

}

}

}

}

}

}

}

}

}

The same goes for the function get_setTime(). Even here we need to ad the update statements in to the adjusting function:


byte get_setTime( byte onTimeH, byte onTimeM, byte offTimeH,

byte offTimeM, byte room, byte timer){

byte subButton = 0;

onTimeH = get_Timer(13, onTimeH, 0, 24);

if(onTimeH >= 0 && onTimeH < 24){

onTimeM = get_Timer(14, onTimeM, 0, 60);

if(onTimeM < 60){

offTimeH = get_Timer(15, offTimeH, 0, 24);

if(offTimeH >= 0 && offTimeH < 24){

offTimeM = get_Timer(16, offTimeM, 0, 60);

if(offTimeM < 60){

lcd.clear();

lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[6]))));

lcd.setCursor(0, 1);

if(onTimeH < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0

lcd.print(onTimeH);

lcd.write(pgm_read_byte(&char_table[3])); //print seperator

if(onTimeM < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0

lcd.print(onTimeM);

lcd.setCursor(11, 1);

if(offTimeH < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0

lcd.print(offTimeH);

lcd.write(pgm_read_byte(&char_table[3])); //print seperator

if(offTimeM < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0

lcd.print(offTimeM);

while(subButton != btnSelect){

subButton = read_act_buttons();

if(subButton == btnMenu) return 0;

if(subButton == btnSelect){

lcd.clear();

lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[1]))));

delay(1000);

Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][0])), onTimeH); //<<<<<<<<<<<<<ADD<<<<<<<<<<<<<<

room_timers[room][timer][0] = onTimeH;

Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][1])), onTimeM); //<<<<<<<<<<<<<ADD<<<<<<<<<<<<<

room_timers[room][timer][1] = onTimeM;

Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][2])), offTimeH); //<<<<<<<<<<<<<ADD<<<<<<<<<<<<<<

room_timers[room][timer][2] = offTimeH;

Mem_updateByte(pgm_read_byte(&(room_timers_ADDR[room][timer][3])), offTimeM); //<<<<<<<<<<<<<ADD<<<<<<<<<<<<<

room_timers[room][timer][3] = offTimeM;

return 0;

}

}

}

}

}

}

}

Room Management system – The Menu part 15 – with EEPROM


All variables safe uploaded to the EEPROM? - Good, than we can modify the main program to use the variables from it. While compiling the sketch for the variable upload, you might have noticed how memory consuming the whole thing is. To deal with the heavy impact on RAM usage, we write the arrays containing the addresses for the variables stored in the EEPROM in to the program memory.

Lets start with bringing the address declarations to the main program. In our room management sketch, right under “Declaring the variables”, we start a new section and name it “/////////////EEPROM storage//////////////”. Than we copy all the variables / arrays, holding the eeprom addresses right under the new section:

/////////////////////Declaring the Variables/////////////////

/////////////EEPROM Storage//////////////

int eepromValue = 0;

const byte EEPROM_ID = 0x99;

const int ID_ADDR = 0;

const byte Sensitivity_ADDR = 1; //2 byte value

const byte photoCellCutOff_ADDR = 3; //2 byte value

const byte photoOutsideOff_ADDR = 5; //2 byte value

const int startDelay_ADDR = 374; //1 byte value

const int acSwitchDelay_ADDR = 375; //1 byte value

const int ac_op_mode_ADDR = 376; //1 byte value

const int ac_set_temp_ADDR = 377; //1 byte value

const byte delayTime_ADDR[15] PROGMEM = {7, 9, 11, 13, 15, 17,

19, 21, 23, 25, 27, 29,

31, 33, 35};

const byte timer_active_ADDR[16][4] PROGMEM = {

{37, 38, 39, 40},

{41, 42, 43, 44},

{45, 46, 47, 48},

{49, 50, 51, 52},

{53, 54, 55, 56},

{57, 58, 59, 60},

{61, 62, 63, 64},

{65, 66, 67, 68},

{69, 70, 71, 72},

{73, 74, 75, 76},

{77, 78, 79, 80},

{81, 82, 83, 84},

{85, 86, 87, 88},

{89, 90, 91, 92},

{93, 94, 95, 96},

{97, 98, 99, 100}

};

const int room_timers_ADDR[16][4][4] PROGMEM = {

{

{102, 103, 104, 105},

{106, 107, 108, 109},

{110, 111, 112, 113},

{114, 115, 116, 117}

},

{

{118, 119, 120, 121},

{122, 123, 124, 125},

{126, 127, 128, 129},

{130, 131, 132, 133}

},

{

{134, 135, 136, 137},

{138, 139, 140, 141},

{142, 143, 144, 145},

{146, 147, 148, 149}

},

{

{150, 151, 152, 153},

{154, 155, 156, 157},

{158, 159, 160, 161},

{162, 163, 164, 165}

},

{

{166, 167, 168, 169},

{170, 171, 172, 173},

{174, 175, 176, 177},

{178, 179, 180, 181}

},

{

{182, 183, 184, 185},

{186, 187, 188, 189},

{190, 191, 192, 193},

{194, 195, 196, 197}

},

{

{198, 199, 200, 201},

{202, 203, 204, 205},

{206, 207, 208, 209},

{210, 211, 212, 213}

},

{

{214, 215, 216, 217},

{218, 219, 220, 221},

{222, 223, 224, 225},

{226, 227, 228, 229}

},

{

{230, 231, 232, 233},

{234, 235, 236, 237},

{238, 239, 240, 241},

{242, 243, 244, 245}

},

{

{246, 247, 248, 249},

{250, 251, 252, 253},

{254, 255, 256, 257},

{258, 259, 260, 261}

},

{

{262, 263, 264, 265},

{266, 267, 268, 269},

{270, 271, 272, 273},

{274, 275, 276, 277}

},

{

{278, 279, 280, 281},

{282, 283, 284, 285},

{286, 287, 288, 289},

{290, 291, 292, 293}

},

{

{294, 295, 296, 297},

{298, 299, 300, 301},

{302, 303, 304, 305},

{306, 307, 308, 309}

},

{

{310, 311, 312, 313},

{314, 315, 316, 317},

{318, 319, 320, 321},

{322, 323, 324, 325}

},

{

{326, 327, 328, 329},

{330, 331, 332, 333},

{334, 335, 336, 337},

{338, 339, 340, 341}

},

{

{342, 343, 344, 345},

{346, 347, 348, 349},

{350, 351, 352, 353},

{354, 355, 356, 357}

}

};

const int ac_forced_on_ADDR[4][2] PROGMEM = {

{358, 359},

{360, 361},

{363, 363},

{364, 365}

};

const int ac_periode_ADDR[4][2] PROGMEM = {

{366, 367},

{368, 369},

{370, 371},

{372, 373}

};

const int ac_master_bypass_ADDR[4] PROGMEM = {378, 379, 380, 381};

///////////Timer and Sensitivity Settings to be changed to individual needs////////////////

You might have noticed right away that I have changed something already. To store the addresses into the program memory I added PROGMEM to the array declarations:

const byte delayTime_ADDR[15] = {7, 9,
becomes
const byte delayTime_ADDR[15] PROGMEM = {7, 9,

and

const byte timer_active_ADDR[16][4] = {
becomes
const byte timer_active_ADDR[16][4] PROGMEM = {

As simple is that to store a multidimensional array into the program memory and keep the structure of the originating array. We change all the arrays containing EEPROM addresses like described on the two examples.
Now we have to move down in the declaration part into the menu and user interface section. Right above the last table being saved to the program memory before the setup loop we add a new section “//////////////Error handling/////////////”. And at the last table, where we have already a couple of error messages we add a couple of things.

ac_sub_8,

ac_sub_9

};

////////////////Error Handling/////////////

prog_char error_0[] PROGMEM = "RTC ERR";

prog_char error_1[] PROGMEM = "RTC Read ERR";

//>>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<

prog_char error_2[] PROGMEM = "EEPROM empty!";

prog_char error_3[] PROGMEM = "EEP write error";

//>>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<<<

PROGMEM const char *error_table[] = {

error_0,

error_1,

//>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<

error_2,

error_3

//>>>>>>>>>>>>>Addition ends here<<<<<<<<<<<<<<

};

void setup() {

//////////////Start Serial for Debugging/////////////////////

#ifdef DA_DEBUG_serial

Serial.begin(9600);

#endif

lcd.begin(16, 2);

Now we move down to the setup loop and add:

void setup() {

//////////////Start Serial for Debugging/////////////////////

#ifdef DA_DEBUG_serial

Serial.begin(9600);

#endif

lcd.begin(16, 2);

//>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<<

lcd.clear();

eepromValue = Mem_readByte(ID_ADDR); //check if the eeprom holds valid data

if(eepromValue != EEPROM_ID){

get_error(2, 0); //if not, display an error

delay(5000);

//load default var values //work with default variables declared

//in the declaration section above

}

else{ //read the values from the eeprom

sensitivity = Mem_readInt(Sensitivity_ADDR); //sensitivity

photoCellCutOff = Mem_readInt(photoCellCutOff_ADDR); //photocell cut off value for rooms

photoOutsideOff = Mem_readInt(photoOutsideOff_ADDR); //photocell cut off value for outside

for(int i=0; i<15; i++){ //PIR and AC cut off delay times

delayTime[i] = Mem_readInt(pgm_read_byte(&(delayTime_ADDR[i])));

}

for(int x=0; x<16; x++){ //holiday lighting and ac timers active settings

for(int y=0; y<4; y++){

timer_active[x][y] = Mem_readByte(pgm_read_byte(&(timer_active_ADDR[x][y])));

}

}

for(int x=0; x<16; x++){ //holiday lighting and ac timer settings

for(int y=0; y<4; y++){

for(int z=0; z<4; z++){

room_timers[x][y][z] = Mem_readByte(pgm_read_byte(&(room_timers_ADDR[x][y][z])));

}

}

}

for(int x=0; x<4; x++){ //ac forced on setting

for(int y=0; y<2; y++){

ac_forced_on[x][y] = Mem_readByte(pgm_read_byte(&(ac_forced_on_ADDR[x][y])));

}

}

for(int x=0; x<4; x++){ //seasonal settings for ac use

for(int y=0; y<2; y++){

ac_periode[x][y] = Mem_readByte(pgm_read_byte(&(ac_periode_ADDR[x][y])));

}

}

startDelay = Mem_readByte(startDelay_ADDR); //ac start delay (compressor protection

acSwitchDelay = Mem_readByte(acSwitchDelay_ADDR); //ac switch time for op mode 3

ac_op_mode = Mem_readByte(ac_op_mode_ADDR); //ac mode

ac_set_temp = Mem_readByte(ac_set_temp_ADDR); //ac temperature setting

for(int i=0; i<4; i++){ //ac master bypass

ac_master_bypass[i] = Mem_readByte(pgm_read_byte(&(ac_master_bypass_ADDR[i])));

}

}

//>>>>>>>>>>>>>ADDITION ends here<<<<<<<<<<<<<

//printing initialisation message

lcd.clear();

lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[4]))));

delay(1000);

lcd.setCursor(0, 1);

lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[3]))));

delay(2000);

//////////////////defining pin modes////////////////////

pinMode(doorMonitor, OUTPUT); //setting the LED pin to output

If you remember from the last post the system to write the values to the eeprom having the same array structure for the values and the address.
To get the right value from the eeprom, we only need to take the corresponding address array with the corresponding counter values and we read back the values. Looking at the delayTime() array, we take the first counter setting of our for loop which would be delayTime[0] and if we look it up from the default declaration part, the first value is 120. Now we overwrite this value with the value we read from the eeprom.


for(int i=0; i<15; i++){ //PIR and AC cut off delay times

delayTime[i] = Mem_readInt(pgm_read_byte(&(delayTime_ADDR[i])));

}


We call the function Mem_readInt(address). Since we have stored all the addresses again in the program memory, we need to retrieve them form there with “pgm_read_byte(&(table_name or array_name)). We stored the arrays in the program memory keeping the whole structure, so the array name is just the same as we declared it and in this example delayTime_ADDR[0], which gives us the address “7”. If we now go back to the sketch we wrote to upload the eeprom values, and check the values for delayTime_ADDR[0] and delayTime[0], we recall what value the default delayTime[0] value will be overwritten with and used by the program. In our case it is 300. It's not difficult. The only thing you have to take care of is that the array counters for the values match with the array counters of the address arrays.

To make it work, we copy the functions we wrote in the upload sketch to the bottom of the Room Management sketch, right on the end of everything.