Часы/Таймер на кухне
- Войдите на сайт для отправки комментариев
Часы\Таймер предназначены для облегчения работы хозяюшки при приготовлении своих вкусных кулинарных шедевров. Вещь на кухне незаменимая и очень удобная. Те кто уже пробовали готовить с применением таймера, уже не представляют как обходиться без него. А так как мне лень тыкать на кнопки для настройки таймера, то обошелся одной крутилкой с кнопкой.
Итак данное устройство умеет:
1. Отображать текущее время (часы, минуты, секунды)
2. Имеет вшитые временные задания (2 мин, 5 мин, 10 мин, 20 мин, 30 мин,
50 мин, 1час, 1ч 20 мин, 1ч 50 мин, 2 часа, 2ч 50 мин)
3. Можно выставить произвольное время таймера в диапазоне (1 мин — 99 час)
4. Ручную корректировку часов реального времени.
5. Пауза в режиме отсчета таймера и прерывание счета.
Прошу по коду сильно не пинать, я все еще учусь.
Файл DS3231.h разместить в одной папке с скетчем.
/***************************************************************** Copyright (C) 2020 Александр *****************************************************************/ #include <LedControl.h> #include <Wire.h> #include "GyverEncoder.h" #include "DS3231.h" /* Now we need a LedControl to work with. ***** These pin numbers will probably not work with your hardware ***** pin 12 is connected to the DIn pin 11 is connected to the CLK pin 10 is connected to CS We have only a single MAX72XX. */ LedControl lc = LedControl(12, 11, 10, 1); #define pin_CLK 3 // Энкодер пин A #define pin_DT 4 // Энкодер пин B #define pin_Btn 5 // Кнопка Encoder enc1(pin_CLK, pin_DT, pin_Btn); #define BUZZER 8 // сюда подключена пищалка volatile boolean Start_timer; // переключатель дисплея boolean screenChange = false; // enum int currentScreen = 0; volatile boolean flag; // флаг секунд volatile boolean flag_null = false; // Флаг для гашения незначащего ноля на часах uint8_t pause; // флаг паузы uint8_t working; // флаг работы long newPosition = 0; // значение энкодера int _sec, _min, _hour; int brightness = 12; // Яркость 15 int DispFlag = 0; int p_ress = 0; enum ScreenID { min2 = 1, min5, min10, min20, min30, min50, h1_00min, h1_20min, h1_50min, h2_00min, h2_50min, COUNT_ITEMS }; //===================== прерывание от sqw =============== /* Для мигания дисплея и отсчета */ void blink() { flag = !flag; } //********************* энкодер кнопка ****************// void isrButton() { if (Start_timer) { if ( !working ) { working = 1; pause = !pause; } else pause = !pause; } } // ============= мигаем экраном ===================== void shimmer () { if (flag) brightness = 2; else brightness = 15; lc.setIntensity(0, brightness); } //============ отображение на дисплее ============== void displey () { // забиваем массив значениями для отпарвки на экран int8_t TimeDisp[6]; TimeDisp[7] = hour / 10; TimeDisp[6] = hour % 10; TimeDisp[4] = minute / 10; TimeDisp[3] = minute % 10; TimeDisp[1] = second / 10; TimeDisp[0] = second % 10; int8_t TimeTime[6]; TimeTime[7] = _hour / 10; // Десятки часов TimeTime[6] = _hour % 10; // Единицы часов TimeTime[4] = _min / 10; // Десятки минут TimeTime[3] = _min % 10; // Единицы минут TimeTime[1] = _sec / 10; // Десятки минут TimeTime[0] = _sec % 10; // Единицы минут // выводим на экран //================= часы ===================== if (!Start_timer) { brightness = 8; lc.setIntensity(0, brightness); if (TimeDisp[7] != 0) { // Если первое значение не 0, то выводим if (flag_null)flag_null = false; // Сбросим флаг нуля lc.setDigit(0, 7, TimeDisp[7], false); // Вывод первой цифры } else { // Иначе гашение незначащего нуля // Гасим один первый раз при смене на 0 if (!flag_null) { flag_null = true; // Выставим флаг нуля lc.clearDisplay(0); // Гашение экрана } } lc.setDigit(0, 6, TimeDisp[6], false); lc.setChar(0, 5, '-', false); lc.setDigit(0, 4, TimeDisp[4], false); lc.setDigit(0, 3, TimeDisp[3], false); lc.setChar(0, 2, '-', false); lc.setDigit(0, 1, TimeDisp[1], false); lc.setDigit(0, 0, TimeDisp[0], false); } //================ таймер ====================== else { if ( _hour != 0 ) { if (TimeTime[7] != 0) { // Если первое значение не 0, то выводим if (flag_null)flag_null = false; lc.setDigit(0, 7, TimeTime[7], false); } else { // Иначе гашение незначащего нуля // Гасим один первый раз при смене на 0 if (!flag_null) { flag_null = true; lc.clearDisplay(0); } } lc.setDigit(0, 6, TimeTime[6], false); lc.setChar(0, 5, '-', false); lc.setDigit(0, 4, TimeTime[4], false); lc.setDigit(0, 3, TimeTime[3], false); lc.setChar(0, 2, '-', false); lc.setDigit(0, 1, TimeTime[1], false); lc.setDigit(0, 0, TimeTime[0], false); } else { if (TimeTime[4] != 0) { // Если первое значение не 0, то выводим if (flag_null)flag_null = false; lc.setDigit(0, 4, TimeTime[4], false); } else { // Иначе гашение незначащего нуля // Гасим один первый раз при смене на 0 if (!flag_null) { flag_null = true; lc.clearDisplay(0); } } lc.setDigit(0, 3, TimeTime[3], false); lc.setChar(0, 2, '-', false); lc.setDigit(0, 1, TimeTime[1], false); lc.setDigit(0, 0, TimeTime[0], false); } shimmer (); // мигаем экраном } } //========== старт таймера ======================== void St_Timer () { if (_hour == 0 && _min == 0 && _sec == 0) stopOut();// если отсчитывать нечего, тогда и не запускаемся if ( pause == 1) { // начинаем отсчет if ( _sec > 0) _sec--; else { _sec = 59; if (_min > 0) _min--; else { _min = 59; if (_hour > 0) _hour--; else _hour = 0; lc.clearDisplay(0); } } if (_hour == 0 && _min == 0 && _sec == 0) displey (), Stop(); } if (enc1.isHolded()) stopOut(); // если была удержана и энк не поворачивался } //---------------------- стоп таймера ----------------------- void Stop () { stopOut(); int i; int y; for (y = 0; y < 5; y++) { for (i = 0; i < 1000; i++) { digitalWrite(BUZZER, HIGH); delayMicroseconds(500); digitalWrite(BUZZER, LOW); delayMicroseconds(500); } delay(500); } } //------------------------------------------------- void stopOut() { enc1.resetStates(); // screenChange = false; currentScreen = 0; working = 0; Start_timer = false; pause = 0; _hour = _min = _sec = 0; } //=========== настройка времени таймера ========================= void setpoint () { do { enc1.tick(); if (enc1.isRight()) newPosition++; // если был поворот if (enc1.isLeft()) newPosition--; if (enc1.isFastR()) newPosition += 10; // если был быстрый поворот направо, увеличиваем на 10 if (enc1.isFastL()) newPosition -= 10; // если был быстрый поворот налево, уменьшаем на 10 _min = _min + newPosition; newPosition = 0; if ( _min > 59 ) { _min = 0; _hour ++; } else if ( _min < 0 ) { _min = 59; _hour --; lc.clearDisplay(0); } if ( _hour > 99 || _hour <= 0 ) _hour = 0; // } displey (); p_ress = enc1.isHold(); // состояние кнопки } while (!p_ress); } //++++++++++++++++++ Настройка времени часов ++++++++++++++++++ void setupTimer() { process_DS3231(); while (!p_ress) { enc1.tick(); if (enc1.isLeft()) { // если влево - минуты newPosition++; if (enc1.isFastL()) newPosition += 5; minute = minute + newPosition; newPosition = 0; if (minute > 59) minute = 0; } if (enc1.isRight()) { // если вправо - часы newPosition++; if (enc1.isFastR()) newPosition += 5; hour = hour + newPosition; newPosition = 0; if (hour > 23) hour = 0; } if (enc1.isClick()) p_ress = 1; displey (); } setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); } //================================================================= void setup() { Serial.begin(115200); Serial.println(""); Wire.begin(); enc1.setType(TYPE2); // тип энкодера setup_DS3231(); pinMode(BUZZER, OUTPUT); delay (50); tone(BUZZER, 1000); // диагностика звука delay(250); noTone(BUZZER); /* The MAX72XX is in power-saving mode on startup, we have to do a wakeup call */ lc.shutdown(0, false); /* Set the brightness to a medium values */ lc.setIntensity(0, brightness); // яркость 15 /* and clear the display */ lc.clearDisplay(0); // очистка дисплея noInterrupts(); attachInterrupt(0, blink, CHANGE); // прерывание от смены секунд interrupts(); // зажимаем кнопку энкодера, включаем питание - //переходим к настройке часов. Кнопкой запись и выход if (!digitalRead(5)) setupTimer(); } //=============================================================== void loop () { enc1.tick(); if (enc1.isClick()) isrButton();// пуск\пауза счета process_DS3231(); displey (); if ( !working ) { if (enc1.isRight()) { // если вправо - настройка времени таймера Start_timer = true; lc.clearDisplay(0); p_ress = 0; _hour = 0; _min = 0; _sec = 0; setpoint (); } if (enc1.isLeft()) { // если влево - выбор предустановленных параметров Start_timer = true; screenChange = true; // флаг, что экран надо перерисовать currentScreen++; // переходим на следующий экран if (currentScreen == COUNT_ITEMS) { currentScreen = min2; } /////// обработчик экранов дисплея if (screenChange) { lc.clearDisplay(0); screenChange = false; switch (currentScreen) { case min2: _hour = 0; _min = 2; _sec = 0; break; case min5: _hour = 0; _min = 5; _sec = 0; break; case min10: _hour = 0; _min = 10; _sec = 0; break; case min20: _hour = 0; _min = 20; _sec = 0; break; case min30: _hour = 0; _min = 30; _sec = 0; break; case min50: _hour = 0; _min = 50; _sec = 0; break; case h1_00min: _hour = 1; _min = 0; _sec = 0; break; case h1_20min: _hour = 1; _min = 20; _sec = 0; break; case h1_50min: _hour = 1; _min = 50; _sec = 0; break; case h2_00min: _hour = 2; _min = 0; _sec = 0; break; case h2_50min: _hour = 2; _min = 50; _sec = 0; break; } } } } if (Start_timer) { if ( flag && DispFlag == 0) { // 1 раз в сек обновляем дисплей в режиме таймера DispFlag ++; St_Timer(); } if ( !flag && DispFlag == 1) { DispFlag = 0; } } // delay(500); }
DS3231.h #ifndef DS3231_h #define DS3231_h #define DS3231_I2C_ADDRESS 0x68 byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; /********************** **** Подпрограммы **** **********************/ /* часы .. */ byte decToBcd(byte val) { return ((val / 10 * 16) + (val % 10)); } byte bcdToDec(byte val) { return ((val / 16 * 10) + (val % 16)); } /* Установка данных в модуль RTC3231 */ void setDateDs3231(byte second, // 0-59 byte minute, // 0-59 byte hour, // 1-23 byte dayOfWeek, // 1-7 byte dayOfMonth, // 1-28/29/30/31 byte month, // 1-12 byte year) // 0-99 { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); Wire.write(decToBcd(dayOfWeek)); Wire.write(decToBcd(dayOfMonth)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.endTransmission(); } /* Получение данных с модуля RTC DS3231 */ void getDateDs3231 ( byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year ) { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } //============================================================== /* Включаем выход SQW, который вроде выключен по умолчанию */ void setINT() { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0x0E); Wire.write(0x0); Wire.endTransmission(); } //=============================================================== void setup_DS3231() { setINT(); // Включаем выход SQW на RTC3231 } void process_DS3231() { // читаем время из модуля getDateDs3231(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); } #endif
А с чем связана такая странная шкала?
Например, между 1 ч и 1 ч 20 мин - 20 минут,
между 1 ч 30 мин и 1 ч 50 мин - 30 минут,
между 1 ч 50 мин и 2 ч - только 10 минут.
Супруга так захотела. Но в прошивке все легко изменить.
У Вас dayOfWeek, dayOfMonth, month, year на табло не выводятся и в скетче не используются. Поэтому достаточно читать и писать в RTC только часы, минуты, сек.
я еще в EEPROM запоминаю последние 16 выдержек с сортировкой по длительности и перезаписью, и по LongPress энкодера перебираю их. За последние 2 года новых выдержек не появлялось, оказалось достаточно тех, что уже записаны. :)
А еще мне нравится библиотека I2C.h https://github.com/DSSCircuits/I2C-Master-Library
Пример
Согласен. Хотел TFT дисплей прилепить с выводом день недели, месяц. Что бы по русски. Но осталось как есть.
Внес исправления по замечаниям Pyotr пост 3