Задача следующая: обработать нажатия на кнопку и включить светодиод соответствующий нужному режиму.
Однократное нажатие, двойное или длинное переводят систему в различные состояния. Для того, что бы не пропустить короткие нажатия, будем использовать прерывания.
void clickButton(){
if(millis() - now > DT_INTERRUPT){
now = millis();
butStatSend++;
detachInterrupt(digitalPinToInterrupt(digitalPinToInterrupt(2)));
}
}
Для расчета нажатий используем разность времени между событиями. Вычисляем длительность нажатия, для определения длинного нажатия и длительность между двумя различными нажатиями для отлова двойных.
t2 – t1 — длительность нажатия. Вычисляем разность и определяем «длинное» или «короткое». t3 – t1 — длительность между нажатиями. Если менее порога, то «двойное».
#include <Arduino.h>
#include "timer.h"
// #include "softLed.h"
#define BUTTON_INTERRUPT 2
#define LED1 10
#define LED2 11
#define LED3 12
const uint32_t FIRST_T{300}; //задержка после первого нажатия
const uint32_t DOUBLE_T{700}; //задержка после двойного нажатия
const uint32_t LONG_T{1000}; //задержка после длинного нажатия
const uint32_t DT_INTERRUPT{45}; //задержка для подавления дребезга
Timer timer;
enum class ButStat {
FREE,
FIRST,
DOUBLE,
};
ButStat butStat{ButStat::FREE}; //не используем операцию присваивания. То же, но дольше ButStat butStat = {ButStat::FREE};
volatile uint8_t butStatSend{0};
volatile uint32_t now{0};
volatile uint32_t t1 = 0; //время текущего нажатия
volatile uint32_t t2 = 0; //время текущего отпускания
volatile uint32_t t3 = 0; //время предыдущего нажатия
//***************************************************************
void clickButton(){
if(millis() - now > DT_INTERRUPT){
now = millis();
++butStatSend;
detachInterrupt(digitalPinToInterrupt(digitalPinToInterrupt(2))); //отключаем обработчик прерываний
}
}
//********************************************* погасить светодиоды
void clearLed(){
digitalWrite(LED1, LOW);
digitalWrite(LED3, LOW);
digitalWrite(LED2, LOW);
}
//*********************************************
void setup() {
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(BUTTON_INTERRUPT), clickButton, RISING);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
}
//*********************************************
void loop() {
if(butStatSend){ //если сработало прерывание
clearLed();
switch(butStat){ //действия выбираются в зависимости от текущего состояния системы
case ButStat::FREE:
t1 = now;
if(t1 - t3 < DOUBLE_T){ //вычиляем двойное нажатие, как разницу времён между двумя нажатиями
Serial.println("Double"); //быстрые нажатия
butStat =ButStat::DOUBLE;
t3 = 0;
} else {
butStat =ButStat::FIRST; //нет двойного нажатия
}
attachInterrupt(digitalPinToInterrupt(2), clickButton, FALLING); //включаем прерывание по "отключению кнопки", переход из 1 в 0
break;
case ButStat::FIRST:
t2 = now;
if(t2 - t1 > LONG_T){ //вычисляем длинное нажатие
butStat =ButStat::FREE;
Serial.println("Long");
digitalWrite(LED2, HIGH);
t3 = 0;
} else {
t3 = t1;
digitalWrite(LED3, HIGH);
Serial.println("Short");
butStat =ButStat::FREE;
}
attachInterrupt(digitalPinToInterrupt(2), clickButton, RISING);
break;
case ButStat::DOUBLE:
digitalWrite(LED1, HIGH); //отлавливаем отпускание кнопки при двойном нажатии
butStat =ButStat::FREE;
attachInterrupt(digitalPinToInterrupt(2), clickButton, RISING);
break;
}
butStatSend = 0;
}
}