#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#define TIMERS_AMOUNT 10//кол-во таймеров(хотел сделать, чтобы можно было делать 9+, но впадло)
#define MAX_TIMER_LENGTH 4//максимальная длина времени таймера
#define LED_ACTIVE_TIME 3//время сколько горит диод
#define LED_PIN 13//пин диода
#define DEFAULT_TIMER_VALUE "15"//дефолтное значение, если пользователь не ввел ничего при настройке
#define ROWS 4 // 4 строки
#define COLS 4 // 4 столбца
LiquidCrystal_I2C lcd(0x27, 20, 4); //
//НАСТРОЙКИ КЕЙПАДА
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {11, 10, 9, 8};//пины кейпада
byte colPins[COLS] = {7, 6, 5, 4};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//==========================
//time
byte hour = 0;
byte minute = 0;
byte sec = 0;
byte currentTimeIndex = 0;
byte currentTimer = 0;//индекс выбранного таймера
bool mainScreen = false;//главный экран
bool timeScreen = false;//экран времени
bool timeSetMode = false;//режим настройки реального времени
bool timeSeted = false;//настроено ли реальное время
bool needSetTimers = true;//При первом запуске нужно установить таймеры
bool setTimersMode = false;//При входе в режим установки времени для таймера - true
bool inputTimerValue = false;//После нажатия * в режиме установки времени таймера true
bool LEDActive = false;//Когда таймер сработал, переменная true
String timerValue = "";//Сюда вводится пользователем значение для таймера при настройке
//массивы значений таймеров(по дефолту 0)
unsigned int timers[TIMERS_AMOUNT];//макс значения таймеров(при старте заполняются нулями)
unsigned int timersCounter[TIMERS_AMOUNT];//тут отсчитываем время таймеров
//таймеры
unsigned long timerLED = 0;//таймер для светодиода
unsigned long startTime = 0;//начинаем отсчет таймеров
unsigned long realTime = 0;//записываем значение, с которого начинаем считать время
unsigned long controllerTimer1Sec = 0;//таймер для своих приколов
//упрощенный вывод текста на дисплей
void lprint(byte column, byte row, String text) {
lcd.setCursor(column, row);
lcd.print(text);
}
void setup()
{
//заполняем массивы нулями
for (int i = 0; i < TIMERS_AMOUNT; i++) {
timers[i] = 0;
timersCounter[i] = 0;
}
lcd.init(); // initialize the lcd
lcd.backlight();//подсветка дисплея
Serial.begin(9600);
}
void loop()
{
//если диод горит, то проверяем прошло ли время, указанное в дефайне(в секундах)
if (LEDActive) {
//если время прошло, то вырубаем диод
if (millis() - timerLED >= LED_ACTIVE_TIME * 1000) {
LEDActive = false;
digitalWrite(LED_PIN, 0);
}
}
//1сек таймер(работает постоянно)
if (millis() - startTime >= 1000) {
startTime = millis();
//циклом перебираем таймеры
for (int i = 0; i < TIMERS_AMOUNT; i++) {
/*
если таймер дошел до конца и в массиве максимальных значений для этого таймера не
ноль, значит таймер настроен и можем обновлять его
*/
if (timersCounter[i] == 0 && timers[i] != 0) {
//таймер дошел до конца, соответственно можем включать диод
timersCounter[i] = timers[i]+1;
if (!LEDActive) {
digitalWrite(LED_PIN, 1);
timerLED = millis();
LEDActive = true;
}
}
//если таймер не настроен, то пропускаем итерацию цикла
if (timers[i] == 0)continue;
//если все таки настроен, то минусуем секунду
timersCounter[i] -= 1;
}
//если время установлено пользователем, то считаем время
if(timeSeted){
sec++;
if(sec == 60){
sec = 0;
minute++;
}
if(minute == 60){
minute = 0;
hour++;
}
if(hour == 24){
hour = 0;
}
}
}
//отслеживаем нажатие кнопки на кейпаде
char key_char = keypad.getKey();
//если нажали какую то кнопку на кейпаде
if (key_char) {
//если нажали не цифру
if (key_char == 'A' || key_char == 'B' || key_char == 'C' || key_char == 'D' || key_char == '*' || key_char == '#') {
switch (key_char) {
case 'A':
if(timeScreen){
timeScreen = false;
mainScreen = true;
}
if(mainScreen){
if(!timeSeted){
lprint(0,3,"Time not set.Press #");
}else{
timeScreen = true;
mainScreen = false;
}
}
break;
case 'C':
//если нажали С, то включаем режим настройки таймеров
if (!setTimersMode)/*если переменная false*/ {
lcd.clear();
setTimersMode = true;
}
//если в режиме настройки таймеров нажали С - стираем 1 символ из введенного значения
if (setTimersMode) {//если переменная true
byte length = timerValue.length();
timerValue.remove(length - 1);
lcd.clear();
}
break;
case 'D':
if (setTimersMode) {
/*если в режиме настройки таймеров нажали D, но не ввели ничего,
то записываем в переменную дефолтное значение*/
if (timerValue == "") {
timerValue = DEFAULT_TIMER_VALUE;
}
//записываем в массив переменную введенного значения
timers[currentTimer] = timerValue.toInt();
//дублируем в массив, в котором считаем секунды то же самое значение
timersCounter[currentTimer] = timerValue.toInt();
//очищаем переменную, которая хранит введенное значение
timerValue = "";
setTimersMode = false;
mainScreen = true;
//вырубаем режим первой настройки
if (needSetTimers)needSetTimers = false;
lcd.clear();
}
if(timeSetMode&&timeScreen){
timeSetMode = false;
timeSeted = true;
currentTimeIndex = 0;
lcd.clear();
}
break;
case '*':
//если в режиме настройки нажали *, то ожидаем от пользователя ввод значения для выбранного таймера
if (setTimersMode && !inputTimerValue) inputTimerValue = true;
break;
case '#':
if(setTimersMode || needSetTimers){
break;
}
if(!timeSeted){
mainScreen = false;
timeSetMode = true;
timeScreen = true;
lcd.clear();
}
}
}
//если нажали цифру
else {
//если находимся в режиме настройки таймера и ожидаем от пользователя ввода
if (setTimersMode && inputTimerValue) {
/*
если пользователь пытается ввести значение, длиной больше, чем указано в дефайне
то выводим текст типо дядя нельзя больше
*/
if (timerValue.length() >= MAX_TIMER_LENGTH) {
lprint(0, 3, "Max timer length: " + String(MAX_TIMER_LENGTH));
} else {//дописываем в переменную, которая хранит ввод пользователя нажатую цифру
timerValue += key_char;
}
} else {
/*если не в режиме настройки таймера или в режиме, но не нажали *
то меняем переменную, которая хранит выбранный таймер
*/
lcd.clear();
String key = String(key_char);//функция перевода из символа в строку
byte int_key = key.toInt();//метод перевода из строки в число int
//если находимся в режиме настройки времени
if(timeScreen && timeSetMode){
switch(currentTimeIndex){
case 0:
if(int_key > 2){
hour = 20;
}else hour = int_key*10;
break;
case 1:
if(hour == 20){
if(int_key > 3) hour = 23;
else hour = hour+int_key;
}else hour = hour+int_key;
break;
case 2:
if(int_key > 5) minute=50;
else minute = int_key*10;
break;
case 3:
minute=minute+int_key;
break;
}
currentTimeIndex++;
return 1;
}
currentTimer = int_key;
}
}
}
//закончили проверят нажатие кнопки
if (setTimersMode) {
//если в режиме настройки, то выводим на дисплей выбранный таймер
lprint(0, 0, "Selected timer: " + String(currentTimer));
//если пользователь еще не перешел к вводу значения, то выводим подсказку
if (!inputTimerValue)lprint(0, 1, "Press *");
//если ожидаем ввод пользователя, то так же выводим подсказки
if (inputTimerValue) {
lprint(0, 1, "Input your value: ");
lprint(0, 2, timerValue);
lprint(0, 3, "Press D after input");
}
//останавливаем loop, если находимся в режиме настройки
return 1;
}
//при первом запуске ожидаем настройки любого таймера
if (needSetTimers) {
//выводим подсказки
lprint(0, 0, "No timer is set");
lprint(0, 1, "Press C to set");
//останавливаем цикл, пока не настроим любой таймер
return 1;
}
if(mainScreen){//если настроили таймер и не находимся в режиме настройки,
//то каждую секунду обновляем главный экран
if (millis() - controllerTimer1Sec >= 1000) {
controllerTimer1Sec = millis();
//чистим экран, чтобы лишнее не выводило
lcd.clear();
lprint(0, 0, "Current timer: " + String(currentTimer));
lprint(0, 1, "Time: " + String(timersCounter[currentTimer])+" Max: "+String(timers[currentTimer]));
}
}
if(timeScreen){
//выполняется каждые 1000 милисекунд
if(millis()-controllerTimer1Sec>=1000){
controllerTimer1Sec = millis();
if(timeSetMode){
lprint(0,0,"Set time:");
lprint(0,1,String(hour)+":"+String(minute));
}else{
lcd.clear();
lprint(0,0,"Real time:");
lprint(0,1,"H: "+String(hour)+" M: "+String(minute)+" S: "+String(sec));
}
}
}
}