For time being, I have decided not to
use the EEPROM since it doesn't help freeing RAM or program memory.
In fact it's using up some program memory for reading the stored data
and since the lifetime of the EEPROM is quite restricted to about
100.000 read/write cycles, we still need to store the retrieved data
in a variable being stored in RAM. Let's get everything else working
and worry about storing the timer values in EEPROM later.
While looking through our sketch at
this point, I found another 2 variables which we need to change. Lets
jump into the declaration section, pretty much in the beginning where
we have all the timer and sensitivity settings:
///////////Timer and Sensitivity Settings to be changed to individual needs//////////////// unsigned int sensitivity = 400; //should be between 200 and 1000 as //lower the number as more responsive //the system will be unsigned int photoCellCutOn = 320; //var holding the switching limit for the photocell unsigned int photoCellCutOff = 280; //var holding the value where the photocell cuts off unsigned int photoOutsideOn = 220; //var holding the value which the photocell reading unsigned int photoOutsideOff = 260; //>>>>>>>>>>>>>Change below here<<<<<<<<<<<<< //The following two variables need to be changed from //unsigned int to byte as shown below. byte hourOutsideOff = 23; //var holding the time (full hours) in which the lights have //to switch off byte minuteOutsideOff = 30; //var holding the time (minutes) in which the lights //have to switch off //>>>>>>>>>>>>>Change ends here<<<<<<<<<<<<< int dBed1 = 60; //delay time in seconds for bedroom 1
From here we move down to “defining
Arduino pins”. There we look for
const int lightSensor = A0; //defining the input for the photocell
and change it to
const byte lightSensor = 0; //defining the input for the photocell
OK, in the last post we managed to
change the system time and date. Let's change a few more variables
and implement the first submenu. There fore we move down to the last
part of our selectMenu() function.
if(menuOption == 20){ //if it's menu option 21 lcd.clear(); //clear lcd //print retrieved string on lcd lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(menu_table[19])))); lcd.setCursor(15, 0); //set cursor to row 2 column 1 //print retrieved message string lcd.write(pgm_read_byte(&char_table[0])); } } if(button == btnSelect){ //if the select button is pressed if(menuOption == 1){ //and menu option is 1 adjust_date_time(); //go to adjust date and time return; } // to make the system recognise the changed value we need to pass it back and this we do //simply in adding the variable we change in front of the function call if(menuOption == 2){ //and menu option is 2 //>>>>>>>>add sensitivity = in front of function call get_Timer()<<<<<< sensitivity = get_Timer("Set Sensitivity", sensitivity, 0, 1000); //go to function return; } if(menuOption == 3){ //and menu option is 3 //>>>>>>>>add photoCellCutOff = in front of get_Timer()<<<<<< photoCellCutOff = get_Timer("Set photocell R", photoCellCutOff, 0, 1024); //go to function return; } if(menuOption == 4) return; //and menu option is 4 return (not used) if(menuOption == 5){ //and menu option is 5 //>>>>>>>>add photoOutsideOff = in front of get_Timer()<<<<<< photoOutsideOff = get_Timer("Set photocell O", photoOutsideOff, 0, 1024); //go to function return; } if(menuOption == 6) return; //and menu option is 6 return (not used) } } }
Setting up the rooms we have various
variables to take care of. First we have the delay timer, being
responsible for the time delay to switch off the lights after the
last detection of movement in a room. Second, we have multiple timers
and there activation for the automated light switching while nobody
is home. Since we have a menu point for every room, we handle the
settings for the rooms in a sub menu.
There fore we make a quick d-tour to
the declaration part where we have all the variables for the menu and
user interface, where we store the sub menu points in the program
memory:
///////////////////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 = 20; //available menu options //>>>>>>>>>>>>>addition starts here<<<<<<<<<<<<< //first we need to add 2 variables to count through the sub menu options byte submenu = 0; //var to count current submenu option const byte submenus = 7; //available submenu options //>>>>>>>>>>>>>addition ends here<<<<<<<<<<<<< char buffer_M[20]; //var holding the menu strings retrieved from //the program memory
Now we move down in the same section
just a bit.
//storing the main menu points in the program memory prog_char menu_0[] PROGMEM = "Date/Time"; prog_char menu_1[] PROGMEM = "Sensitivity"; prog_char menu_2[] PROGMEM = "Room photo cut"; prog_char menu_3[] PROGMEM = "Room photo limit"; prog_char menu_4[] PROGMEM = "OS photo cut"; prog_char menu_5[] PROGMEM = "OS photo limit"; prog_char menu_6[] PROGMEM = "Room 1"; prog_char menu_7[] PROGMEM = "Room 2"; prog_char menu_8[] PROGMEM = "Room 3"; prog_char menu_9[] PROGMEM = "Room 4"; prog_char menu_10[] PROGMEM = "Room 5"; prog_char menu_11[] PROGMEM = "Room 6"; prog_char menu_12[] PROGMEM = "Room 7"; prog_char menu_13[] PROGMEM = "Room 8"; prog_char menu_14[] PROGMEM = "Room 9"; prog_char menu_15[] PROGMEM = "Room 10"; prog_char menu_16[] PROGMEM = "AC 1"; prog_char menu_17[] PROGMEM = "AC 2"; prog_char menu_18[] PROGMEM = "AC 3"; prog_char menu_19[] PROGMEM = "AC 4"; PROGMEM const char *menu_table[] = { menu_0, menu_1, menu_2, menu_3, menu_4, menu_5, menu_6, menu_7, menu_8, menu_9, menu_10, menu_11, menu_12, menu_13, menu_14, menu_15, menu_16, menu_17, menu_18, menu_19 }; //>>>>>>>>>>>>>Addition starts here<<<<<<<<<<<<< //storing the sub menu points in the program memory prog_char submenu_0[] PROGMEM = "PIR delay R"; prog_char submenu_1[] PROGMEM = "HT1 Active R"; prog_char submenu_2[] PROGMEM = "Timer 1 R"; prog_char submenu_3[] PROGMEM = "HT2 Active R"; prog_char submenu_4[] PROGMEM = "Timer 2 R"; prog_char submenu_5[] PROGMEM = "HT3 Active R"; prog_char submenu_6[] PROGMEM = "Timer 3 R"; PROGMEM const char *submenu_table[] = { submenu_0, submenu_1, submenu_2, submenu_3, submenu_4, submenu_5, submenu-6 }; //>>>>>>>>>>>>>addition ends here<<<<<<<<<<<<< void setup() { //////////////Start Serial for Debugging///////////////////// //Serial.begin(9600); //printing initialisation message
Nothing new here. As we have done
before, we store the strings in the program memory and set up a table
to retrieve the stored data at a later point. Let's move on to the
more interesting part, putting it in the main menu. First we go to
the beginning of the selectMenu() function and add a sub button
variable.
void selectMenu(){ //Serial.println("SelectMenu"); byte button = 0; //var holding the button value //>>>>>>>>>>>>>addition starts here<<<<<<<<<<<<< byte subButton = 0; //var holding the subButton value //>>>>>>>>>>>>>addition ends here<<<<<<<<<<<<< menuOption = 1; //current menu option lcd.clear(); //clear screen //print the retrieved string on lcd lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(menu_table[0]))));
We stay inside the selectMenu()
function but we move down to the end where we add the actual sub
menu structure:
if(menuOption == 5){ //and menu option is 5 photoOutsideOff = get_Timer("Set photocell O", photoOutsideOff, 0, 1024); //go to function return; } if(menuOption == 6) return; //and menu option is 6 return (not used) //////////////////////////////////////////////////////////////////////////////////// //>>>>>>>>>>>>>Addition starts here<<<<<<<<<<<<< //////////////////////////////////////////////////////////////////////////////////// if(menuOption == 7){ //and menu option is 7 (room 1) subButton = 0; //resetting the button var submenu = 1; //submenu counter lcd.clear(); //clear screen //retrieving and printing first sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[0])))); lcd.print("1"); //printing assigned room number while(submenu < submenus){ //loop through the sub menu points subButton = read_act_buttons(); //checking for pressed buttons if(subButton == btnMenu){ //if button Menu was pressed submenu++; //add 1 - move to the next sub menu point if(submenu == 2){ //if we are at sub menu 2 lcd.clear(); //retrieve and print second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[1])))); lcd.print("1"); //printing assigned room number } if(submenu == 3){ //if we are at sub menu 3 lcd.clear(); //retrieve and print second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[2])))); lcd.print("1"); //printing assigned room number } if(submenu == 4){ //if we are at sub menu 4 lcd.clear(); //retrieve and print second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[3])))); lcd.print("1"); //printing assigned room number } if(submenu == 5){ //if we are at sub menu 5 lcd.clear(); //retrieve and print second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[4])))); lcd.print("1"); //printing assigned room number } if(submenu == 6){ //if we are at sub menu 6 lcd.clear(); //retrieve and print second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[5])))); lcd.print("1"); //printing assigned room number } if(submenu == 7){ //if we are at sub menu 7 lcd.clear(); //retrieve and print second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[6])))); lcd.print("1"); //printing assigned room number } } } } //submenu end ////////////////////////////////////////////////////////////////////////////////// //>>>>>>>>>>>>>addition ends here<<<<<<<<<<<<< ////////////////////////////////////////////////////////////////////////////////// } } }
What happens here? If we are at the
main menu point 7 (room 1) and press select it brings us not as
before to the point where we changed the values. Now we just enter
another menu with the same structure as the main menu with just
different options. We set the sub menu button to 0 and wait again for
button input. According to which button is pressed, we move through
the sub menu or go to the point where we change a value if the button
“select” is pressed.
Let's move on and add the part where we
change the values if the button select is pressed. We start again,
where we just left off.
if(submenu == 7){ //if we are at sub menu 7 lcd.clear(); //retrieve and print second sub menu point lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(submenu_table[6])))); lcd.print("1"); //printing assigned room number } } ////////////////////////////////////////////////////////////////////////////////// //>>>>>>>>>>>>>addition starts here<<<<<<<<<<<<< ////////////////////////////////////////////////////////////////////////////////// if(subButton == btnSelect){ //if we pressed btnSelect if(submenu == 1){ //and submenu is 1 //call the function get_delay() to change the setting delayTime[0] = get_delay("R1 PIR Delay", dBed1); return; } if(submenu == 2){ //and sub menu is 2 //call the function get_offon to change the setting room1MActive = get_offon("R1 T1 On/Off", room1MActive); return; } if(submenu == 3){ //and submenu is 3 //call the function get_setTime() to change timer 1 get_setTime("R1 T1 On/Off", room1OnM[0], room1OnM[1], room1OffM[0], room1OffM[1], room1SubMenu); return; } if(submenu == 4){ //and submenu is 4 //call the function get_offon() to change the setting room101Active = get_offon("R1 T2 On Off", room101Active); return; } if(submenu == 5){ //and submenu is 5 //call the function get_setTime() to change timer 2 get_setTime("R1 T2 On/Off", room1On1[0], room1On1[1], room1Off1[0], room1Off1[1], room1SubMenu); return; } if(submenu == 6){ //and submenu is 6 //call the function get_offon() to change the setting room102Active = get_offon("R1 T3 On Off", room102Active); return; } if(submenu == 7){ //and submenu == 7 //call function get_setTime() to change timer 3 get_setTime("R1 T3 On/Off", room1On2[0], room1On2[1], room1Off2[0], room1Off2[1], room1SubMenu); return; } } ///////////////////////////////////////////////////////////////////////////////// //>>>>>>>>>>>>>addition ends here<<<<<<<<<<<<< ///////////////////////////////////////////////////////////////////////////////// } } //submenu end } } }
The structure and how it works is the
same principal as what I have done in the main menu. To have a
working sketch again, we need to have a quick look at 3 new functions
to change the values. Since this are values which might be changed
more often, we add them straight after the selectMenu() function. The
first one to look at is the function get_delay(). Here we pass the
changed value back into a array and not in a variable. That's why the
variable we declare in the beginning of the sketch is packed into a
array and the program is working with the array better then with
single variables. Let's got to the end of the selectMenu() function
and have a closer look at get_delay().
//function to adjust the pir delay time int get_delay(char delayText[], int reading){ byte subButton = 0; //resetting the button value byte value = raeding / 60; //converting to Minutes lcd.clear(); //clear screen lcd.print(delayText); //print passed message lcd.setCursor(0, 1); //set cursor to second row, first column if(value < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(value); //print the passed value in minutes lcd.setCursor(4, 1); //set cursor to second row, column 4 lcd.print("Min"); //just print Min. while(subButton != btnSelect){ //wait for select btn subButton = read_act_buttons(); //check if a button was pressed if(subButton == btnSearch){ //if btnSearch was pressed if(value > 0 && value < 30){ //we are within allowed range value++; //add 1 to value while btnSearch is pressed } if(value >= 30) value = 1; //if reaches upper limit set to lower limit lcd.setCursor(0, 1); //setting the cursor if(value < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(value); //printing the updated value } } return value*60; }
The way we work the adjustment is
nothing new. We enter the function with passing a informative message
to be printed on LCD and the variable we want to change. In this case
we do not need to pass minimum and maximum value, since this function
is only be used for the delay timers and a maximum adjustable range
of 30 minutes is more than sufficient. If you need a larger range,
just change the 30 in the following two statement to whatever maximum
range you need.
if(value > 0 && value < 30){ //we are within allowed range value++; //add 1 to value while btnSearch is pressed } if(value >= 30) value = 1; //if reaches upper limit set to lower limit
The statement “byte value = reading
/ 60; //converting to Minutes” needs the division by 60 to convert
the seconds we are working with in the program to minutes, to make it
easier to adjust for the user. Also, in the end we need to reconvert
to seconds in which the value is stored ( return value*60;).
The next function we have is
get_offon(). We can build this one again right at the end of the
selectMenu() function.
//function to set a timer active / inactive byte get_offon(char offonText[], byte reading){ byte subButton = 0; //resetting button value lcd.clear(); //clear screen lcd.print(offonText); //print passed info text lcd.setCursor(0, 1); //set cursor to second row column 1 if(reading != 1) lcd.print("Off "); //if value is not 1 timer is off //print off if(reading == 1) lcd.print("Active"); //if timer is 1, timer is active //print active while(subButton != btnSelect){ //waiting for btnSelect to be pressed subButton = read_act_buttons(); //checking for pressed buttons if(subButton == btnSearch){ //if btnSearch is pressed if(reading == 1) reading = 0; //set to 0 if 1 else if(reading == 0) reading = 1; //set to 1 if 0 } lcd.setCursor(0, 1); //set cursor to first column, second row if(reading != 1) lcd.print("Off "); //print off if not set to 1 if(reading == 1) lcd.print("Active"); //print Active if set to 1 } return reading; }
The on off function is pretty straight
forward and I think everything is pretty clear just going through the
comments in the function it self. The only thing which might need a
little attention is the addition of 3 blanks after the word “Off”.
Not to rebuild the whole screen after putting in a lcd.clear(), we
just overwrite Off and Active. Again, the lcd does not replace not
used spaces with blanks. If you overwrite Active with Off it will
read Offive on the LCD. Here we need the 3 blanks again to get rid of
the left overs from Active.
Now the last function for today
get_setTime(), which again, we just build at the end of the
selectMenu() function:
byte get_setTime(char timeText[], byte onTimeH, byte onTimeM, byte offTimeH, byte offTimeM, byte room){ byte subButton = 0; onTimeH = get_Timer("ADJ Hour On", onTimeH, 0, 23); if(onTimeH >= 0 && onTimeH < 24){ onTimeM = get_Timer("ADJ Minute On", onTimeM, 0, 59); if(onTimeM < 60){ offTimeH = get_Timer("ADJ Hour Off", offTimeH, 0, 23); if(offTimeH >= 0 && offTimeH < 24){ offTimeM = get_Timer("ADJ Minute Off", offTimeM, 0, 59); 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 separator 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 separator 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); if(room == 1){ room1OnM[0] = onTimeH; room1OnM[1] = onTimeM; room1OffM[0] = offTimeH; room1OffM[1] = offTimeM; } return 0; } } } } } } }
The structure reminds us a bit on the
function adjust_date_time(), which is build in the same manner. The
only difference is that we are not really saving the values, we are
just giving them back to their respective places in the originating
arrays.
In the next post, we will do a little
more house keeping and putting it all together.
No comments:
Post a Comment