/*
O que é IRAM_ATTR?
Se o código que queremos executar é uma Rotina de Serviço de
Interrupção (ISR), geralmente queremos executá-lo o mais rápido
possível. Se tivéssemos que "esperar" que o ISR carregasse
no Flash, as coisas podem dar terrivelmente errado.
A função IRAM_ATTR, é utilizada, então, para indicar que tal
trecho de código ficará na seção do barramento de
instruções da RAM (maior velocidade), e não na Flash.
Uma peculiaridade:
deve ser feito o debounce do botão em software dentro da
interrupção, a fim de as trepidações no botão não serem
contadas erroneamente como acionamentos.
Isso não pode ser feito com delays, por isso deve-se fazer
uso da função millis() para ajudar na comparação do tempo
do acionamento com o tempo do último acionamento válido.
Dessa forma, o impacto em termos de tempo de execução dentro
da função ISR é mínimo.
*/
#define TEMPO_DEBOUNCE 100 //ms
unsigned long timestamp_ultimo_acionamento = 0;
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Button button1 = {18, 0, false};
void IRAM_ATTR isr() {
/* Conta acionamentos do botão considerando debounce */
if ( (millis() - timestamp_ultimo_acionamento) >= TEMPO_DEBOUNCE )
{
button1.numberKeyPresses++;
button1.pressed = true;
timestamp_ultimo_acionamento = millis();
}
}
void setup() {
Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterrupt(button1.PIN, isr, FALLING);
}
void loop() {
if (button1.pressed) {
Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses);
button1.pressed = false;
}
}