Translate

Sunday, 4 May 2014

Room Management System – The Menu – part 1


Finally we are at a stage, where we can start building the menu. First we need to add a few more buttons and a switch. To activate the “Setup Mode” I am using Arduino pin DI 12 to a switch and a 10K resistor and the other side of the switch goes to 5 Volt supply.



The next thing to do is building a small button shield. If you have enough space on a breadboard left, you can also use a bread board for the menu buttons. Since I run out of breadboards, I quickly build a 3 button shield.
We need 4 10K resistors, 3 momentary switches, 1 small 3 point female connector and a prototyping- or breadboard. I soldered the switches to a prototyping board, connected on side of the switches together and to the connector, going to Arduino's analogue pin 1. If you have various photocells connected please use the next analogue pin available. The other side of the buttons is connected through a 10 K resistor in serial with the resistor of the next switch going again to the connector and to the 5V supply voltage. If you want to separate the analogue readings more to give it a wider range due to jumping readings you can increase the resistor value. Finally we connect a 10 K resistor from the ground pin to the connection going to the analogue pin as a pull-down resistor.



The next image shows how I implemented it into the existing system:



A quick note on using only three buttons for the menu if it would be easier to use a set of 5. Very simple, since the main program already uses quite a lot of memory, and the menu itself will have a huge impact on memory use itself, we try to use as less memory as any possible.

Let's add the needed variables for the just implemented switches.

Again, we start in our declaration section and why we have been doing so much house keeping, we do a little more. I categorised our variables a bit more since I was having problems finding things again. I just through in the complete declaration part with all the structure changes I made and on the way down I explain the additional variables to go in. We start at the point where it says “do not modify below here”. There we go into the section “defining Arduino pins”. There we add:

const byte setupMode = 12; //Arduino pin for switching to setup mode

Now we go down to the end of the declaration part and start a new section:

///////////////////////////////////////////////////////////////////////////

///////////////////Menu and user interface/////////////////////////////////

///////////////////////////////////////////////////////////////////////////

const byte btnMenu = 1;

const byte btnSearch = 2;

const byte btnSelect = 3;

const byte btnNone = 0;

int act_key_in = 0;

And here again the whole effected declaration part from the point “do not modify below here” until the end of the just added section.

///////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////DO NOT MODIVY BELOW HERE///////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////

////////////////////////////defining Arduino Pins/////////////////////////////

//////////////////////////////////////////////////////////////////////////////

ShiftLCD lcd(9, 11, 10); //initializing the LCD adaptor pins

const byte latchPin = 2; //5latch pin input connected to

//Arduino digital pin 2

const byte clockPin = 3; //6clock pin input connected to

//Arduino digital pin 3

const byte dataPin = 4; //7data pin input connected to

//Arduino digital pin 4

const byte latchPinOut = 5; //2latch pin output shift register

//74HC595 connected to Arduino

//digital pin 5

const byte clockPinOut = 6; //3clock pin output shift register

//74HC595 connected to Arduino

//digital pin 6

const byte dataPinOut = 7; //4data pin output shift register

//74HC595 connected to Arduino

//digital pin 7

const int lightSensor = A0; //defining the input for the photocell

const byte doorMonitor = 8; //Arduino pin for a monitor LED

const byte setupMode = 12; //Arduino pin for switching to setup mode

/////////////////////////////////////////////////////////////////////////////

///////Variables to hold the data for each input shift register//////////////

/////////////////////////////////////////////////////////////////////////////

byte switchVar1 = 0; //data for input shift register 1

byte switchVar2 = 0; //data for input shift register 2

byte switchVar3 = 0; //data for input shift register 3

///////////////////////////////////////////////////////////////////////////////

///////////////////////////all the other variables/////////////////////////////

///////////////////////////////////////////////////////////////////////////////

////Sensor and timer variables

int delayTime[16] = {dBed1, dBed2, dBed3, dLiving, dBath1, dBath2, dBath3,

dBath4, dKitchen, dCorridor, dAC1, dAC2, dAC3, dAC4,

dMaster, 0};

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)

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

unsigned int outsideOnTime = 0; //checking result if the time is within

//on or off time limits

////////////////////////////////////////////////////////////////////////////////////////

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

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

//////////////////////////////////////////////////////////////////////////////

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

//////////////////////////////////////////////////////////////////////////////

unsigned long outputL = 0; //variable holding the output data

//////////////////////////////////////////////////////////////////////////////////////

///////////////////////////Service Switches///////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////

byte maintenancePin = 0; //defining the var for the maintenance switch

byte maintenanceActive = 0; //holding the switch state

/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////RTC and Holiday switch timers///////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////

byte room1Lights = 0; //var to hold the on command for room light

byte room2Lights = 0; //var to hold the on command for room light

byte room3Lights = 0; //var to hold the on command for room light

byte room4Lights = 0; //var to hold the on command for room light

byte room5Lights = 0; //var to hold the on command for room light

byte room6Lights = 0; //var to hold the on command for room light

byte room7Lights = 0; //var to hold the on command for room light

byte room8Lights = 0; //var to hold the on command for room light

byte room9Lights = 0; //var to hold the on command for room light

byte currentHour = 0; //var holding the time (hour 0-23)

byte currentMinute = 0; //var holding the time (minute 0-59)

byte currentDay = 0; //var holding the date (day 1-31)

byte currentDoM = 0; //var holding the weekday (Sun - Sat, 1-7)

byte currentMonth = 0; //var holding the date (month 1-12)

int currentYear = 0; //var holding the year (based on Unix time)

//Array holding the day names to replace the weekday index

prog_char weekday_0[] PROGMEM = "Sun";

prog_char weekday_1[] PROGMEM = "Mon";

prog_char weekday_2[] PROGMEM = "Tue";

prog_char weekday_3[] PROGMEM = "Wed";

prog_char weekday_4[] PROGMEM = "Thu";

prog_char weekday_5[] PROGMEM = "Fri";

prog_char weekday_6[] PROGMEM = "Sat";

PROGMEM const char *weekday_table[] = {

weekday_0,

weekday_1,

weekday_2,

weekday_3,

weekday_4,

weekday_5,

weekday_6

};

char buffer[20];

///////////////////////////////////////////////////////////////////////////

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

The next thing we do is storing some message texts which show on the LCD in the program memory. There for we add to the last addition under the new created section “Menu and user interface”:

char buffer_M[20]; //buffer holding text strings to be displayed on LCD

//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.2.5";

//Creating the table for the stored menu messages

PROGMEM const char *msg_table[] = {

msg_0,

msg_1,

msg_2,

msg_3,

msg_4

};

How this works is explained in the first menu pages I wrote. From here we move down to the Setup loop and replace the lcd print statements:

void setup() {

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

//Serial.begin(9600);

//printing initialisation message

lcd.begin(16, 2);

//the following lcd.print statement to replace with

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

lcd.print("RMU 1.2.4");

delay(1000);

lcd.setCursor(0, 1);

//the following lcd.print statement to be replaced with

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

lcd.print("starting......");

delay(2000);

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

Again, the part we just changed with all the changes made:

void setup() {

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

//Serial.begin(9600);

//printing initialisation message

lcd.begin(16, 2);

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

We move on to the beginning of the main loop and add:

void loop() {

//>>>>>>>>>addition starts right here>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

///////////////////checking the setup switch/////////////////////////

while(digitalRead(setupMode) != 0){ //stay in here if activated

lcd.clear(); //clear display

lcd.print(strcpy_P(buffer_M, (char*)pgm_read_word(&(msg_table[2])))); //print Setup mode

delay(500); //small delay

button_loop(); //function call to monitor menu buttons

}

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

//////////////////////////////////////getting the input//////////////////////////////////////////////////

Here I am using a while loop to make sure, we are monitoring the menu buttons if the switched to setup mode. The buttons are monitored in the function button_loop. To build this little function, we move again to the far end of the sketch and add the function:

//Checking for a pressed menu button

void button_loop(){

//Serial.println("in button loop");

byte button = read_act_buttons(); //function call to read the buttons

if(button == btnMenu){ //if button menu was pressed

lcd.setCursor(0, 1); //temp to check functionality

lcd.print("Menu button"); //temp to check functionality

delay(500); //delay for readability

}

}

Nothing really magic. We do a new function call byte button = read_act_buttons() which converts the analogue reading into a constant assigned to the buttons pressed. If the button menu is pressed, for now we just print on lcd that the menu button is pressed. Later, we will implement here another function showing the main menu.

Above the function we just added, we add the last function for today:


int read_act_buttons(){

act_key_in = analogRead(1); //reading the sensor

//Readings centred at 170 for menu

//203 for search and 252 for select

//Serial.print("Reading: ");

//Serial.println(act_key_in);

if(act_key_in < 160) return btnNone; //most likely result first

//adding a range of +/- 10 to compensate for bouncing

//readings

if(act_key_in > 160 && act_key_in < 180) return btnMenu;

if(act_key_in > 193 && act_key_in < 213) return btnSearch;

if(act_key_in > 242 && act_key_in < 262) return btnSelect;

return btnNone;

}

Even here nothing real magic.

With act_key_in = analogRead(1); we are reading the value measured between supply voltage and the pressed button. In my setup the values returned are 170 for the menu button, 203 for the search button and 252 for the select button. Since analogue reading are never that exact and always changing within a range, we have to take this in account when we select which button was pressed. While watching my readings for a while, I got away with adding +/- 10 to the average reading. That's done
in:
if(act_key_in > 160 && act_key_in < 180) return btnMenu;
so what ever reading is returned between 160 and 180 is recognised as menu button. Same system works for the next to button.

Your reading may vary depending on resistor value and tolerance. Before you write this function, you might just want to uncomment the Serial.begin(9600) and add temporary in the while loop in the beginning of our main loop the following:

int value = analogRead(1);
Serial.println(value);

and check in the serial monitor what readings are returned when you press your buttons and modify the read_act_buttons() function accordingly.

Before we carry on and go into writing the menu, I am preparing again a post with the full sketch with all changes and implementations up to this point.

No comments:

Post a Comment