Загрузка данных
#include <Arduino.h>
// 74HC595 на multifunction shield
const byte DATA_PIN = 8; // SDI
const byte CLOCK_PIN = 7; // SFTCLK
const byte LATCH_PIN = 4; // LCHCLK
// Кнопки на shield
const byte BTN_INC = A1; // +1
const byte BTN_MODE = A2; // минуты / секунды
const byte BTN_START = A3; // старт
// Пьезоэлемент
const byte BUZZER_PIN = 3; // если не пищит — проверь пин на своём шилде
// Таблица сегментов для common anode
const byte SEG_CA[10] = {
0xC0, // 0
0xF9, // 1
0xA4, // 2
0xB0, // 3
0x99, // 4
0x92, // 5
0x82, // 6
0xF8, // 7
0x80, // 8
0x90 // 9
};
// Выбор разрядов
const byte DIGIT_SEL[4] = {
0x01,
0x02,
0x04,
0x08
};
const unsigned long DEBOUNCE_MS = 40;
const unsigned long TICK_MS = 1000;
const unsigned long BLINK_MS = 500;
struct ButtonState {
bool lastRead = HIGH;
bool stable = HIGH;
unsigned long lastChange = 0;
};
ButtonState incBtn, modeBtn, startBtn;
enum TimerMode {
SETUP,
RUNNING,
DONE
};
TimerMode mode = SETUP;
// Редактируемое время
uint8_t setMinutes = 0;
uint8_t setSeconds = 0;
// Текущее время таймера
uint16_t remainingSeconds = 0;
// 0 = минуты, 1 = секунды
uint8_t editField = 0;
unsigned long lastTick = 0;
unsigned long lastBlink = 0;
bool blinkOn = true;
byte digits[4] = {0, 0, 0, 0};
void send595(byte firstByte, byte secondByte) {
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, firstByte);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, secondByte);
digitalWrite(LATCH_PIN, HIGH);
}
bool buttonPressed(ButtonState &btn, byte pin) {
bool reading = digitalRead(pin);
if (reading != btn.lastRead) {
btn.lastChange = millis();
btn.lastRead = reading;
}
if (millis() - btn.lastChange > DEBOUNCE_MS) {
if (reading != btn.stable) {
btn.stable = reading;
if (btn.stable == LOW) return true;
}
}
return false;
}
void splitToDigits(uint16_t n) {
digits[3] = n % 10;
n /= 10;
digits[2] = n % 10;
n /= 10;
digits[1] = n % 10;
n /= 10;
digits[0] = n % 10;
}
void refreshDisplay(uint16_t value, bool blank = false) {
if (!blank) {
splitToDigits(value);
}
for (byte pos = 0; pos < 4; pos++) {
if (blank) {
send595(0xFF, 0x00);
} else {
byte seg = SEG_CA[digits[pos]];
byte dig = DIGIT_SEL[pos];
send595(seg, dig);
}
delayMicroseconds(800);
}
}
uint16_t presetToSeconds() {
return (uint16_t)setMinutes * 60U + (uint16_t)setSeconds;
}
void startTimer() {
remainingSeconds = presetToSeconds();
if (remainingSeconds == 0) return;
mode = RUNNING;
lastTick = millis();
noTone(BUZZER_PIN);
}
void setup() {
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(BTN_INC, INPUT_PULLUP);
pinMode(BTN_MODE, INPUT_PULLUP);
pinMode(BTN_START, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(LATCH_PIN, HIGH);
noTone(BUZZER_PIN);
}
void loop() {
// Кнопки
if (buttonPressed(incBtn, BTN_INC)) {
if (mode != RUNNING) {
mode = SETUP;
noTone(BUZZER_PIN);
if (editField == 0) {
setMinutes++;
if (setMinutes > 99) setMinutes = 0;
} else {
setSeconds++;
if (setSeconds > 59) setSeconds = 0;
}
}
}
if (buttonPressed(modeBtn, BTN_MODE)) {
if (mode != RUNNING) {
mode = SETUP;
noTone(BUZZER_PIN);
editField ^= 1;
}
}
if (buttonPressed(startBtn, BTN_START)) {
if (mode != RUNNING) {
startTimer();
}
}
// Таймер
if (mode == RUNNING) {
unsigned long now = millis();
if (now - lastTick >= TICK_MS) {
lastTick += TICK_MS;
// Пищим в последние 10 секунд, каждую секунду
if (remainingSeconds <= 10 && remainingSeconds > 1) {
tone(BUZZER_PIN, 2000, 80);
}
if (remainingSeconds > 0) {
remainingSeconds--;
}
if (remainingSeconds == 0) {
mode = DONE;
lastBlink = now;
blinkOn = true;
// Сигнал по окончанию таймера
tone(BUZZER_PIN, 2500, 700);
}
}
}
// Мигающие нули после окончания
if (mode == DONE) {
unsigned long now = millis();
if (now - lastBlink >= BLINK_MS) {
lastBlink = now;
blinkOn = !blinkOn;
}
refreshDisplay(0, !blinkOn);
return;
}
// Обычный вывод времени
if (mode == RUNNING) {
refreshDisplay(remainingSeconds);
} else {
refreshDisplay(presetToSeconds());
}
}