Being so focused on saving memory space
and optimizing the code so everything fits on a Atmega 328 chip or a
Arduino Uno board, I missed something. I just realized, that with the
current code, the priority switches which we are using to stop the
light from coming on in bed room while asleep are working but we have
again the effect, that the light keeps on switching on and off while
the button is pressed for a longer periode of time. But we want the
light only to switch once per button press no matter for how long the
button is pressed.
Let's go down in the declaration part
of the sketch and find the section “/PIR and Room switch related
var's/”
//////////////////////PIR and Room switch related var's///////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////// byte mainOff = 1; //variable for master relay control unsigned int offTime = 0; //var needed to calculate delay for master off byte masterSwitchStateOld = 0; //var holding the previous door switch state byte switchState[25] = {0}; //array holding the state of each switch unsigned long lightOutput[17] = {0}; //array holding a integer which converted to binary //will trigger the relay to switch in our output code byte lightStatus[17] = {0}; //array holding the switch status of each room on/off byte priorityStatus[17] = {0}; //array holding the priority status of each room on/off //>>>>>>>>>>>>>DELETE from here<<<<<<<<<<<<<< byte switchState1Old = 0; //var to check if the priority switch state has changed byte switchState3Old = 0; //var to check if the priority switch state has changed byte switchState5Old = 0; //var to check if the priority switch state has changed byte switchState7Old = 0; //var to check if the priority switch state has changed //>>>>>>>>>>>>>DELETE ends here<<<<<<<<<<<<<< //>>>>>>>>>>>>>ADD the line below<<<<<<<<<<<<<< byte switchStateOld[4] = {0}; //var to check if the priority switch state has changed ////////////////////////////////////////////////////////////////////////////// ///////////////////////////Output/////////////////////////////////////////////
The 4 variables which where checking if
the switchState of the priority switches in the 3 bedrooms and the
living room have changed don't work any more since we have banned
this part of the code into a function and the function is not
handling only 1 room, its handling all four rooms having a priority
switch. Since it's the first four rooms it's easy, we just replace
the the for variables with a 4 spaces containing array. To make it
work we have to go down to our function check_light_P() and where
ever we find a variable called “switchState1Old”, we replace it
with switchStateOld[room]. Below you find the already updated
function:
unsigned long check_light_P(byte pir, byte prio, byte room, unsigned long light){ if(switchState[prio] == 0 && sensorValue <= photoCellCutOff) { //checking if S2 priority off was if(switchState[pir] == 1 && priorityStatus[room] == 0) { //check if the PIR in bed 1 was //activated and no priority was set //Serial.println("We switch in the lights in bedroom 1");//Debug only lightOutput[room] = light; //switching on the lights – binary lightStatus[room] = 1; //setting the light status for bed 1 lightOutput[14] = 16384; //make sure the master relay //stays on lightStatus[14] = 1; //setting the master relay status roomTimer[room] = millis()/1000; //setting the timer } else if(switchState[pir] == 0 && lightStatus[room] == 1) { //the PIR not activated but the //lights are on if(allTimer(roomTimer[room], delayTime[room])){ // check allowed delay time //Serial.println("Time is up switching off the lights"); //Debug only lightOutput[room] = 0; //switching off the lights lightStatus[room] = 0; //resetting the light status roomTimer[room] = 0; //resetting the room timer } } } else if(switchState[prio] == 1 && lightStatus[room] == 1 && switchStateOld[room] != 1) { //if priority is activated and the //lights are on //Serial.println("Priority switch activated switching off the lights"); //Debug only lightOutput[room] = 0; //switching off the lights lightStatus[room] = 0; //resetting the light status roomTimer[room] = 0; //resetting the room timer priorityStatus[room] = 1; //setting the priority status bed 1 } else if(switchState[prio] == 1 && lightStatus[room] == 0 && switchStateOld[room] != 1) { //if priority was activated and the //lights are off //Serial.println("Priority switch deactivated switching on the lights"); //Debug only lightOutput[room] = light; //switching on the lights lightStatus[room] = 1; //setting the light status roomTimer[room] = millis()/1000; //setting the room timer priorityStatus[room] = 0; //setting the priority for bed 1 back //to 0 } switchStateOld[room] = switchState[prio]; //passing on the switch state return lightOutput[room]; }
Here comes a small upgrade. In our lcd
display, in row 0 , where we display the status of the shift
register, displaying 1 or 0 to show if a output is activated or not I
would like to keep a 16 digit display, so I can see straight away
which room should be on or off. Currently we are loosing 1 digit
every time the outside lighting goes off and if we are in the holiday
timer option at some points of the day the display in row 0 isn't
showing anything and that is because binary numbers drop there upper
most digits soon as they turn 0.
The number 4 in a 16 bit binary would
be:
0000000000000100
But the display would only show
100
since all the upper most digits turning
to 0 are dropped.
This we do with help of a little function,
which we place at the end of the main loop. Since we are currently
displaying the output status in the first row and date and time in
the second row of our display but having a bit more information to
show, I made a little routine to change the display in the second row
a little to show date and time in an interval exchanging with
temperature and photocell reading.
We start again in the declaration part
and there we go into the “all the other variables” section.
///////////////////////////all the other variables///////////////////////////// /////////////////////////////////////////////////////////////////////////////// ////Sensor and timer variables byte temperatur1 = 0; //holding temperature for room 1 unsigned long lastRun[4] = {0}; //var to hold var when ac was last running int sensorValue = 0; //holding the indicated sensor value of the photocell byte photocellSwitch = 0; //holding the switch command after //checking sensor readings (0, 1) byte photocellSwitchOld = 0; //switch command from the previous pass byte lightLevel[17] ={0}; //array holding the switch state //checking timer and photocell (0, 1) byte roomLight[15] = {0}; //array holding the switch on command in holiday lighting const unsigned int outputValues[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,32768}; unsigned int roomTimer[17] = {0}; //array holding the time when the PIR was last activated unsigned int currentTime = 0; //var to hold a reference time to calculate the up time //against the preprogrammed delay time unsigned int endTime = 0; //var to hold a temp result to calculate the up time //against the preprogrammed delay time //>>>>>>>>>>>>>ADD the line below<<<<<<<<<<<<<< unsigned int displayTimeSet = millis()/1000; //variable needed for display exchange //////////////////////////////////////////////////////////////////////////////////////// //////////////////////PIR and Room switch related var's/////////////////////////////////
from here we go down into the main loop
in to the section where it says “processing the input”
//////////////////processing the input///////////////////// if(RTC.read(tm)) { //Reading the clock currentHour = tm.Hour; //passing the time into a var currentMinute = tm.Minute; //passing the time into a var currentDay = tm.Wday - 1; //passing Weekday //(Mon - Sun e.g. 1-7) into var currentDoM = tm.Day; //passing day in to var (1-31) currentMonth = tm.Month; //passing month into var (1-12) currentYear = tmYearToCalendar(tm.Year); //passing year to var //>>>>>>>>>>>>>DELETE the part marked<<<<<<<<<<<<<< lcd.setCursor(0, 0); //set the cursor to line 1 pos 1 lcd.print(" "); //print 15 blanks to delete all //prior statements lcd.setCursor(0, 1); //set cursor to row 2 pos 1 lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(weekday_table[currentDay])))); lcd.print(" "); if(currentDoM < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(currentDoM); lcd.write(pgm_read_byte(&char_table[4])); //print dot if(currentMonth < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(currentMonth); lcd.print(" "); if(currentHour < 10) lcd.write(pgm_read_byte(&char_table[2])); //if the hour is less than 10 //we print a 0 to keep 2 digits lcd.print(currentHour); //print current time (hour) lcd.write(pgm_read_byte(&char_table[3])); //print separator if(currentMinute < 10) lcd.write(pgm_read_byte(&char_table[2])); //if the minute is less than //10 print 0 to keep 2 digits lcd.print(currentMinute); //print current time (minutes) //>>>>>>>>>>>>>DELETE ends here<<<<<<<<<<<<< } else { get_error(0, 1); } photocellSwitch = getSensorValue(sensorValue, photoCellCutOff, photoCellCutOn, photocellSwitchOld); photocellSwitchOld = photocellSwitch; //allowing the lights to switch on between 17:00 and 23:00 h if(photocellSwitch == 1 && currentHour >= 17 && currentHour <= 23) { for(int i=0; i<10; i++){ lightLevel[i] = 1; } lightLevel[15] = 1;
There fore we add:
if(RTC.read(tm)) { //Reading the clock currentHour = tm.Hour; //passing the time into a var currentMinute = tm.Minute; //passing the time into a var currentDay = tm.Wday - 1; //passing Weekday //(Mon - Sun e.g. 1-7) into var currentDoM = tm.Day; //passing day in to var (1-31) currentMonth = tm.Month; //passing month into var (1-12) currentYear = tmYearToCalendar(tm.Year); //passing year to var } else { get_error(0, 1); } //>>>>>>>>>>>>>ADDITION starts here<<<<<<<<<<<<< endTime = (millis()/1000) – displayTimeSet; //set time reference if(endTime <= 15) displayDateTime(); //display time for 15 seconds if(endTime > (15) && endTime <= (30)) displayTemp(); //display temp and photocell reading for 15 sec. if(endTime > 30) displayTimeSet = millis()/1000; //reset the timer //>>>>>>>>>>>>>>ADDITION ends here photocellSwitch = getSensorValue(sensorValue, photoCellCutOff, photoCellCutOn, photocellSwitchOld); photocellSwitchOld = photocellSwitch; //allowing the lights to switch on between 17:00 and 23:00 h if(photocellSwitch == 1 && currentHour >= 17 && currentHour <= 23) { for(int i=0; i<10; i++){ lightLevel[i] = 1; } lightLevel[15] = 1; now we go down to the end of the main loop: outputL = 65535; //setting the output //binary 1111111111111111 } lcd.setCursor(0,0); //>>>>>>>>>>>>>REPLACE the line below<<<<<<<<<<<<<< lcd.print(outputL, BIN); //>>>>>>>>>>>>>>>>>>>WITH this line <<<<<<<<<<<<<<<<<<< printBinary16(outputL); #ifdef DA_DEBUG_out Serial.print("Output value: "); Serial.print(outputL); Serial.print(" "); Serial.println(outputL, BIN); #endif digitalWrite(latchPinOut, LOW); //setting the latch pin to low to //be able to send the data shiftOut(dataPinOut, clockPinOut, MSBFIRST, (outputL >> 8)); //sending the date for the //second shift register shiftOut(dataPinOut, clockPinOut, MSBFIRST, outputL); //sending the data for the //first shift register digitalWrite(latchPinOut, HIGH); //setting the latch pin back to //high to finish the data transmission outputL = 0; //setting the var holding the output //number back to 0 delay(sensitivity); //delay to adjust how responsive the //system will react }
Time to build the three functions
needed right at the end of the main loop:
The first function is the one keeping a
16 bit (digit) display. In praxis we can mark above the display what
every digit is for. In our case from right to left it would be
bed room 1
bed room 2
bed room 3
Living
Bath room 1
Bath room 2
Bath room 3
Bath room 4
Kitchen
Corridor
AC bed 1
AC bed 2
AC bed 3
AC bed 4
Master relay
Outside lights
Having it setup this way might help in
a later state trouble shooting since we no if a corresponding relay
should be activated or not. If the corresponding digit indicates a 1
and a light does not come on you got to check if the relay itself is
working and if it does than the problem is some where in the external
part of the system. If the corresponding digit shows 0 while you
jumping in front of the indicating PIR, than you might have to have a
look at the PIR first and if you are sure that the PIR is working you
have a more serious electronic problem.
//function to keep a 16 digit (bit) display void printBinary16(unsigned int iIn) { // 0b1234567812345678 for (unsigned int mask = 0b1000000000000000; mask; mask >>= 1) { //create a bit mask if (mask & iIn) { //add the incoming data lcd.print('1'); //print if active } else { lcd.print('0'); //if empty, still print the 0 } } }
Next is the function to display the
time and date. If you deleted the part of code in the main loop which
was displaying it you are fine. If you have been lazy like I was and
just copied the part into a function, please delete the firs three
lines:
lcd.setCursor(0, 0); //set the cursor to line 1 pos lcd.print(" "); //print 15 blanks to delete all //prior statements
This part was responsible for a unsteady (blinking) first row on the
LCD, which I was looking for to fix it for nearly a week!
//function to display date and time void displayDateTime(){ lcd.setCursor(0, 1); //set cursor to row 2 pos 1 lcd.print(strcpy_P(buffer, (char*)pgm_read_word(&(weekday_table[currentDay])))); lcd.print(" "); if(currentDoM < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(currentDoM); lcd.write(pgm_read_byte(&char_table[4])); //print dot if(currentMonth < 10) lcd.write(pgm_read_byte(&char_table[2])); //print 0 lcd.print(currentMonth); lcd.print(" "); if(currentHour < 10) lcd.write(pgm_read_byte(&char_table[2])); //if the hour is less than 10 //we print a 0 to keep 2 digits lcd.print(currentHour); //print current time (hour) lcd.write(pgm_read_byte(&char_table[3])); //print separator if(currentMinute < 10) lcd.write(pgm_read_byte(&char_table[2])); //if the minute is less than //10 print 0 to keep 2 digits lcd.print(currentMinute); //print current time (minutes) lcd.print(" "); }
The last function is the one printing
the temperature and light reading. The temperature reading we use
direct since it returns the directly the temperature in degrees
Celsius. OK, got the point. I put an option in to change it to
Fahrenheit. The photocell reading is converted to output the value in
lux from 0 (all dark) to 100000 (direct bright sunlight).
//function to display temperature and light reading void displayTemp() { lcd.setCursor(0, 1); //set cursor column 0 row 1 lcd.print("T "); //print T for temperature lcd.print(temperatur1); //print the reading lcd.print(" C"); //print C for Celsius lcd.print(" "); //print a space lcd.print("L "); //print L for light lcd.print(map(sensorValue, 0, 1023, 0, 100000)); //convert the photocell reading to lux if(map(sensorValue, 0, 1023, 0, 100000) < 10000) lcd.print(" "); //print a space if below 10000 lcd.print(" L"); //print L for Lux }
No comments:
Post a Comment