Hello again folks!
Lets talk about buttons...
...no, not that sort of buttons, this kind:
(BitsBox link to the buttons I used in this test project: BitsBox 6x6 tactile switches)
Firstly lets briefly mention button or keypad shields.
"What's a button or keypad shield?"
I'm glad you asked because I'm about to waffle on about it for a while.
A button shield is a device which mounts straight onto an Arduino UNO board, and has a 16x2 LCD and a 5 button keypad built in.
It's a very handy little device, that allows all sorts of functions, like menus for example.
It looks like this:
(Switch Electronics link to keypad shield shown here: Switch Electronics 16x2 keypad shield)
You'll see that it actually has six buttons.
The button on the far right side of the keypad is actually a reset button for the Arduino, so we shall only be concerned with the other five.
They are 'UP', 'DOWN', 'LEFT', 'RIGHT', and the one on the far left is 'SELECT'.
This is all well and good, but what if we wanted to use a different screen for example, say a 20x4 LCD instead?
And what if it just isn't practical to use an Arduino UNO for size reasons?
And furthermore, what if you wanted to put the buttons in a different place, away from the screen?
I wanted answers to these questions, and it turns out that the solution is....
make your own button shield!
Don't panic...it's not as hard as it sounds!
Put simply, a button shield is five buttons which are connected through a resistor array, to a single analogue pin on the Arduino.
(I'll be using a 20x4 LCD screen, which will be connected the way I discussed in the previous chapter.)
As you press a button, the Arduino sees a value between 0 and 1023 on the analogue pin.
We can adjust the resistors so that a specific button has a specific value.
Then it's a matter of assigning a button to a particular resistance value.
In order to emulate the exact button shield function, I used the following values of resistors:
1 X 330 Ω
1 X 620 Ω
1 X 1 KΩ
1 X 2 KΩ
1 X 3.3 KΩ
I connected it using the following circuit:
It should look something like this:
As you can see, it only uses one pin
(the orange wire to analog pin A0 in this case) on the Arduino NANO, which is very handy if you want to keep things minimal.
Now lets connect up the LCD screen, as shown in the previous chapter above:
And there it is, a
'homemade' keypad shield, which uses an Arduino NANO, and can be customised and fitted into any project.
Of course it won't work without a sketch.
So lets talk about that....this is where it might get a little bit complicated, because I'm also going to talk about using the buttons to navigate a menu system.
There are many ways to implement a menu structure in Arduino, and I have spent a considerable amount of time looking for the simplest and easiest to follow.
The template that I was able to find is reasonably simple to understand, as long as you work through it slowly and methodically.
It uses the
'switch-case' system within Arduino, which enables choices to be made depending on inputs.
Here is the template sketch:
C++:
/*+++++++++++++++++++++++++++++++++++++++++++++++++++
Adapted by Gareth Bellamy (2019)
Thanks to Fahmi Ghani for his menu template
+++++++++++++++++++++++++++++++++++++++++++++++++++*/
// LCD Pins: VCC - 5V, GND - GND, SDA - A4, SDL - A5
#include <Wire.h>
#include <LiquidCrystal_I2C.h> //Use I2C library for LCD
LiquidCrystal_I2C lcd(0x27, 20, 4); //Set up 20x4 LCD called 'lcd' - assign to 0x27 address (default)
int keypad_pin = A0; //assign the button pin to A0 on Arduino
int keypad_value = 0;
int keypad_value_old = 0;
char btn_push;
byte mainMenuPage = 1;
byte mainMenuPageOld = 1;
byte mainMenuTotal = 5; //specify how many pages are in the menu - change if more pages required
void setup()
{
Serial.begin(9600); //start the serial monitor
lcd.init(); //Initialise lcd
lcd.backlight(); //turn on backlight
MainMenuDisplay(); //call the function 'MainMenuDisplay'
delay(1000);
}
void loop()
{
btn_push = ReadKeypad(); //read values from buttons
MainMenuBtn(); //call the function 'MainMenuBtn'
if (btn_push == 'S') //enter selected menu
{
WaitBtnRelease();
switch (mainMenuPage)
{ //the following 'cases' are the main menu options - add more 'cases' if more pages added
case 1:
MenuA();
break;
case 2:
MenuB();
break;
case 3:
MenuC();
break;
case 4:
MenuD();
break;
case 5:
MenuE();
break;
}
MainMenuDisplay();
WaitBtnRelease();
}
delay(10);
}
//--------------- main menu button navigation ---------------------
void MainMenuBtn()
{
WaitBtnRelease();
if (btn_push == 'U') //if the up button is pressed...
{
mainMenuPage++; //....then increment the page by 1
if (mainMenuPage > mainMenuTotal)
mainMenuPage = 1;
}
else if (btn_push == 'D') //if the down button is pressed...
{
mainMenuPage--; //...then decrement the page by 1
if (mainMenuPage == 0)
mainMenuPage = mainMenuTotal;
}
if (mainMenuPage != mainMenuPageOld) //only update display when page change
{
MainMenuDisplay();
mainMenuPageOld = mainMenuPage;
}
}
void MainMenuDisplay() //this function calls the main menu options - add more 'cases' when more pages needed
{
lcd.clear();
lcd.setCursor(0, 0);
switch (mainMenuPage)
{
case 1:
lcd.print("1. Menu A");
break;
case 2:
lcd.print("2. Menu B");
break;
case 3:
lcd.print("3. Menu C");
break;
case 4:
lcd.print("4. Menu D");
break;
case 5:
lcd.print("5. Menu E");
break;
}
}
//This is where the individual menu contents are to be actioned
//Add more 'void Menu#()' if you are adding more pages - copy and paste, but change the relevant bits accordingly
void MenuA()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Inside Menu A");
while (ReadKeypad() != 'L') //task is performed and then pressing 'left' takes you back to main menu
{
//Insert Task for Menu A here
}
}
void MenuB()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Inside Menu B");
while (ReadKeypad() != 'L')
{
//Insert Task for Menu B here
}
}
void MenuC()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Inside Menu C");
while (ReadKeypad() != 'L')
{
//Insert Task for Menu C here
}
}
void MenuD()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Inside Menu D");
while (ReadKeypad() != 'L')
{
//Insert Task for Menu D here
}
}
void MenuE()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Inside Menu E");
while (ReadKeypad() != 'L')
{
//Insert Task for Menu E here
}
}
char ReadKeypad() //this function sets up the button values and assigns the directions
{
Serial.println(keypad_value); // if different resistor values - open serial monitor, hold down a button and note the value then adjust values below accordingly
/* Keypad button analog Value
no button pressed 1023
select 741
left 503
down 326
up 142
right 0
*/
keypad_value = analogRead(keypad_pin);
if (keypad_value < 100) //the right button value is 0 - see above
return 'R';
else if (keypad_value < 200) //the up button value is 142
return 'U';
else if (keypad_value < 400) //the down button value is 326
return 'D';
else if (keypad_value < 600) //the left button value is 503
return 'L';
else if (keypad_value < 800) //the select button value 741
return 'S';
else
return 'N';
}
void WaitBtnRelease()
{
while (analogRead(keypad_pin) < 800) {}
}
Of all the menu sketches I found on the internet, this one was by far the easiest to understand....and I like easy!!
It might look daunting, but I've tried to notate it as best I can....I'll be honest, I don't even understand bits of it....but it does work well, and I think it will work nicely for what I have in mind for my project.
It can be expanded to have as many pages as you like, but for this example sketch there are five pages, with each main menu page having a sub menu section, which can be anything you want to do.
For me this will be where I will tell Arduino the individual valve timings and flash delays etc.
If you are following along at home, and have connected your buttons with the resistor values that I have, then this sketch should work straight away.
If, however, you haven't used the exact same values, then resistors that are close will do.
You will need to check the values of each button in the serial monitor, and make the necessary changes in the sketch - I have shown where to do this....it's near the bottom.
Thanks to
Fahmi Ghani for publishing this great menu Template.
His original sketch can be found here:
https://pastebin.com/HKPsWB6z
Here is a link to the demonstration video
(by the original author), showing the menu in action:
View: http://youtu.be/cMqif5ICS5M
I should reiterate that I have adapted his sketch to work with a 20x4 LCD screen, and I have added a fifth menu page, whereas his original will only work with a 16x2 keypad shield, and only has four menu pages.
contd...