#include <dht.h>
dht DHT;
#include <LiquidCrystal_I2C.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 - необязательная кнопка
uint8_t brightness; // Параметры, которые мы будем именять
uint8_t _delay;
char float_str[4];
char line0[5];
byte termometru[8] = //icon for termometer
{
B00100,
B01010,
B01010,
B01010,
B01010,
B11111,
B11111,
B01110
};
byte picatura[8] = //icon for water droplet
{
B00100,
B00100,
B01110,
B01110,
B11111,
B11111,
B11111,
B01110,
};
byte speakerOn[8] = {
B00001,
B00011,
B01111,
B01111,
B01111,
B00011,
B00001,
B00000
} ;
byte speakerOff[8] = {
B00000,
B10001,
B01010,
B00100,
B01010,
B10001,
B00000,
B00000
} ;
byte hetting[8] = {
B11111,
B11111,
B10010,
B01001,
B10010,
B01001,
B10010,
B00000
};
byte culling[8] = {
B00000,
B10011,
B11010,
B00100,
B01011,
B11001,
B00000,
B00000
};
byte rotate[8] = {
B01111,
B01001,
B11101,
B01000,
B00010,
B10111,
B10010,
B11110
};
byte egg[8] = {
B00000,
B01110,
B11111,
B11111,
B11111,
B11111,
B01110,
B00000
};
byte batery[8] = {
B01110,
B11111,
B10001,
B11111,
B10001,
B11111,
B10001,
B11111
};
// Объявим перечисление, используемое в качестве ключа пунктов меню
enum {mkBack, mkRoot, mkSetBrightness, mkSetDelay, mkDefaults};
// Прототипы обработчиков пунктов меню:
void SetBrightness();
void SetDelay();
void SetDefaults();
// Описание меню
// структура пункта меню: {ParentKey, Key, Caption, [Handler]}
sMenuItem menu[] = {
// {ParentKey, Key, Caption, [Handler]} - структура пункта меню
{mkBack, mkRoot, "Options", NULL},
{mkRoot, mkSetBrightness, NULL, SetBrightness}, // Названия этих пунктов
{mkRoot, mkSetDelay, NULL, SetDelay}, // будут сгенерированы позже
{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);
}
// Обработчик для пункта меню Brightness
void SetBrightness(){
// Запрашиваем новое значение
brightness = lcd.inputVal<uint8_t>("Input brightness(%)", 0, 100, brightness, 5);
// Сохраняем его в EEPROM
EEPROM.update(0, brightness);
// Обновляем название пункта меню
updateCaption(mkSetBrightness, "Brightness (%d%%)", brightness);
// Далее может распологаться код - реакция на изменение значения Brightness
}
// Обработчик для пункта меню Delay
void SetDelay(){
// Запрашиваем новое значение
_delay = lcd.inputVal<uint8_t>("Input delay(ms)", 0, 20, _delay);
// Сохраняем его в EEPROM
EEPROM.update(1, _delay);
// Обновляем название пункта меню
updateCaption(mkSetDelay, "Delay (%dms)", _delay);
// Далее может распологаться код - реакция на изменение значения Delay
}
// Обработчик для пункта меню 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.createChar(0, termometru);
lcd.createChar(1, picatura);
lcd.createChar(2, speakerOn);
lcd.createChar(3, batery);
lcd.createChar(4, hetting);
lcd.createChar(5, egg);
lcd.createChar(6, culling);
lcd.createChar(7, rotate);
lcd.clear();
lcd.printfAt(0, 0, "Курка 37.6|68");
lcd.setCursor(0,1);
lcd.write(0);
lcd.printfAt(2, 1, "--.-");
//lcd.print((char)223); //degree sign
lcd.setCursor(8, 1);
lcd.write(5);
lcd.printfAt(10, 1, "--.-");
//lcd.print((char)223); //degree sign
lcd.setCursor(17,1);
lcd.write(6);
lcd.setCursor(19,1);
lcd.write(4);
lcd.setCursor(0,2);
lcd.write(1);
lcd.printfAt(2, 2, "--");
//lcd.print("%"); //degree sign
lcd.setCursor(17,2);
lcd.write(6);
lcd.setCursor(17,0);
lcd.write(3);
lcd.setCursor(18,0);
lcd.write(2);
lcd.printfAt(19,0, "x");
lcd.setCursor(0,3);
lcd.write(7);
lcd.printfAt(2, 3, "01:30");
lcd.printfAt(14, 3, "den %d", 1);
}
void setup() {
pinMode(12, OUTPUT);
lcd.begin();
lcd.attachButtons(pinLeft, pinRight, pinEnter, pinBack);
// Считываем значения brightness и _delay из 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);
}
// Формируем названия пунктов меню
updateCaption(mkSetBrightness, "Brightness (%d%%)", brightness);
updateCaption(mkSetDelay, "Delay (%dms)", _delay);
LCDRepaint();
digitalWrite(12, HIGH);
}
void loop() {
// Для изменения параметров необходимо нажать кнопку enter
if (lcd.getButtonsState() == eButton) { // При нажатии
lcd.showMenu(menu, menuLen, 0); // показываем меню
LCDRepaint(); // после чего обновляем информацию на дисплее
}
int chk = DHT.read22(8);
if(chk == DHTLIB_OK){
dtostrf(DHT.temperature,3,1,float_str);
sprintf(line0, "%-5s", float_str);
lcd.printAt(2,1,line0);
dtostrf(DHT.humidity,2,0,float_str);
sprintf(line0, "%-3s", float_str);
lcd.printAt(2,2,line0);
delay(200);
}
}