khoih-prog / TimerInterrupt

This library enables you to use Interrupt from Hardware Timers on an Arduino, such as Nano, UNO, Mega, etc. It now supports 16 ISR-based timers, while consuming only 1 hardware Timer. Timers' interval is very long (ulong millisecs). The most important feature is they're ISR-based timers. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks.
MIT License
98 stars 11 forks source link

User of new ISR_Timer does not work #6

Closed chess-levin closed 3 years ago

chess-levin commented 3 years ago

Hello Khoi Hoang, I like to try your new Library 1.0.2, but had no success with your new 16 ISR-based-timers. I want to work with several 'virtual timers' based on timer number two of my arduino nano board. Timer number one is used for a PWM-function / analogWrite() According to my sketch (see below) there should be some output every 2 and 5 seconds, but nothing happens. What do I wrong?

When I attach an ISR this way ITimer2.attachInterruptInterval(TIMER2_INTERVAL_MS, timer2HandlerDown) it works. But my understanding is, that it is not possible to use more than one ISR this way.

Thank you for your support.

#define TIMER_INTERRUPT_DEBUG      0

#define USE_TIMER_1     false
#define USE_TIMER_2     true
#define USE_TIMER_3     false
#define USE_TIMER_4     false
#define USE_TIMER_5     false

#include "TimerInterrupt.h"
#include "ISR_Timer.h"

#define TIMER2_INTERVAL_MS 50

//https://www.youtube.com/watch?v=2kr5A350H7E?t=4m14s
ISR_Timer ISR_Timer2;

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

  ITimer2.init();

  ISR_Timer2.setInterval(2000L, doingSomething2s);
  ISR_Timer2.setInterval(5000L, doingSomething5s);

  ISR_Timer2.run();
}

void doingSomething2s() {
  Serial.println("INFO: doingSomething2s()");
}
void doingSomething5s() {
  Serial.println("INFO: doingSomething5s()");
}

void loop() {

  Serial.println("delay");
  delay(5000);
}

Arduino IDE 1.8.13 VID: 1A86 PID: 7523

khoih-prog commented 3 years ago

Thanks for your interests in the Library.

Your code did not initialize the ISR_Timer2 correctly.

I've just added example ISR_16_Timers_Array_Complex and ISR_Timers_Array_Simple to demonstrate the usage of 16 virtual ISR-based timers

The latter is modified from your code to illustrate what steps are missing.

#define TIMER_INTERRUPT_DEBUG      0

#define USE_TIMER_1     false
#define USE_TIMER_2     true
#define USE_TIMER_3     false
#define USE_TIMER_4     false
#define USE_TIMER_5     false

#include "TimerInterrupt.h"
#include "ISR_Timer.h"

#include <SimpleTimer.h>              // https://github.com/schinken/SimpleTimer

ISR_Timer ISR_Timer2;

#ifndef LED_BUILTIN
  #define LED_BUILTIN       13
#endif

#define LED_TOGGLE_INTERVAL_MS        1000L

// You have to use longer time here if having problem because Arduino AVR clock is low, 16MHz => lower accuracy.
// Tested OK with 1ms when not much load => higher accuracy.
#define TIMER2_INTERVAL_MS            1L

volatile uint32_t startMillis = 0;

volatile uint32_t deltaMillis2s = 0;
volatile uint32_t deltaMillis5s = 0;

volatile uint32_t previousMillis2s = 0;
volatile uint32_t previousMillis5s = 0;

void TimerHandler2()
{
  static bool toggle  = false;
  static int timeRun  = 0;

  ISR_Timer2.run();

  // Toggle LED every LED_TOGGLE_INTERVAL_MS = 2000ms = 2s
  if (++timeRun == ((LED_TOGGLE_INTERVAL_MS) / TIMER2_INTERVAL_MS) )
  {
    timeRun = 0;

    //timer interrupt toggles pin LED_BUILTIN
    digitalWrite(LED_BUILTIN, toggle);
    toggle = !toggle;
  }
}

void doingSomething2s()
{
  unsigned long currentMillis  = millis();

  deltaMillis2s    = currentMillis - previousMillis2s;
  previousMillis2s = currentMillis;
}

void doingSomething5s()
{
  unsigned long currentMillis  = millis();

  deltaMillis5s    = currentMillis - previousMillis5s;
  previousMillis5s = currentMillis;
}

/////////////////////////////////////////////////

#define SIMPLE_TIMER_MS        2000L

// Init SimpleTimer
SimpleTimer simpleTimer;

// Here is software Timer, you can do somewhat fancy stuffs without many issues.
// But always avoid
// 1. Long delay() it just doing nothing and pain-without-gain wasting CPU power.Plan and design your code / strategy ahead
// 2. Very long "do", "while", "for" loops without predetermined exit time.
void simpleTimerDoingSomething2s()
{
  static unsigned long previousMillis = startMillis;

  unsigned long currMillis = millis();

  Serial.println("SimpleTimer : programmed " + String(SIMPLE_TIMER_MS) + "ms, current time ms : " + String(currMillis) + ", Delta ms : " + String(currMillis - previousMillis));

  Serial.println("Timer2s actual : " + String(deltaMillis2s));
  Serial.println("Timer5s actual : " + String(deltaMillis5s));

  previousMillis = currMillis;
}

////////////////////////////////////////////////

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);
  while (!Serial);

  Serial.println("\nStarting ISR_Timers_Array_Simple");
  Serial.println("Version : " + String(TIMER_INTERRUPT_VERSION));
  Serial.println("CPU Frequency = " + String(F_CPU / 1000000) + " MHz");

  ITimer2.init();

  if (ITimer2.attachInterruptInterval(TIMER2_INTERVAL_MS, TimerHandler2))
    Serial.println("Starting  ITimer2 OK, millis() = " + String(millis()));
  else
    Serial.println("Can't set ITimer2. Select another freq., duration or timer");

  ISR_Timer2.setInterval(2000L, doingSomething2s);
  ISR_Timer2.setInterval(5000L, doingSomething5s);

  // You need this timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary.
  simpleTimer.setInterval(SIMPLE_TIMER_MS, simpleTimerDoingSomething2s);
}

#define BLOCKING_TIME_MS      10000L

void loop()
{
  // This unadvised blocking task is used to demonstrate the blocking effects onto the execution and accuracy to Software timer
  // You see the time elapse of ISR_Timer still accurate, whereas very unaccurate for Software Timer
  // The time elapse for 2000ms software timer now becomes 3000ms (BLOCKING_TIME_MS)
  // While that of ISR_Timer is still prefect.
  delay(BLOCKING_TIME_MS);

  // You need this Software timer for non-critical tasks. Avoid abusing ISR if not absolutely necessary
  // You don't need to and never call ISR_Timer.run() here in the loop(). It's already handled by ISR timer.
  simpleTimer.run();
}

Although Serial.print() in Arduino Mega/UNO/Nano ISR is currently working, I advise not to do that way,. I've moved them to software timer's simpleTimerDoingSomething2s() to demonstrate how to use ISRs correctly.

Good Luck,

khoih-prog commented 3 years ago

You can see in the following terminal output the accuracy if ISR-based Timers

Starting ISR_Timers_Array_Simple
Version : v1.0.3
CPU Frequency = 16 MHz
Starting  ITimer2 OK, millis() = 1
SimpleTimer : programmed 2000ms, current time ms : 10004, Delta ms : 10004
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 20013, Delta ms : 10009
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 30021, Delta ms : 10008
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 40030, Delta ms : 10009
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 50038, Delta ms : 10008
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 60046, Delta ms : 10008
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 70054, Delta ms : 10008
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 80063, Delta ms : 10009
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 90072, Delta ms : 10009
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 100080, Delta ms : 10008
Timer2s actual : 2001
Timer5s actual : 5001
SimpleTimer : programmed 2000ms, current time ms : 110089, Delta ms : 10009
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 120097, Delta ms : 10008
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 130106, Delta ms : 10009
Timer2s actual : 2000
Timer5s actual : 5000
SimpleTimer : programmed 2000ms, current time ms : 140113, Delta ms : 10007
Timer2s actual : 2000
Timer5s actual : 5000