Обработка нажатий на кнопку

Задача следующая: обработать нажатия на кнопку и включить светодиод соответствующий нужному режиму.

Однократное нажатие, двойное или длинное переводят систему в различные состояния. Для того, что бы не пропустить короткие нажатия, будем использовать прерывания.

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;
	}
}