Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save futureshocked/5327bec254a9d5afcc91fa0b673442b6 to your computer and use it in GitHub Desktop.
Save futureshocked/5327bec254a9d5afcc91fa0b673442b6 to your computer and use it in GitHub Desktop.
ESP32 timer interrupts, how to change duration in the loop.
const byte LED_GPIO = 2;
volatile int interruptCounter; // When this is not zero, we'll take a reading from the sensor
// The interrupt service routine will increment it.
// When the sensor is read, this variable is decremented.
volatile int blinkCounter = 0;
// The hardware timer pointer
hw_timer_t * timer = NULL;
// This variable is used for syncronisation
// We use it to ensure that the ISR and the loop
// do not try to access the interruptCounter variable
// at the same time.
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
blinkCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(9600);
pinMode(LED_GPIO, OUTPUT);
// Initilise the timer.
// Parameter 1 is the timer we want to use. Valid: 0, 1, 2, 3 (total 4 timers)
// Parameter 2 is the prescaler. The ESP32 default clock is at 80MhZ. The value "80" will
// divide the clock by 80, giving us 1,000,000 ticks per second.
// Parameter 3 is true means this counter will count up, instead of down (false).
timer = timerBegin(0, 80, true);
// Attach the timer to the interrupt service routine named "onTimer".
// The 3rd parameter is set to "true" to indicate that we want to use the "edge" type (instead of "flat").
timerAttachInterrupt(timer, &onTimer, true);
// This is where we indicate the frequency of the interrupts.
// The value "1000000" (because of the prescaler we set in timerBegin) will produce
// one interrupt every second.
// The 3rd parameter is true so that the counter reloads when it fires an interrupt, and so we
// can get periodic interrupts (instead of a single interrupt).
timerAlarmWrite(timer, 1000000, true);
// Start the timer
timerAlarmEnable(timer);
}
void loop() {
if (interruptCounter > 0) {
Serial.print(blinkCounter);
Serial.print(" ");
portENTER_CRITICAL(&timerMux);
interruptCounter--;
// timerAlarmDisable(timer);
if (blinkCounter % 2 == 0)
{
timerAlarmWrite(timer, 5000000, true);
Serial.println("5000000");
}
else
{
timerAlarmWrite(timer, 500000, true);
Serial.println("500000");
}
// timerAlarmEnable(timer);
portEXIT_CRITICAL(&timerMux);
toggleLED(); // Access the sensor and print the values
}
}
void toggleLED() {
digitalWrite(LED_GPIO, HIGH); // turn the LED on (HIGH is the voltage level)
delay(50); // wait for a second
digitalWrite(LED_GPIO, LOW); // turn the LED off by making the voltage LOW
}
@TommMissioneiro
Copy link

#include "esp32-hal-timer.h"

hw_timer_t * timer1 = NULL;
volatile bool isr = false;

void ARDUINO_ISR_ATTR onTimer1() {
isr = true;
/*
É uma boa prática evitar chamadas como Serial.println() dentro de uma ISR (Interrupt Service Routine) no ESP32, pois elas podem causar instabilidade devido à execução de operações não seguras para interrupção ou que demandam muito tempo.
No seu código revisado, você usou a abordagem correta ao definir uma flag volatile chamada isr na ISR e manipular qualquer comunicação serial ou lógica mais complexa no loop principal. Essa é a maneira recomendada de lidar com interrupções, especialmente em plataformas sensíveis ao tempo como o ESP32. Isso evita problemas com watchdog timers e garante que a ISR seja o mais rápida e leve possível.
Além disso, você utilizou timerWrite(timer1, 0) e timerAlarmEnable(timer1) para reiniciar o timer a partir do loop principal, o que é uma excelente maneira de controlar quando o timer deve começar a contar novamente, evitando manipulações desnecessárias na ISR.
*/
}

void setup() {
Serial.begin(115200);
timer1 = timerBegin(0, 80, true);
timerAttachInterrupt(timer1, &onTimer1, true);
// Configura o Timer 1 para o primeiro disparo
timerAlarmWrite(timer1, 5000000, false);
timerAlarmEnable(timer1);
// setupTimer1();
}

void loop() {
// Suponha que, baseado em alguma condição, você quer reiniciar o Timer 1 para um novo disparo único
// Aqui, usamos uma entrada Serial simples para o exemplo
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'r') { // Se o caractere 'r' for recebido, reinicie o timer
timerWrite(timer1, 0);
timerAlarmEnable(timer1);
Serial.println("Timer 1 reiniciado para um novo disparo único.");
}
}
if (isr) {
isr=false;
Serial.println("Timer 1 foi disparado");
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment