#include <LiquidCrystal.h>
#include <GyverTM1637.h>
// номера пинов подключенных устройств
const int RS = 2, EN = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7; // ЖК дисплей LCD1602
const int DISP_CLK = 11, DIO = 12; // семисегментный дисплей ТМ1637
const int LED1 = A0, LED2 = A1; // СИД ошибок
const int CLK = 8, DT = 9, SW = 10; // энкодер
const int BUZZER1 = A2, BUZZER2 = A3; // !!! зуммер, пины при выводе подключать и переключать параллельно!!!
// глобальные переменные и констаты
const int DEFUSE_TIME = 300; // начальное время таймера, сек
const uint32_t TIMER_TICK_INTERVAL = 1000; // интервал тиков таймера, мс
const uint32_t BEEP_TIME = 25; // время писка зуммера
bool timerTick = true; // тик таймера, значение на 1 цикл переводится в true
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7); // инициализация ЖК дисплея LCD1602
GyverTM1637 disp(DISP_CLK, DIO); // инициализация семисегментного дисплея ТМ1637
// массив - символ батарейки
byte batt[8] = {
0b01110,
0b11111,
0b10001,
0b10001,
0b10001,
0b10001,
0b11111,
0b00000,
};
// массив - символ индикатора
byte ind[8] = {
0b00000,
0b01110,
0b11111,
0b11111,
0b11111,
0b01110,
0b00000,
0b00000,
};
void setup() {
// конфигурируем порты на вход
pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SW, INPUT_PULLUP); // Вроде мой энкодер не надо подтягивать, это для эмулятора
// конфигурируем порты на выход
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(BUZZER1, OUTPUT);
pinMode(BUZZER2, OUTPUT);
lcd.createChar(0, batt); // создаем символ батарейки
lcd.createChar(1, ind); // создаем символ индикатора
lcd.begin(16, 2); // стартуем дисплей
// печатаем первую строку
lcd.setCursor(0, 0);
lcd.print("12A49Q ");
lcd.write(byte(1)); // индикатор
lcd.print("CAR ");
lcd.print("2");
lcd.write(byte(0)); // батарейка
lcd.print("AA");
// печатаем вторую строку
lcd.setCursor(0, 1);
lcd.print("Ports: DVID PS/2");
// конфигурируем сегментный дисплей
disp.clear();
disp.brightness(4); // яркость, 0 - 7 (минимум - максимум)
}
void loop() {
timerTicks();
showTimer();
switchLEDs();
beep(timerTick); // пищим каждый тик таймера
}
// функция генерирует тики таймера
void timerTicks() {
static uint32_t previousTime = 0;
uint32_t currentTime = millis();
if ( (currentTime - previousTime) >= TIMER_TICK_INTERVAL ) {
timerTick = true;
previousTime = currentTime;
}
else timerTick = false;
}
// функция отображает часы на TM1637
void showTimer() {
static int seconds = DEFUSE_TIME;
static bool points = true;
if (!digitalRead(SW)) seconds = DEFUSE_TIME; // сбрасываем таймер при нажатии энкодера
// каждый тик таймера обновляем дисплей
if (timerTick) {
disp.displayClock(seconds / 60, seconds % 60); // отображаем минуты и секунды
disp.point(points); // включаем/выключаем разделитель ТМ1637
points = !points;
if (seconds > 0) --seconds;
}
}
// функция кратковременно пищит зуммером
// для активного зуммера использовать два порта!!!
// т.к. ток слишком велик для одного
void beep(bool enable) {
static uint32_t previousTime = 0;
uint32_t currentTime = millis();
if (enable) {
// для активного зуммера
// digitalWrite (BUZZER1, HIGH);
// digitalWrite (BUZZER2, HIGH);*/
// для пассивного зуммера
tone(BUZZER1, 2300);
previousTime = currentTime;
}
else {
if ( (currentTime - previousTime) >= BEEP_TIME ) {
// для активного зуммера
// digitalWrite (BUZZER1, LOW);
// digitalWrite (BUZZER2, LOW);
// для пассивного зуммера
noTone(BUZZER1);
}
}
}
// Функция мигает СИДами ошибок
void switchLEDs() {
static bool led1State = true;
static bool led2State = false;
if (timerTick) {
digitalWrite(LED1, led1State);
digitalWrite(LED2, led2State);
led1State = !led1State;
led2State = !led2State;
}
}