#define LED_pin 32
#define prescaler 40
#define contador (40000000/prescaler)
#define contagem_em_segundos 3

hw_timer_t *timer = NULL; // ponteiro para uma variável do tipo hw_timer_t

volatile bool interrupted = false;
int contagem_interrupcao = 0;
bool LED = false;

/* Ao definir a ISR como IRAM_ATTR, indicamos que o trecho de código ficará na seção de
   instruções da RAM e não na Flash, ganhando velocidade na execução
*/
void IRAM_ATTR onTimer() {
  contagem_interrupcao++;
  if (contagem_interrupcao == contagem_em_segundos)
    interrupted = true;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_pin, OUTPUT);
  digitalWrite(LED_pin, HIGH);
  Serial.begin(115200);
  Serial.println(contador);

  /* timerBegin(param1, param2, param3)
    param1: número do timer que queremos usar (de 0 a 3, pois temos 4 timers de hardware)
    param2: valor do prescaler (divisor de frequência do clock)
    param3: flag indicando se o contador deve contar para cima (true) ou para baixo (false)
  */
  timer = timerBegin(0, prescaler, true);

  /* o terceiro parametro de timerAttachInterrupt(), true, indica que queremos que a interrupção
    seja do tipo borda (o que significa que ela deve ser acionada em uma borda de subida (rising) ou
    de descida (falling)
  */

  timerAttachInterrupt(timer, &onTimer, true);

  /* A função timerAlarmWrite especifica que um ALARME deve ser acionado toda vez que a contagem do
    temporizador atingir o CONTADOR.
    O terceiro argumento desta função, true, indica que o temporizador deve ser recarregado automaticamente.
    Isso significa que após gerar um alarme uma vez, ele deve recarregar automaticamente e começar a contar
    novamente de 0 a CONTADOR
  */
  timerAlarmWrite(timer, contador, true);
  timerAlarmEnable(timer);
}

void loop() {
  if (interrupted) { // Se interrupted for true, significa que o alarme foi acionado
    contagem_interrupcao = 0;
    interrupted = false;
    digitalWrite(LED_pin, LED);
    LED = !LED;
  }
}