Translate

Sunday, 18 May 2014

Room Management System – Some improvements and bug fixes


First thing a big THANK YOU to Rene who is a great help in optimizing the code.

Currently I am addressing a simpler way of debugging,
a small bug fix in the way we are collecting the data from the CD4021B input shift registers
and removing the possibility of an error in case of RTC read problems.

For debugging purposes, I have plenty of “//Serial.print(value)” statements in the code which is a bit of a pain, finding them all, uncommenting them for debugging and commenting them out again after finishing the debug.
One of the things Rene brought to my attention was to define a debug mode and run it within #ifdef and #endif like:

//#define DEBUG_DA

#ifdef DEBUG_DA

for(int i=0; i<24; i++){

Serial.print(some text );

Serial.print(i);

Serial.print( :);

Serial.println(value[i]);

}

#endif

The code within #ifdef and #endif is ignored by the compiler as long as the corresponding #define is commented out.
That makes debugging a lot easier removing only a couple of “/” in the declaration part of the sketch rather than going through the whole sketch and finding all the needed “Serial.print” statements.

That's what I have done so far:

//#define DEBUG_DA

#ifdef DEBUG_DA

for(int i=0; i<24; i++){

Serial.print(some text );

Serial.print(i);

Serial.print( :);

Serial.println(value[i]);

}

#endif

Next jump is down to the main loop to where it says “do something with the collected data”

and change the following debug block

/////////////do something with the collected Data/////////////////////

//checks for debugging

//Serial.println(); //debug only

//Serial.print("Switch variable 1: "); //debug only

//Serial.println(switchVar1, BIN); //debug only

//Serial.println("-------------------"); //debug only

//Serial.println(); //debug only

//Serial.print("Switch variable 2: "); //debug only

//Serial.println(switchVar2, BIN); //debug only

//Serial.println("-------------------"); //debug only

//Serial.println(); //debug only

//Serial.print("Switch variable 3: "); //debug only

//Serial.println(switchVar3, BIN); //debug only

//Serial.println("-------------------"); //debug only
 
to

/////////////do something with the collected Data/////////////////////

#ifdef DA_DEBUG_in

Serial.println(); //debug only

Serial.print("Switch variable 1: "); //debug only

Serial.println(switchVar1, BIN); //debug only

Serial.println("-------------------"); //debug only

Serial.println(); //debug only

Serial.print("Switch variable 2: "); //debug only

Serial.println(switchVar2, BIN); //debug only

Serial.println("-------------------"); //debug only

Serial.println(); //debug only

Serial.print("Switch variable 3: "); //debug only

Serial.println(switchVar3, BIN); //debug only

Serial.println("-------------------"); //debug only

#endif

and we do the same thing with the debug statements at the end of the part where we go through the single shift register pins and pass the results into the switchState[] array:

//////////////Debug Statements//////////////////////////////////

#ifdef DA_DEBUG_in

for(int c=0; c<22; c++){

Serial.print("Switch state: ");

Serial.print(c);

Serial.print(" / ");

Serial.println(switchState[c]);

delay(500);

}

#endif

//////////////////checking the light status//////////////////////

I also added a revised debug part between the photo cell checks and the Holiday light switching. We go down to the “Holiday lighting” section and add above:

#ifdef DA_DEBUG_photo

Serial.print("Photo cell switch: ");

Serial.println(photocellSwitch);

for(int c=0; c<17; c++){

Serial.print("Light level ");

Serial.print(c);

Serial.print(" :");

Serial.println(lightLevel[c]);

}

#endif

//////////////Holiday lighting/////////////////////////

From here we jump down to the end of the main loop to the “Output” section and change

///////////////////////////Output/////////////////////////////////////////////////

for(int i=0; i<17; i++) { //loop through the light output array

/*Serial.print("Light Output "); //debug only

Serial.print(i); //debug only

Serial.print(": "); //debug only

Serial.println(lightOutput[i]); //debug only

Serial.print("Light status: "); //debug only

Serial.println(lightStatus[i]); //debug only

Serial.print("Room Timer: "); //debug only

Serial.println(roomTimer[i]); //debug only

delay(500);*/

outputL += lightOutput[i]; //adding up the numbers

}

if(maintenancePin == 1) { //if maintenance switch is active

for(int i=1; i>17; i++){ //loop through all circuits

lightStatus[i] = 1; //setting the light status of everything

roomTimer[i] = millis()/1000; //setting all the room timers

}

outputL = 32767; //setting the output

//binary 0111111111111111

}

lcd.setCursor(0,0);

lcd.print(outputL, BIN);

//Serial.print("Output value: ");

//Serial.print(outputL);

//Serial.print(" ");

//Serial.println(outputL, BIN);

digitalWrite(latchPinOut, LOW); 

to

///////////////////////////Output/////////////////////////////////////////////////

for(int i=0; i<17; i++) { //loop through the light output array

#ifdef DA_DEBUG_out

Serial.print("Light Output "); //debug only

Serial.print(i); //debug only

Serial.print(": "); //debug only

Serial.println(lightOutput[i]); //debug only

Serial.print("Light status: "); //debug only

Serial.println(lightStatus[i]); //debug only

Serial.print("Room Timer: "); //debug only

Serial.println(roomTimer[i]); //debug only

delay(100);

#endif

outputL += lightOutput[i]; //adding up the numbers

}

if(maintenancePin == 1) { //if maintenance switch is active

for(int i=1; i>17; i++){ //loop through all circuits

lightStatus[i] = 1; //setting the light status of everything

roomTimer[i] = millis()/1000; //setting all the room timers

}

outputL = 32767; //setting the output

//binary 0111111111111111

}

lcd.setCursor(0,0);

lcd.print(outputL, BIN);

#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

Let's have a look at the little “bug” in the data collection from the input shift register. There fore we go back up to

/////////////do something with the collected Data/////////////////////

//checks for debugging

#ifdef DA_DEBUG_in

Serial.println(); //debug only

Serial.print("Switch variable 1: "); //debug only

Serial.println(switchVar1, BIN); //debug only

Serial.println("-------------------"); //debug only

Serial.println(); //debug only

Serial.print("Switch variable 2: "); //debug only

Serial.println(switchVar2, BIN); //debug only

Serial.println("-------------------"); //debug only

Serial.println(); //debug only

Serial.print("Switch variable 3: "); //debug only

Serial.println(switchVar3, BIN); //debug only

Serial.println("-------------------"); //debug only

#endif

////////////loop through the 8 input pins to check their status////////////

for(int n=0; n<=7; n++){

Here we have a closer look at the for loop:

I am going through the shift registers 8 times even the data is read only once. At this stage we can eleminate the for loop complete.

for(int n=0; n<=7; n++){ //<<<<<<<<<<<<<DELETE<<<<<<<<<<<<

//shift register 1

if(switchVar1 & (1 << 0)) { //checking S1

//Serial.println("Switch 1 was activated."); //debug only

switchState[0] = 1;

}

else {

switchState[0] = 0;

}

if(switchVar1 & (1 << 1)) { //checking S2

//Serial.println("Switch 2 was activated."); //debug only

switchState[1] = 1;

}

else {

switchState[1] = 0;

}

if(switchVar1 & (1 << 2)) { //checking S3

//Serial.println("Switch 3 was activated."); //debug only

switchState[2] = 1;

}

else {

switchState[2] = 0;

}

if(switchVar1 & (1 << 3)) { //checking S4

//Serial.println("Switch 4 was activated."); //debug only

switchState[3] = 1;

}

else {

switchState[3] = 0;

}

if(switchVar1 & (1 << 4)) { //checking S8

//Serial.println("Switch 8 was activated."); //debug only

switchState[7] = 1;

}

else {

switchState[7] = 0;

}

if(switchVar1 & (1 << 5)) { //checking S7

//Serial.println("Switch 7 was activated."); //debug only

switchState[6] = 1;

}

else {

switchState[6] = 0;

}

if(switchVar1 & (1 << 6)) { //checking S6

//Serial.println("Switch 6 was activated."); //debug only

switchState[5] = 1;

}

else {

switchState[5] = 0;

}

if(switchVar1 & (1 << 7)) { //checking S5

//Serial.println("Switch 5 was activated."); //debug only

switchState[4] = 1;

}

else {

switchState[4] = 0;

}

//shift register 2

if(switchVar2 & (1)) { //checking S9

//Serial.println("Switch 9 was activated."); //debug only

switchState[8] = 1;

}

else {

switchState[8] = 0;

}

if(switchVar2 & (1 << 1)) { //checking S10

//Serial.println("Switch 10 was activated."); //debug only

switchState[9] = 1;

}

else {

switchState[9] = 0;

}

if(switchVar2 & (1 << 2)) { //checking S11

//Serial.println("Switch 11 was activated."); //debug only

switchState[10] = 1;

}

else {

switchState[10] = 0;

}

if(switchVar2 & (1 << 3)) { //checking S12

//Serial.println("Switch 12 was activated."); //debug only

switchState[11] = 1;

}

else {

switchState[11] = 0;

}

if(switchVar2 & (1 << 4)) { //checking S16

//Serial.println("Switch 16 was activated."); //debug only

switchState[15] = 1;

}

else {

switchState[15] = 0;

}

if(switchVar2 & (1 << 5)) { //checking S15

//Serial.println("Switch 15 was activated."); //debug only

switchState[14] = 1;

}

else {

switchState[14] = 0;

}

if(switchVar2 & (1 << 6)) { //checking S14

//Serial.println("Switch 14 was activated."); //debug only

switchState[13] = 1;

}

else {

switchState[13] = 0;

}

if(switchVar2 & (1 << 7)) { //checking S13

//Serial.println("Switch 13 was activated."); //debug only

switchState[12] = 1;

}

else {

switchState[12] = 0;

}

//shift register 3

if(switchVar3 & (1)) { //checking S17

//Serial.println("Switch 17 was activated."); //debug only

switchState[16] = 1;

}

else {

switchState[16] = 0;

}

if(switchVar3 & (1 << 1)) { //checking S18

//Serial.println("Switch 18 was activated."); //debug only

switchState[17] = 1;

}

else {

switchState[17] = 0;

}

if(switchVar3 & (1 << 2)) { //checking S19

//Serial.println("Switch 19 was activated."); //debug only

switchState[18] = 1;

}

else {

switchState[18] = 0;

}

if(switchVar3 & (1 << 3)) { //checking S20

//Serial.println("Switch 20 was activated."); //debug only

maintenancePin = 1;

}

else {

maintenancePin = 0;

}

if(switchVar3 & (1 << 4)) { //checking S21

//Serial.println("Switch 20 was activated."); //debug only

switchState[20] = 1;

}

else {

switchState[20] = 0;

}

if(switchVar3 & (1 << 5)) { //checking S22

//Serial.println("Switch 21 was activated."); //debug only

switchState[21] = 1;

}

else {

switchState[21] = 0;

}

if(switchVar3 & (1 << 6)) { //checking S23

//Serial.println("Switch 22 was activated."); //debug only

switchState[22] = 1;

}

else {

switchState[22] = 0;

}

}//<<<<<<<<<<<<<DELETE<<<<<<<<<<<<<

A small explanation why it is sructured like that:

The original plan was to go through the pins like

for(n=0; n<=7; n++){

if(switchVar1 & (1 << n)){

switchState[n] = 1;

}

else {

switchState[n] = 0;

}

if(switchVar2 & (1 << n)){

switchState[n + 8] = 1;

}

else {

switchState[n + 8] = 0;

}

if(switchVar3 & (1 << n)){

switchState[n + 16] = 1;

}

else {

switchState[n + 16] = 0;

}

}

While building a prototype, I run into a problem with the pin layout of the shift register which forced me to cross the tracks on the circuit board. The compromise resulted in the current structure of not having a parallel linearity in the pin count and the count in the switchState[] array which prevents us of using the for loops as planned above. I know, it's a few more lines of code and thinking it through after wards, there would have been another way. But that would have caused of not having a linearity in the output shift register.
May be if I get a couple of more years experience in coding, I might find a way around it (-:.

Now we take care of an issue at the RTC read statement.

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

}

It doesn't seem to be anything wrong with it but what happens when RTC.read fails? Being honest, I would have assumed nothing since the if statement will only be processed if RTC.read does read something. OK, that's the point “read something”.

For now we just move the part below, where we are printing the time and date into the if statement “if(RTC.read(tm))” and print a error message in a corresponding “else” statement in case RTC.read fails. Going through the readings and check if they are within the required range and to check if they make sens (comparing them to the last reading) is a pretty complex error handling routine, which I will take care of soon as the Menu is completed.

The revised part now looks like:

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

//>>>>>>>>>>>>>The part below moved from

//just outside the “if(RTC.read statement) <<<<<<<<<<<<<

lcd.setCursor(0, 0); //set the corsor 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 dott

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 seperator

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)

//>>>>>>>>>>>>>The moved part ends here<<<<<<<<<<<<<

}

//>>>>>>>>>>>>>Added else statement<<<<<<<<<<<<<

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;

}

//allowing the lights to switch on between 00:00 and 08:00 h

else if(photocellSwitch == 1 && currentHour >= 0 && currentHour <= 8){

for(int i=0; i<10; i++){

lightLevel[i] = 1;

}

Now you got me, I sneeked a new function in, get_error(0, 1). Nothing dramatic, at the end of the whole sketch we add:

void get_error(byte msg, byte row){ //function to print error message

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

//print assigned message from the error_table

lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(error_table[msg]))));

}

I know, I am bad today. To store the error messages we want to print in the program memory, we have to go all the way back up into the declaration part to the Menu and user interface section and add just above the setup loop:


//>>>>>>>>>>>>>addition starts here<<<<<<<<<<<<<<

prog_char error_0[] PROGMEM = "RTC ERR";

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

PROGMEM const char *error_table[] = {

error_0,

error_1

};

//>>>>>>>>>>>>>>addition ends here<<<<<<<<<<<<<

void setup() {

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

#ifdef DA_DEBUG_serial

Serial.begin(9600);

#endif

Another discovery I made today. Since I had repeated problems with the lcd display going blank and the whole system resetting it self while I turned on the computer monitor or my mobile rang, I was all over to find out what's going on. First I thought its the display cause the LCD displays are a little fuzzy with noise. I checked it out and had it running on the Arduino board again with a dummy clock program only using the time library and it worked fine without any problems. Finally I dragged it down to an I2C issue. I just added a 3.3k pull up resistor between the RTC's SDA line and VCC and the RTC's SCL line and VCC.

No comments:

Post a Comment