countdown timer using interrupts

lannocm
Posts: 28
Joined: Fri Feb 05, 2021 5:43 pm

countdown timer using interrupts

Postby lannocm » Mon Sep 26, 2022 2:41 pm

Hi,

I thought this would be a simple matter but I have spent DAYS trying to resolve it for myself with no luck.

I simply want to create a countdown timer using hardware interrupts (because there a number of other things going on) and that the countdown appear on a display, counting down seconds to zero. Therefore, the display should be refreshed every second.

I have searched the internet for an example of setting the direction of countdown and found only ONE example. And that was changed.

The key points are (I think):

timer = timerBegin(0, 80, false); - this should be set to 'false' to count down, according to the documentation. Is that correct?
timerWrite(timer,10000); - this is supposed to be the value from which to count down but I can't find anywhere to tell me what the units are.
I don't want the counter to start immediately - I thought that could be achieved using the timerStart. So, do I need timerBegin?
I want to display the number of seconds remaining on the display: can that be achieved using "timerReadSeconds(timer)"?

Thanks,

Connal

Here is the code I have so far (which doesn't work).

Code: Select all

volatile bool interruptCounter;
int timeStat;
 
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
 
void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux);
  interruptCounter = true;
  portEXIT_CRITICAL_ISR(&timerMux);
 
}
 
void setup() {
 
  Serial.begin(115200);
  timer = timerBegin(0, 80, false);
  timerWrite(timer,10000);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 1000000, true);
  timerAlarmEnable(timer);
 
}
 
void loop() {
 
  if (interruptCounter) {
 
    portENTER_CRITICAL(&timerMux);
    interruptCounter = false;
    timeStat = timerReadSeconds(timer);
    portEXIT_CRITICAL(&timerMux);
    
    Serial.print(timeStat);
    Serial.println(" seconds");
  }
}

felmue
Posts: 69
Joined: Mon Nov 16, 2020 2:55 pm

Re: countdown timer using interrupts

Postby felmue » Mon Sep 26, 2022 4:31 pm

Hello @lannocm

the way I understand timers to work is like this:
- timer counting up: timer starts at 0 microseconds and when it reaches the alarm value (1000000 microseconds) the interrupt is triggered.
- timer counting down: timer starts at 1000000 microseconds and when it reaches the alarm value (0 microseconds) the interrupt is triggered.

So in your example you start the countdown timer at 10000 microseconds and wait for it to reach the alarm time of (1000000 microseconds). That is probably not what you've intended.

If you change the start time to 1000000 microseconds and the alarm time to 0 microseconds the interrupt will be triggered every second.

Calling TimerReadSeconds() only when the interrupt has been triggered will always return 0 (as the condition for the interrupt to be triggered is the alarm time.)

You can either add a counter variable which you decrement within the interrupt function (which is called every second).

BTW: in that scenario it actually doesn't matter whether the timer is setup to increment or decrement.

Or you could start your timer at let's say 10 seconds, still set the alarm time to 0 seconds and non repeating and ReadTimerSeconds() in the loop. That will count down from 10 to 0 seconds and then stop. (Note: You won't need the interrupt in that scenario.)

Also have a look at the examples at the bottom of this page: https://espressif-docs.readthedocs-host ... timer.html

Thanks
Felix

lbernstone
Posts: 636
Joined: Mon Jul 22, 2019 3:20 pm

Re: countdown timer using interrupts

Postby lbernstone » Mon Sep 26, 2022 5:30 pm

I would save the hardware timer for when you really need to interact with the hardware on a microsecond scale. The OS timer will be much easier for this use case, and gets you around all the interrupt issues.

Code: Select all

#include <Ticker.h>
Ticker tkSec;
uint32_t timer1 = 42;
void everySecond() {
  if (timer1 && --timer1 == 0) Serial.println("timer done");
}
void setup() {
  Serial.begin(115200);
  tkSec.attach(1, everySecond);  
}
void loop() {}

lannocm
Posts: 28
Joined: Fri Feb 05, 2021 5:43 pm

Re: countdown timer using interrupts

Postby lannocm » Mon Sep 26, 2022 7:04 pm

Thanks, both.

A few more questions, then...

@felmue. You suggest a 10 second timer: does that mean setting timerWrite to 10,000,000? I think I understand why no interrupt is required but could you just spell it out for me, please?

@lbernstone. I'm happy not to use interrupts but I thought there was an impact if other things were going on. Eg I have two other interrupts running, monitoring sensors and controllers. You are right, it doesn't have to be microsecond accurate but it should be millisecond accurate. Is your method ok for that?

Also, what do I need to pick out to output to my lcd display (ili9341) to count down in seconds?

Many thanks,

Connal

lbernstone
Posts: 636
Joined: Mon Jul 22, 2019 3:20 pm

Re: countdown timer using interrupts

Postby lbernstone » Mon Sep 26, 2022 8:40 pm

The everySecond function will run every second (that's the 1 in attach). You can write what you want to the display in there. The execution of that function will not be exactly every 1000 milliseconds, as there may be system activity which will be higher priority. However, the cadence will absolutely be that the function fires every 1000 milliseconds, so your timing will not fall out of sync (at least not any more than the underlying frequency from the piezo crystal).
https://github.com/espressif/arduino-es ... r/examples

lannocm
Posts: 28
Joined: Fri Feb 05, 2021 5:43 pm

Re: countdown timer using interrupts

Postby lannocm » Tue Sep 27, 2022 8:26 pm

Hi,

Thanks for the extra information. I think I now have a version of it working that (so far) meets my needs:

Code: Select all

#include "TickTwo.h"

int	BTN_SELECT	=	18;
long int modeLastChanged = 0;
int iTime = 10;

void timeMessage() {
  Serial.println(iTime);
  if (iTime && --iTime == 0) Serial.println("timer done");
  }

TickTwo timer(timeMessage, 1000, iTime); // iTime times, every second


void setup() {
  Serial.begin(115200);

  pinMode(BTN_SELECT,	INPUT_PULLUP);
  }

void loop() {


if (digitalRead(BTN_SELECT) == LOW && millis() - modeLastChanged > 300) {       //the button has been pressed, BTN_SELECT = LOW
    modeLastChanged = millis();
    startTimer();
    Serial.println("Button Pressed");
  }
  timer.update();
  }


void startTimer(){
  timer.start();
}
Thanks again,

Connal

Who is online

Users browsing this forum: No registered users and 65 guests