/* Пример использования меню для ввода параметров
* с отображением их текущих значений в пунктах меню
* и сохранением в EEPROM.
* Обработка выбранных пунктов осуществляется в обработчиках.
*/
#include <Wire.h>
#include "LiquidCrystal_I2C_Menu_Btns.h"
LiquidCrystal_I2C_Menu_Btns lcd(0x27, 20, 4);
#include <EEPROM.h>
// Пины, к которым подключены кнопки
#define pinLeft 2
#define pinRight 3
#define pinEnter 4
#define pinBack 5 // Back - необязательная кнопка
#define pinSTART 7 //运行按钮
uint8_t brightness; // Параметры, которые мы будем именять
uint8_t _delay;
uint8_t _R0OP;
uint8_t _R0CL;
uint8_t _R0LOP;//#继电器0三个选项 //开启,关闭,循环次数
uint8_t _R1OP;
uint8_t _R1CL;
uint8_t _R1LOP;//#继电器1三个选项
//宣布用作菜单项键的列表
enum {mkBack, mkRoot, mkSetBrightness, mkSetDelay,
mkR0OP,mkR0CL,mkR0LOP,mkR1OP,mkR1CL,mkR1LOP,
mkDefaults};
//菜单项处理程序原型:
void SetBrightness();
void SetDelay();
void SetDefaults();
void SetR0OP();
void SetR0CL();
void SetR0LOP();
void SetR1OP();
void SetR1CL();
void SetR1LOP();
//菜单描述
//菜单项的结构:{parentkey,key,caption,[handler]}
sMenuItem menu[] = {
//{parentkey,key,caption,[handler]]-菜单项的结构
{mkBack, mkRoot, "Options", NULL},
{mkRoot, mkSetBrightness, NULL, SetBrightness}, // Названия этих пунктов
{mkRoot, mkSetDelay, NULL, SetDelay}, // будут сгенерированы позже
{mkRoot, mkR0OP, NULL, SetR0OP},
{mkRoot, mkR0CL, NULL, SetR0CL},
{mkRoot, mkR0LOP, NULL, SetR0LOP},
{mkRoot, mkR1OP, NULL, SetR1OP},
{mkRoot, mkR1CL, NULL, SetR1CL},
{mkRoot, mkR1LOP, NULL, SetR1LOP},
{mkRoot, mkDefaults, "Defaults", SetDefaults},
{mkRoot, mkBack, "Back", NULL}
};
uint8_t menuLen = sizeof(menu) / sizeof(sMenuItem);
//按项目键搜索项目索引的功能
int getItemIndexByKey(uint8_t key){
for (uint8_t i = 0; i < menuLen; i++)
if (menu[i].key == key)
return i;
return -1;
}
//创建包含参数值的菜单项名称的函数
void updateCaption(uint8_t key, char format[], int value){
// key - 菜单项的键,用于更新堆栈
// format - 具有值的名称模板
// value - 添加到标题中的值
uint8_t index = getItemIndexByKey(key);
char* buf = (char*) malloc(40);
sprintf(buf, format, value);
menu[index].caption = (char*) realloc(menu[index].caption, strlen(buf)+1);
strcpy(menu[index].caption, buf);
free(buf);
}
//明亮菜单项的处理程序
void SetBrightness(){
// Запрашиваем новое значение
brightness = lcd.inputVal<uint8_t>("Input brightness(%)", 0, 100, brightness, 5);
// Сохраняем его в EEPROM
EEPROM.update(0, brightness);
// Обновляем название пункта меню
updateCaption(mkSetBrightness, "Brightness (%d%%)", brightness);
// Далее может распологаться код - реакция на изменение значения Brightness
}
//延时菜单项的处理程序
void SetDelay(){
// Запрашиваем новое значение
_delay = lcd.inputVal<uint8_t>("Input delay(ms)", 0, 20, _delay);
// Сохраняем его в EEPROM
EEPROM.update(1, _delay);
// Обновляем название пункта меню
updateCaption(mkSetDelay, "Delay (%dms)", _delay);
// Далее может распологаться код - реакция на изменение значения Delay
}
void SetR0OP()
{
_R0OP = lcd.inputVal<uint8_t>("Input R0OP(ms)", 0, 100, _R0OP);
EEPROM.update(2, _R0OP);
updateCaption(mkR0OP, "R0OP (%dms)", _R0OP);
}
void SetR0CL()
{
_R0CL = lcd.inputVal<uint8_t>("Input R0CL(ms)", 0, 100, _R0CL);
EEPROM.update(3, _R0CL);
updateCaption(mkR0CL, "R0CL (%d ms)", _R0CL);
}
void SetR0LOP()
{
_R0LOP = lcd.inputVal<uint8_t>("Input R0LOP(num)", 0, 100, _R0LOP);
EEPROM.update(4, _R0LOP);
updateCaption(mkR0LOP, "R0LOP (%d)", _R0LOP);
}
void SetR1OP()
{
_R1OP = lcd.inputVal<uint8_t>("Input R1OP(ms)", 0, 100, _R1OP);
EEPROM.update(5, _R1OP);
updateCaption(mkR1OP, "R1OP (%d ms)", _R1OP);
}
void SetR1CL()
{
_R1CL = lcd.inputVal<uint8_t>("Input R1CL(ms)", 0, 100, _R1CL);
EEPROM.update(6, _R1CL);
updateCaption(mkR1CL, "R1CL (%d ms)", _R1CL);
}
void SetR1LOP()
{
_R1LOP = lcd.inputVal<uint8_t>("Input R1LOP(num)", 0, 100, _R1LOP);
EEPROM.update(7, _R1LOP);
updateCaption(mkR1LOP, "R1LOP (%d)", _R1LOP);
}
// Обработчик для пункта меню Defaults
void SetDefaults(){
brightness = 50;
_delay = 10;
EEPROM.update(0, brightness);
EEPROM.update(1, _delay);
updateCaption(mkSetBrightness, "Brightness (%d%%)", brightness);
updateCaption(mkSetDelay, "Delay (%dms)", _delay);
// Далее может распологаться код - реакция на изменение значений Delay и Brightness
}
//默认菜单项的处理程序
void LCDRepaint(){
lcd.clear();
lcd.printfAt(0, 0, "READY...");
lcd.printAt(0, 1, "Press E for menu");
}
void setup() {
lcd.begin();
lcd.attachButtons(pinLeft, pinRight, pinEnter, pinBack);
pinMode(pinSTART,INPUT_PULLUP);
//从EEPROM读取亮度和延迟值
brightness = EEPROM.read(0);
if (brightness > 100) {
brightness = 50;
EEPROM.write(0, brightness);
}
_delay = EEPROM.read(1);
if(_delay > 20) {
_delay = 10;
EEPROM.write(1, _delay);
}
_R0OP = EEPROM.read(2);
if(_R0OP > 20) {
_R0OP = 10;
EEPROM.write(2, _R0OP);
}
_R0CL = EEPROM.read(3);
if(_R0CL > 20) {
_R0CL = 10;
EEPROM.write(3, _R0CL);
}
_R0LOP = EEPROM.read(4);
if(_R0LOP > 20) {
_R0LOP = 10;
EEPROM.write(4, _R0LOP);
}
_R1OP = EEPROM.read(5);
if(_R1OP > 20) {
_R1OP = 10;
EEPROM.write(5, _R1OP);
}
_R1CL = EEPROM.read(6);
if(_R1CL > 20) {
_R1CL = 10;
EEPROM.write(6, _R1CL);
}
_R1LOP = EEPROM.read(7);
if(_R1LOP > 20) {
_R1LOP = 10;
EEPROM.write(7, _R1LOP);
}
//创建菜单项的名称
updateCaption(mkSetBrightness, "Brightness (%d%%)", brightness);
updateCaption(mkSetDelay, "Delay (%dms)", _delay);
updateCaption(mkR0OP, "R0OP (%d ms)", _R0OP);
updateCaption(mkR0CL, "R0CL (%d ms)", _R0CL);
updateCaption(mkR0LOP, "R0LOP (%d)", _R0LOP);
updateCaption(mkR1OP, "R1OP (%d ms)", _R1OP);
updateCaption(mkR1CL, "R1CL (%d ms)", _R1CL);
updateCaption(mkR1LOP, "R1LOP (%d)", _R1LOP);
LCDRepaint();
}
void loop() {
//创建菜单项的名称
if (lcd.getButtonsState() == eButton) { // При нажатии
lcd.showMenu(menu, menuLen, 1); // показываем меню
LCDRepaint(); // после чего обновляем информацию на дисплее
}
// Далее может располагаться основной функционал программы
if(digitalRead(pinSTART)==HIGH)
{
delay(50);
if(digitalRead(pinSTART)==LOW)
{
digitalWrite(8,HIGH);
delay(100);
digitalWrite(8,LOW);
}
}
}