0

I have to use multiple timers (for example, to blink different LEDs) with different frequency (for example, 7.3 Hz). Cannot you tell me, what is the preferred way to implement it?

Just now I use one simple TimerOne timer and just check what LEDs should be inverted and what are not, but I don't think it's a good idea.

#include <TimerOne.h>

#define PIN_RED 52
#define PIN_GREEN 50
#define PIN_BLUE 48
#define PIN_YELLOW 46

#define N_LEDS 4

float freqs[N_LEDS] = {1, 2, 3, 4};
int pins[N_LEDS] = {PIN_RED, PIN_GREEN, PIN_BLUE, PIN_YELLOW};

long int usec_to_invert[N_LEDS];
long int full_usec_to_invert[N_LEDS];

boolean led_states[N_LEDS];

int who_is_next()
{
  int next_to_invert = 0;
  for(int i = 0; i < N_LEDS; i++)
  {
    if(usec_to_invert[i] < usec_to_invert[next_to_invert])
    {
      next_to_invert = i;
    }
  }
  return next_to_invert;
}

void process_timer()
{
  int to_invert_now = who_is_next(); // Смотрим, кого надо инвертировать на этот раз
  long int time_past = usec_to_invert[to_invert_now];

  for(int i = 0; i < N_LEDS; i++)
  {
    usec_to_invert[i] -= time_past;
  }
  led_states[to_invert_now] = !led_states[to_invert_now];
  digitalWrite(pins[to_invert_now], led_states[to_invert_now]);
  usec_to_invert[to_invert_now] = full_usec_to_invert[to_invert_now];


  int next_to_invert = who_is_next();
  long int time_to_pass = usec_to_invert[next_to_invert];
  if(time_to_pass <= 200)
  {  // The interrupt processor should finish work
    Timer1.setPeriod(200);
  }
  else
  {
    Timer1.setPeriod(time_to_pass);
  }
}

void setup()
{
  Serial.begin(115200);
  for(int i = 0; i < N_LEDS; i++)
  {
    pinMode(pins[i], OUTPUT);
    led_states[i] = false;
    full_usec_to_invert[i] = (long int)(1000000. / freqs[i] / 2.);
    usec_to_invert[i] = full_usec_to_invert[i];
  }

  int next_to_invert = who_is_next();
  Timer1.initialize(usec_to_invert[next_to_invert]);
  Timer1.attachInterrupt(process_timer);
}

void loop()
{
   delay(1000);
}
1

My suggestions would be:

  • Implement a class that handles the queue and timer settings and uses callbacks.
  • If you do not need perfect accuracy, remove the loop making the program wait and do that part just setting the timer.
  • digitalRead() on an output pin returns the value it was last set to, therefore you do not need to waste that extra RAM.
  • DO NOT wait in the ISR "process_timer()", since you might lose other interrupts! (for the Serial communication, for example)
  • is it neccessary to have only values above 200? if not, then don't prevent them from going below that.

--or

use a total overkill system for this situation, such as my multitasking-library arduOS that also covers a some other things.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.