// ЗАДАЧА: ПЕРЕКЛЮЧЕНИЕ РЕЖИМОВ КНОПКОЙ С ПРОГРАММНЫМ АНТИДРЕБЕЗГОМ ПО КОЛЬЦУ ПО ПРЕРЫВАНИЮ.
// ПРИ ПОДАЧЕ ПИТАНИЯ РЕЖИМЫ НЕ ВКЛЮЧАЮТСЯ, Т.К. НАЧАЛЬНАЯ УСТАНОВКА COUNTER = -1,
// А ЭТО НЕ СООТВЕТСТВУЕТ НИ ОДНОМУ ИЗ ВАРИАНТОВ CASE (0, 1 ИЛИ 2).
// ПОСЛЕ ПЕРВОГО КЛИКА КНОПКОЙ ВКЛЮЧАЕТСЯ РЕЖИМ CASE 0, Т.К. COUNTER СТАНОВИТСЯ РАВНЫМ 0.
// ДАЛЕЕ РЕЖИМЫ ПЕРЕКЛЮЧАЮТСЯ ПО КОЛЬЦУ.
#define LED_Red 5
#define LED_Yellow 4
#define LED_Green 6
#define button_Pin 2 // Кнопку подключаем на пин 2 (INT0 для Atmega328).
#define MODES 3 // Кол-во режимов (case 0, 1 или 2)
byte PINS[] = { LED_Red, LED_Yellow, LED_Green };
byte i = 0;
volatile bool flagTick = false; // Флаг прерывания (flagTick = true - прерывание произошло)
volatile uint32_t debounceTimer = 0; // переменная таймера антидребезга
volatile int8_t counter = -1; // Счётчик нажатий кнопки. Начальная установка = -1, чтобы
// после первого клика кнопкой режим начинался с case 0.
// При плохой кнопке пришлось подобрать время 200 мс антидребезга. Стало работать надёжно.
void buttonTick() {
flagTick = true; // Произошло прерывание. Поднимаем флаг.
/* Если прошло 200 мс "И" сигнал на кнопке = HIGH
(т.к. кнопка по INPUT_PULLUP подцеплена), то увеличиваем счётчик:*/
if (millis() - debounceTimer >= 200 && !digitalRead(button_Pin)) {
debounceTimer = millis();
counter++;
}
}
void setup() {
pinMode(button_Pin, INPUT_PULLUP); // Используем внутреннюю подтяжку к U пит.
attachInterrupt(0, buttonTick, CHANGE); // INT0 на пине D2 по изменению сигнала.
for (i = 0; i < 3; i++) { pinMode(PINS[i], OUTPUT); }
}
void loop() {
if (flagTick) { // Если флаг прерывания поднят, то надо сбросить и закольцевать счётчик.
flagTick = false;
if (counter > MODES - 1) counter = 0;
}
switch (counter) {
case 0:
digitalWrite(LED_Red, 1);
break;
case 1:
digitalWrite(LED_Yellow, 1);
break;
case 2:
digitalWrite(LED_Green, 1);
break;
}
for (i = 0; i < 3; i++) digitalWrite(PINS[i], LOW); // Выключаем светодиоды между режимами
}