/***************************************************************************************************
Таймер для засвета ФР. Скетч написан ИИ по заказу Cybervad
***************************************************************************************************/
#include <GyverTM1637.h> // Библиотека для работы с дисплеем TM1637
#include <EEPROM.h> // Для сохранения значений таймеров
// Настройка подключения дисплея
#define PIN_CLK 12
#define PIN_DIO 11
GyverTM1637 tm(PIN_CLK, PIN_DIO);
// Настройки кнопок и сигнала
const int pinStart = A0; // Кнопка Старт
const int pinTimer1 = A3; // Выбор Таймера 1
const int pinTimer2 = A2; // Выбор Таймера 2
const int pinTimer3 = A1; // Выбор Таймера 3
const int buzzerPin = A4; // Пин пищалки
// Подключение энкодера
const int encoderPinA = 2; // Фаза А энкодера
const int encoderPinB = 3; // Фаза B энкодера
// Значение таймеров хранится здесь
unsigned long timerValues[] = {5 * 1000, 30 * 60 * 1000}; // Изначально установлены два таймера (5 секунд и 30 минут)
uint8_t currentTimerIndex = 0; // Индекс текущего выбранного таймера
// Вспомогательная структура для энкодера
struct EncoderData {
volatile byte prevState = 0; // Предыдущее состояние энкодера
};
EncoderData edata;
void setup() {
Serial.begin(9600); // Для отладки
// Инициализация дисплея
tm.brightness(2); // Установка яркости дисплея
tm.clear(); // Очистка экрана
// Инициализация кнопок
pinMode(pinStart, INPUT_PULLUP);
pinMode(pinTimer1, INPUT_PULLUP);
pinMode(pinTimer2, INPUT_PULLUP);
pinMode(pinTimer3, INPUT_PULLUP);
// Инициализация энкодера
pinMode(encoderPinA, INPUT_PULLUP);
pinMode(encoderPinB, INPUT_PULLUP);
// Присоединяем прерывание для энкодера
attachInterrupt(digitalPinToInterrupt(encoderPinA), ISR_EncoderA, CHANGE);
attachInterrupt(digitalPinToInterrupt(encoderPinB), ISR_EncoderB, CHANGE);
// Читаем сохраненные значения таймеров из памяти
for(int i = 0; i < sizeof(timerValues)/sizeof(unsigned long); ++i){
unsigned long value = EEPROM.read(i*4 + 0) << 24 |
EEPROM.read(i*4 + 1) << 16 |
EEPROM.read(i*4 + 2) << 8 |
EEPROM.read(i*4 + 3);
if(value > 0 && value <= 30*60*1000){
timerValues[i] = value; // Сохраняем значение, если оно валидное
}
}
Serial.println("Устройство готово!");
}
void loop() {
checkButtons();
delay(10); // Маленькая задержка между циклами
}
// Проверяет состояние кнопок и обрабатывает события
void checkButtons(){
static bool lastStateStart = true;
static bool lastStateTimer1 = true;
static bool lastStateTimer2 = true;
static bool lastStateTimer3 = true;
bool startPressed = !digitalRead(pinStart); // Кнопка старта
bool timer1Pressed = !digitalRead(pinTimer1); // Выбор таймера 1
bool timer2Pressed = !digitalRead(pinTimer2); // Выбор таймера 2
bool timer3Pressed = !digitalRead(pinTimer3); // Выбор таймера 3
if(startPressed != lastStateStart){
if(startPressed){
runSelectedTimer();
}
lastStateStart = startPressed;
}
if(timer1Pressed != lastStateTimer1){
if(timer1Pressed){
selectTimer(0);
}
lastStateTimer1 = timer1Pressed;
}
if(timer2Pressed != lastStateTimer2){
if(timer2Pressed){
selectTimer(1);
}
lastStateTimer2 = timer2Pressed;
}
if(timer3Pressed != lastStateTimer3){
if(timer3Pressed){
selectTimer(2);
}
lastStateTimer3 = timer3Pressed;
}
}
// Запуск текущего выбранного таймера
void runSelectedTimer(){
unsigned long selectedTime = timerValues[currentTimerIndex]; // Берем текущее значение таймера
unsigned long endTime = millis() + selectedTime;
while(millis() < endTime){
updateDisplay(selectedTime - (millis() - (endTime - selectedTime))); // Обновляем экран
delay(100); // Задержка обновления
}
beepSignal(); // Звуковые сигналы по окончании таймера
tm.displayInt(0); // Останавливаемся на значении '0'
Serial.println("Таймер завершил отсчёт.");
}
// Обработка энкодера (фазы A и B)
void ISR_EncoderA() {
byte newState = (digitalRead(encoderPinA) << 1) | digitalRead(encoderPinB);
if(edata.prevState == 0 && newState == 1) {
adjustTimerValue(-1); // Минус шаг (против часовой стрелки)
}
edata.prevState = newState;
}
void ISR_EncoderB() {
byte newState = (digitalRead(encoderPinA) << 1) | digitalRead(encoderPinB);
if(edata.prevState == 0 && newState == 2) {
adjustTimerValue(+1); // Плюс шаг (по часовой стрелке)
}
edata.prevState = newState;
}
// Изменение значения таймера на указанную величину
void adjustTimerValue(int step){
unsigned long newValue = timerValues[currentTimerIndex] + step * 5000; // Шаг 5 секунд
if(newValue >= 5000 && newValue <= 30*60*1000){ // Ограничиваем диапазон
timerValues[currentTimerIndex] = newValue;
saveToEeprom(); // Сохраняем новое значение в память
updateDisplay(timerValues[currentTimerIndex]); // Обновляем дисплей новым значением
Serial.print("Новый таймер: ");
Serial.println((newValue / 1000));
}
}
// Сохраняем новые значения таймеров в энергонезависимую память
void saveToEeprom(){
for(int i=0; i<sizeof(timerValues)/sizeof(unsigned long); i++){
uint32_t val = timerValues[i];
EEPROM.write(i*4 + 0, val >> 24 & 0xFF);
EEPROM.write(i*4 + 1, val >> 16 & 0xFF);
EEPROM.write(i*4 + 2, val >> 8 & 0xFF);
EEPROM.write(i*4 + 3, val & 0xFF);
}
Serial.println("Значения таймеров сохранены в EEPROM.");
}
// Устанавливаем индекс текущего таймера
void selectTimer(uint8_t index){
currentTimerIndex = index % 3;
updateDisplay(timerValues[currentTimerIndex]);
Serial.print("Выбран таймер №");
Serial.println(currentTimerIndex + 1);
}
// Обновление дисплея текущим временем таймера
void updateDisplay(long timeInMs){
int secondsRemaining = timeInMs / 1000;
tm.displayInt(secondsRemaining);
}
// Генерируем тройной звуковой сигнал по окончании таймера
void beepSignal(){
tone(buzzerPin, 1000); // Частота 1000 Гц
delay(200); // Длительность звучания
noTone(buzzerPin); // Пауза
delay(100); // Короткая пауза перед следующим звуком
tone(buzzerPin, 1000); // Повтор звука дважды ещё раз
delay(200);
noTone(buzzerPin);
delay(100);
tone(buzzerPin, 1000); // Третий звук
delay(200);
noTone(buzzerPin);
}