The menu for the Arduino (Atmega32).
Заинтересовался вопросом : меню для Arduino.На помощь пришел всемогущий Google.На его бескрайних просторах нашелся и источник для вдохновения www.coagula.org .
Структура меню :
Главное меню
|
Меню_1 -------------------------------------------------- Меню_2 ------------------------------------------------------------------ Меню_3
| |
Подменю 1_1 ---- Подменю 1_2 Подменю 2_1 ---- Подменю 2_2 ---- Подменю 2_3
Используется LCD MTC-16204X на контролере HD44780,совместимый с обычным LCD 1602 и поддерживающий кирилицу.
Для навигации по меню используются четыре кнопки.Для удобства мной был изготовлен "самопальный" шилд ,плата которог по-быстрому вырезана малярным ножиком (эх "тряхнул стариной").
Cхема подключений :
Фото собраной схемы :
Скетч.
Библиотека MenuBackend для Arduino IDE 1.0.4 - cкачать .
Первым делом я занялся переводом статьи и скетча с www.coagula.org .Оказалось что для нормальной компиляции и работы скетча необходимо вносить изменения в файл MenuBackend.h.
Добавляются следующие строки в линии 195 MenuBackend.h файла, непосредственно перед строкой "private" :
void toRoot ( ) {
setCurrent ( &getRoot ( ) );
}
Это сделано для того, чтобы иметь возможность легко вернуться c любого подменю в корень меню, нажатием кнопки ESC.
В самом скетче организована програмная реализация "антидребезга" кнопок. Для LCD применяется библиотека LiquidCrystalRus - скачать .
/*
IMPORTANT: to use the menubackend library by Alexander Brevig download it at http://www.arduino.cc/playground/uploads/Profiles/MenuBackend_1-4.zip and add the next code at line 195
void toRoot() {
setCurrent( &getRoot() );
}
*/
#include <MenuBackend.h> //MenuBackend library - copyright by Alexander Brevig
#include <LiquidCrystalRus.h> //this library is included in the Arduino IDE
const int buttonPinLeft = 12; // pin for the Up button
// контакт для кнопки "Вверх"
const int buttonPinRight = 11; // pin for the Down button "вниз"
const int buttonPinEsc = 14; // pin for the Esc button "выход"
const int buttonPinEnter = 15; // pin for the Enter button "вход"
int lastButtonPushed = 0;
int lastButtonEnterState = LOW; // the previous reading from the Enter input pin
int lastButtonEscState = LOW; // the previous reading from the Esc input pin
int lastButtonLeftState = LOW; // the previous reading from the Left input pin
int lastButtonRightState = LOW; // the previous reading from the Right input pin
long lastEnterDebounceTime = 0; // the last time the output pin was toggled
long lastEscDebounceTime = 0; // the last time the output pin was toggled
long lastLeftDebounceTime = 0; // the last time the output pin was toggled
long lastRightDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 500; // the debounce time
// LiquidCrystal display with:
LiquidCrystalRus lcd(9, 6, 5, 4, 3, 2);
//Menu variables
MenuBackend menu = MenuBackend(menuUsed,menuChanged);
//initialize menuitems
//инициализации пунктов меню
MenuItem menu1Item1 = MenuItem("меню_1");
MenuItem menuItem1SubItem1 = MenuItem("подменю1_1");
MenuItem menuItem1SubItem2 = MenuItem("подменю1_2");
MenuItem menu1Item2 = MenuItem("меню_2");
MenuItem menuItem2SubItem1 = MenuItem("подменю2_1");
MenuItem menuItem2SubItem2 = MenuItem("подменю2_2");
MenuItem menuItem3SubItem3 = MenuItem("подменю2_3");
MenuItem menu1Item3 = MenuItem("меню_3");
void setup()
{
pinMode(buttonPinLeft, INPUT);
pinMode(buttonPinRight, INPUT);
pinMode(buttonPinEnter, INPUT);
pinMode(buttonPinEsc, INPUT);
lcd.begin(16, 2);
//configure menu
//настроить меню
menu.getRoot().add(menu1Item1);
menu1Item1.addRight(menu1Item2).addRight(menu1Item3);
menu1Item1.add(menuItem1SubItem1).addRight(menuItem1SubItem2);
menu1Item2.add(menuItem2SubItem1).addRight(menuItem2SubItem2).addRight(menuItem3SubItem3);
menu.toRoot();
lcd.setCursor(0,0);
lcd.print("Меню для Arduino");
} // setup()...
void loop()
{
readButtons(); //I splitted button reading and navigation in two procedures because
//Я разделил чтения и навигации кнопки в двух процедур, поскольку
navigateMenus(); //in some situations I want to use the button for other purpose (eg. to change some settings)
//В некоторых ситуациях я хочу использовать кнопки для других целей (например, для изменения настроек)
} //loop()...
void menuChanged(MenuChangeEvent changed){
MenuItem newMenuItem=changed.to; //get the destination menu
lcd.setCursor(0,1); //set the start position for lcd printing to the second row
if(newMenuItem.getName()==menu.getRoot()){
lcd.print("Главное меню ");
}else if(newMenuItem.getName()=="меню_1"){
lcd.print("меню_1 ");
}else if(newMenuItem.getName()=="подменю1_1"){
lcd.print("подменю1_1 ");
}else if(newMenuItem.getName()=="подменю1_2"){
lcd.print("подменю1_2 ");
}else if(newMenuItem.getName()=="меню_2"){
lcd.print("меню_2 ");
}else if(newMenuItem.getName()=="подменю2_1"){
lcd.print("подменю2_1 ");
}else if(newMenuItem.getName()=="подменю2_2"){
lcd.print("подменю2_2 ");
}else if(newMenuItem.getName()=="подменю2_3"){
lcd.print("подменю2_3 ");
}else if(newMenuItem.getName()=="меню_3"){
lcd.print("меню_3 ");
}
}
void menuUsed(MenuUseEvent used){
lcd.setCursor(0,0);
lcd.print("Вы использовали ");
lcd.setCursor(0,1);
lcd.print(used.item.getName());
delay(3000); //delay to allow message reading - чтобы задержать чтении сообщение
lcd.setCursor(0,0);
lcd.print("Меню для Arduino");
menu.toRoot(); //back to Main
}
void readButtons(){ //read buttons status
int reading;
int buttonEnterState=LOW; // the current reading from the Enter input pin
int buttonEscState=LOW; // the current reading from the input pin
int buttonLeftState=LOW; // the current reading from the input pin
int buttonRightState=LOW; // the current reading from the input pin
//Enter button - кнопка Enter
// read the state of the switch into a local variable:
// читать состояние переключателя в локальную переменную:
reading = digitalRead(buttonPinEnter);
// check to see if you just pressed the enter button
// (i.e. the input went from LOW to HIGH), and you've waited
// long enough since the last press to ignore any noise:
// Проверяем, если вы только что нажал на кнопку ввода
// (Т.е. входные пошел от низкой до высокой), а вы ждали
// Достаточно долго, с момента последней пресс игнорировать любые шумы:
// If the switch changed, due to noise or pressing:
// Если переключатель изменилась, из-за шума или нажатие:
if (reading != lastButtonEnterState) {
// reset the debouncing timer
// Сброс таймера дребезга
lastEnterDebounceTime = millis();
}
if ((millis() - lastEnterDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
// Все, что показания на, он был там дольше
// Чем дребезга задержки, так что принять его в качестве фактического текущего состояния:
buttonEnterState=reading;
lastEnterDebounceTime=millis();
}
// save the reading. Next time through the loop,
// it'll be the lastButtonState:
// Сохранить чтении. В следующий раз через loop,
// Это будет lastButtonState:
lastButtonEnterState = reading;
//Esc button
// read the state of the switch into a local variable:
reading = digitalRead(buttonPinEsc);
// check to see if you just pressed the Down button
// (i.e. the input went from LOW to HIGH), and you've waited
// long enough since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonEscState) {
// reset the debouncing timer
lastEscDebounceTime = millis();
}
if ((millis() - lastEscDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonEscState = reading;
lastEscDebounceTime=millis();
}
// save the reading. Next time through the loop,
// it'll be the lastButtonState:
lastButtonEscState = reading;
//Down button
// read the state of the switch into a local variable:
reading = digitalRead(buttonPinRight);
// check to see if you just pressed the Down button
// (i.e. the input went from LOW to HIGH), and you've waited
// long enough since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonRightState) {
// reset the debouncing timer
lastRightDebounceTime = millis();
}
if ((millis() - lastRightDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonRightState = reading;
lastRightDebounceTime =millis();
}
// save the reading. Next time through the loop,
// it'll be the lastButtonState:
lastButtonRightState = reading;
//Up button
// read the state of the switch into a local variable:
reading = digitalRead(buttonPinLeft);
// check to see if you just pressed the Down button
// (i.e. the input went from LOW to HIGH), and you've waited
// long enough since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonLeftState) {
// reset the debouncing timer
lastLeftDebounceTime = millis();
}
if ((millis() - lastLeftDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonLeftState = reading;
lastLeftDebounceTime=millis();;
}
// save the reading. Next time through the loop,
// it'll be the lastButtonState:
lastButtonLeftState = reading;
//records which button has been pressed
//запись, какая кнопка была нажата
if (buttonEnterState==HIGH){
lastButtonPushed=buttonPinEnter;
}else if(buttonEscState==HIGH){
lastButtonPushed=buttonPinEsc;
}else if(buttonRightState==HIGH){
lastButtonPushed=buttonPinRight;
}else if(buttonLeftState==HIGH){
lastButtonPushed=buttonPinLeft;
}else{
lastButtonPushed=0;
}
}
void navigateMenus() {
MenuItem currentMenu=menu.getCurrent();
switch (lastButtonPushed){
case buttonPinEnter:
if(!(currentMenu.moveDown())){ //if the current menu has a child and has been pressed enter then menu navigate to item below
//Если в текущем меню есть подменю, и была нажата, то введите меню перейдите к пункту ниже
menu.use();
}else{ //otherwise, if menu has no child and has been pressed enter the current menu is used
//Иначе, если меню не имеет подменю и была нажата Enter текущее меню используется
menu.moveDown();
}
break;
case buttonPinEsc:
menu.toRoot(); //back to main - Вернуться на главную
break;
case buttonPinRight:
menu.moveRight();
break;
case buttonPinLeft:
menu.moveLeft();
break;
}
lastButtonPushed=0; //reset the lastButtonPushed variable
//сбросить переменную lastButtonPushed
}