//настройка времени, даты и дня недели модуля RTC DS1302 #include <LiquidCrystal_I2C.h> //библиотеки работы с LCD через I2C #include <Wire.h> #include <iarduino_RTC.h> //библиотека для работы с модулем RTC DS1302 //Не забудь шунтировать выход от кнопок резистором 10 КОм const byte BtDownPin = 5; //пин кнопки Уменьшить const byte BtUpPin = 6; //пин кнопки Увеличить const byte BtSettingPin = 7; //пин кнопки настроек //Объявляем объект watch для работы с RTC модулем на базе чипа DS1302, //указывая выводы Arduino подключённые к выводам модуля RST, CLK, DAT. iarduino_RTC watch(RTC_DS1302, 2, 3, 4); //пины модуля I2C LCD-дисплея : //SDA - A4 //SCL - A5 //питание от шилда boolean LastButtonSetting = LOW; //предыдущее состояние кнопки boolean CurrentButtonSetting = LOW; //текущее состояние кнопки boolean LastButtonDown = LOW; boolean CurrentButtonDown = LOW; boolean LastButtonUp = LOW; boolean CurrentButtonUp = LOW; boolean FlagSettingLoop = true; //были ли мы в цикле нажатия кнопки Настройки boolean FlagDownLoop = true; //были ли мы в цикле нажатия кнопки Меньше boolean FlagUpLoop = true; //были ли мы в цикле нажатия кнопки Больше //нужна при нажатии и удерживании кнопки ВВЕРХ unsigned long ButtonHoldTimerUp = 0; //нужна при нажатии и удерживании кнопки ВНИЗ unsigned long ButtonHoldTimerDown = 0; //по прошествии этого времени кнопка ВВЕРХ или ВНИЗ //перейдет в режим удержания, мс const long ButtonHoldIncTime = 500; boolean FlagUpHold = true; //были ли мы в цикле удержания кнопки ВВЕРХ boolean FlagDownHold = true; //были ли мы в цикле удержания кнопки ВНИЗ unsigned long currentTime = 0; //нужна, чтобы убрать delay() const long intervalTime = 1000; //интервал опроса датчика в мс boolean FlagSettingIn = false; //находимся ли в настройках int8_t SettingNumber = 0; //пункт меню настройки //Объявляем переменные для настройки времени //D-день, M-месяц, Y-год, h-часы, m-минуты, s-секунды, W-день недели. //int8_t D, M, Y, h, m, s, W; int8_t D = 1; //текущий день месяца 1-31 int8_t M = 1; //текущий месяц 1-12 int8_t Y = 23; //текущий год 0-99 int8_t h = 0; //текущие часы 0-23 int8_t m = 0; //текущие минуты 0-59 int8_t s = 0; //текущие секунды 0-59 int8_t W = 0; //текущий день недели 0-6 LiquidCrystal_I2C lcd(0x27,16,2); //Задаем адрес и размерность дисплея. void setup() //************************************************ { pinMode (BtSettingPin, INPUT); pinMode (BtDownPin, INPUT); pinMode (BtUpPin, INPUT); watch.begin(); //Инициируем работу с модулем RTC. lcd.init(); //инициализация lcd lcd.backlight(); //включаем подсветку lcd.setCursor(0,0); //ставим курсор в начало первой строки lcd.print(" RTC DS1302 "); lcd.setCursor(0,1); //ставим курсор в начало второй строки lcd.print(" SETTING "); delay(2000); } void loop() //*************************************************** { //цикл замера температуры if(millis() - currentTime > intervalTime) //опрос датчика через intervalTime { currentTime = millis(); //****************** Вывод на экран ****************************** if(FlagSettingIn == false) //если мы не в настройках { lcd.setCursor(0,0); //прописываем первую строку lcd.print(" "); lcd.print(watch.gettime("H:i:s")); lcd.print(" "); lcd.setCursor(0,1); //прописываем вторую строку lcd.print(" "); lcd.print(watch.gettime("d.m.y D")); lcd.print(" "); } } //if(millis() - currentTime > intervalTime) //********************* Нажата кнопка Настройки ************************ //при каждом нажатии кнопки Настройки //перескакиваем на следующий параметр в очереди. И так по кругу //считываем состояние кнопки с устраненным дребезгом CurrentButtonSetting = debounce(LastButtonSetting, BtSettingPin); if(CurrentButtonSetting == HIGH) //кнопка нажата { if (FlagSettingLoop == true) //эта переменная нужна для однократного нажатия кнопки, //даже если ее удерживать { FlagSettingLoop = false; FlagSettingIn = true; SettingNumber = SettingNumber + 1; if (SettingNumber > 8) { SettingExit(); //выход из настроек } } } else //кнопка отжата { FlagSettingLoop = true; } //обновляем текущее значение кнопки LastButtonSetting = CurrentButtonSetting; if (FlagSettingIn == true) //если мы в настройках { //******************* Нажата кнопка Увеличить ************************** ButtonPlus(); //функция реакции на нажатие кнопки Увеличить //******************* Нажата кнопка Уменьшить ************************** ButtonMinus(); //функция реакции на нажатие кнопки Уменьшить SettingsOnLCD(SettingNumber); //отображаем строку с настройками } } //void loop() //********************** ФУНКЦИИ ********************************* //*********** Функция отображения настроек на LCD ************* void SettingsOnLCD(int SettingItem) { lcd.setCursor(0,0); switch (SettingItem) { case 1: //настройка часов lcd.print("HourOld "); watch.blinktime(3); lcd.print(watch.gettime("H:i:s")); lcd.setCursor(0,1); lcd.print("HourNew "); lcd.print(ZeroFormat(h)); //если цифра одна, добавляем в начало "0" lcd.print(":"); lcd.print(ZeroFormat(m)); lcd.print(":"); lcd.print(ZeroFormat(s)); lcd.print(" "); break; case 2: //настройка минут lcd.print("Min_Old "); watch.blinktime(2); lcd.print(watch.gettime("H:i:s")); lcd.setCursor(0,1); lcd.print("Min_New "); lcd.print(ZeroFormat(h)); lcd.print(":"); lcd.print(ZeroFormat(m)); lcd.print(":"); lcd.print(ZeroFormat(s)); lcd.print(" "); break; case 3: //настройка секунд lcd.print("Sec_Old "); watch.blinktime(1); lcd.print(watch.gettime("H:i:s")); lcd.setCursor(0,1); lcd.print("Sec_New "); lcd.print(ZeroFormat(h)); lcd.print(":"); lcd.print(ZeroFormat(m)); lcd.print(":"); lcd.print(ZeroFormat(s)); lcd.print(" "); break; case 4: //настройка дня lcd.print("Day_Old "); watch.blinktime(4); lcd.print(watch.gettime("d.m.y")); lcd.setCursor(0,1); lcd.print("Day_New "); lcd.print(ZeroFormat(D)); lcd.print("."); lcd.print(ZeroFormat(M)); lcd.print("."); lcd.print(ZeroFormat(Y)); lcd.print(" "); break; case 5: //настройка месяца lcd.print("Mon_Old "); watch.blinktime(5); lcd.print(watch.gettime("d.m.y")); lcd.setCursor(0,1); lcd.print("Mon_New "); lcd.print(ZeroFormat(D)); lcd.print("."); lcd.print(ZeroFormat(M)); lcd.print("."); lcd.print(ZeroFormat(Y)); lcd.print(" "); break; case 6: //настройка года lcd.print("YearOld "); watch.blinktime(6); lcd.print(watch.gettime("d.m.y")); lcd.setCursor(0,1); lcd.print("YearNew "); lcd.print(ZeroFormat(D)); lcd.print("."); lcd.print(ZeroFormat(M)); lcd.print("."); lcd.print(ZeroFormat(Y)); lcd.print(" "); break; case 7: //настройка дня недели lcd.print("WeekOld "); watch.blinktime(0); watch.gettime(); lcd.print(WeekLongFormat(watch.weekday)); lcd.print(" "); lcd.setCursor(0,1); lcd.print("WeekNew "); lcd.print(WeekLongFormat(W)); lcd.print(" "); break; case 8: //запись настроек в модуль времени lcd.print("Save Time Settin"); lcd.setCursor(0,1); lcd.print("Press UP button "); break; } } //********* Функция кнопки Больше, Увеличить, Плюс и т.п. ************* void ButtonPlus() { CurrentButtonUp = debounce(LastButtonUp, BtUpPin); if(CurrentButtonUp == HIGH) //кнопка нажата { if (SettingNumber >= 1 && SettingNumber <= 6) //пункты настроек, где нужен разгон параметра в режиме удержания { if(FlagUpHold == true) //отсечка времени удержания кнопки { ButtonHoldTimerUp = millis(); FlagUpHold = false; } if(millis() - ButtonHoldTimerUp > ButtonHoldIncTime) //сначала однократное нажатие, но если держать кнопку более //ButtonHoldIncTime, она переходит в режим удержания { ButtonPlusAction(SettingNumber, true); } if(FlagUpLoop == true) //однократное нажатие, даже если удерживать кнопку, //пока не прошло ButtonHoldIncTime { FlagUpLoop = false; ButtonPlusAction(SettingNumber, false); } } else //пункты настроек, где нужно только однократное нажатие кнопки { if(FlagUpLoop == true) { FlagUpLoop = false; ButtonPlusAction(SettingNumber, false); } } } else //кнопка отжата { FlagUpLoop = true; FlagUpHold = true; } LastButtonUp = CurrentButtonUp; //обновляем текущее значение кнопки } //******** Функция изменения параметров при нажатии кнопки Больше ********** void ButtonPlusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //настройка часов h = h + Inc_Val_Calc(IncTrigger); if(h > 23) //верхний порог { h = 23; } break; case 2: //настройка минут m = m + Inc_Val_Calc(IncTrigger); if(m > 59) //верхний порог { m = 59; } break; case 3: //настройка секунд s = s + Inc_Val_Calc(IncTrigger); if(s > 59) //верхний порог { s = 59; } break; case 4: //настройка дня D = D + Inc_Val_Calc(IncTrigger); if(D > 31) //верхний порог { D = 31; } break; case 5: //настройка месяца M = M + Inc_Val_Calc(IncTrigger); if(M > 12) //верхний порог { M = 12; } break; case 6: //настройка года Y = Y + Inc_Val_Calc(IncTrigger); if(Y > 99) //верхний порог { Y = 99; } break; case 7: //настройка дня недели W = W + 1; if(W > 6) //верхний порог { W = 0; } break; case 8: //запись настроек в модуль времени watch.settime(s,m,h,D,M,Y,W); //Записываем время в модуль lcd.setCursor(0,1); lcd.print("Saving... OK "); delay(1500); SettingExit(); break; } } //********* Функция кнопки Меньше, Уменьшить, Минус или т.п. ************* void ButtonMinus() { CurrentButtonDown = debounce(LastButtonDown, BtDownPin); if(CurrentButtonDown == HIGH) //кнопка нажата { if (SettingNumber >= 1 && SettingNumber <= 6) //пункты настроек, где нужен разгон параметра в режиме удержания { if(FlagDownHold == true) //отсечка времени удержания кнопки { ButtonHoldTimerDown = millis(); FlagDownHold = false; } if(millis() - ButtonHoldTimerDown > ButtonHoldIncTime) //сначала однократное нажатие, но если держать кнопку более //ButtonHoldIncTime, она переходит в режим удержания { ButtonMinusAction(SettingNumber, true); } if(FlagDownLoop == true) //однократное нажатие, даже если удерживать кнопку, //пока не прошло ButtonHoldIncTime { FlagDownLoop = false; ButtonMinusAction(SettingNumber, false); } } else //пункты настроек, где нужно только однократное нажатие кнопки { if(FlagDownLoop == true) { FlagDownLoop = false; ButtonMinusAction(SettingNumber, false); } } } else //кнопка отжата { FlagDownLoop = true; FlagDownHold = true; } LastButtonDown = CurrentButtonDown; //обновляем текущее значение кнопки } //******** Функция изменения параметров при нажатии кнопки Меньше ********** void ButtonMinusAction(int SettingItem, boolean IncTrigger) { switch (SettingItem) { case 1: //настройка часов h = h - Inc_Val_Calc(IncTrigger); if(h < 0) //нижний порог { h = 0; } break; case 2: //настройка минут m = m - Inc_Val_Calc(IncTrigger); if(m < 0) //нижний порог { m = 0; } break; case 3: //настройка секунд s = s - Inc_Val_Calc(IncTrigger); if(s < 0) //нижний порог { s = 0; } break; case 4: //настройка дня D = D - Inc_Val_Calc(IncTrigger); if(D < 1) //нижний порог { D = 1; } break; case 5: //настройка месяца M = M - Inc_Val_Calc(IncTrigger); if(M < 1) //нижний порог { M = 1; } break; case 6: //настройка года Y = Y - Inc_Val_Calc(IncTrigger); if(Y < 0) //нижний порог { Y = 0; } break; case 7: //настройка дня недели W = W - 1; if(W < 0) //нижний порог { W = 6; } break; } } //*************** Функция устранения дребезга контактов *********** boolean debounce(boolean last, int ButtonPinDebounce) { boolean current = digitalRead(ButtonPinDebounce); //считываем текущее состояние кнопки if(last != current) //если оно иное, чем предыдущее... { delay(50); //ждем 50 мс current = digitalRead(ButtonPinDebounce); //считываем состояние снова } return current; //возвращаем текущее состояние кнопки } //*************** Функция разгона приращения параметра ************ float Inc_Val_Calc(boolean IncTrigger) { static int count_inc = 0; //счетчик итераций if (IncTrigger == true) //пришел сигнал на разгон { count_inc = count_inc + 1; //играя этими числами, вы можете подстраивать разгон параметра под себя if (count_inc > 0 && count_inc <= 10) { return 1; } if (count_inc > 10 && count_inc <= 20) { return 2; } if (count_inc > 20) { return 3; } } else { count_inc = 0; return 1; //приращение по умолчанию } } //******************* добавляем 0 в начало, если цифра < 10 *************************** String ZeroFormat(int8_t digitIn) { if(digitIn < 10) { return "0" + String(digitIn); } else { return String(digitIn); } } //********** возвращаем полное название дня недели по цифре ********************* String WeekLongFormat(int8_t digitIn) { switch (digitIn) { case 0: return "Sunday"; break; case 1: return "Monday"; break; case 2: return "Tuesday"; break; case 3: return "Wednesday"; break; case 4: return "Thursday"; break; case 5: return "Friday"; break; case 6: return "Saturday"; break; } } //****************** выход из настроек ************************* void SettingExit() { SettingNumber = 0; FlagSettingIn = false; //вышли из режима настройки watch.blinktime(0); //останавливаем мигание }