Blinking an LED at 20Hz

I wanted to make a battery operated project that blinks an LED at 20Hz with an LED on time of 20uS and put the micro to sleep between pulses to save battery. I want the times between when the LED is turned on to stay very constant. Do I need to worry about temperature drift with the internal Arduino clock? For the LED I assume I just need to pick one with a very fast on time, or there any other considerations I should think about?

20uS is pretty long for a led if you figure that a led is a diode with a switching time of maybe a couple dozen nanoseconds. I'm not sure what the requirement on the rise and fall times are for the led. It's also not entirely clear/objectively quantified how you define 'very constant' for the off-period, so hard to tell if clock drift would be a concern. You might use a temperature compensated oscillator on the Arduino of course if it's somewhat critical. Again, not clear at this point if the, let's say, 30ppm deviation of your typical quartz oscillator is going to be a problem. Looks like Atmega328p (assuming your Arduino is based on this...it's not specified either) can wake up fine from a Timer2 interrupt in several of it's power saving modes, so conceptually your idea should work. You may have to account for the couple of clock cycles it takes for the Atmega to wake up and actually start. The datasheet will give you the necessary information on this.

So I guess the question is mostly: how critical are these timings in an objective sense - i.e. can you quantify them? The more strict your requirements, the more complex it's going to be (obviously, as always...)

1 Like

You can run the hardware PWM in IDLE sleep mode.

1 Like

May be you don’t need an arduino and can fine tune something with a NE555 (or similar).

1 Like

Thanks for your reply! I'm not sure on how strict my timing needs to be just yet. It's for an IR break beam sensor to dect "motion" when the Led beam is broken. On one side (Tx) the Arduino turns the LED on at 20Hz but not really sure how long the LED will be on, shorter is better for the battery obviously. Ideally would like to have a .1% duty cycle.

Haven't figured out the Rx side but my understanding is that an IR receiver will be charging an appropriately sized cap and if the cap doesn't get charged (something is blocking the LED beam) the voltage goes low and that interrupt wakes the micro. I'd rather have a fast trigger and detect on the first missed pulse so at 20Hz that would mean the next pulse is coming 50ms after the start of the first pulse so probably need the times to be within 30mS of each other every pulse.

Yeah, ok, that's pretty clear. I'd recommend to actually start with the receiver and then engineer the transmitter based on the receiver's capabilities. This will help you to fill in the present unknowns.

1 Like

I don't think the timing of the pulses or their length needs to be anything better than "approximately" in this project. You can use the watchdog timer to wake the chip from its deepest sleep mode to achieve the lowest possible power during the off periods.

But you may be missing something very important. IR receivers are very susceptible to being triggered by ambient IR light levels, especially outdoors. So to reduce false triggering, their built-in circuits are tuned to respond only to IR light which has been modulated with a particular frequency, for example 38KHz. Therefore your IR transmitter must be modulated to the frequency expected by your receiver, otherwise it's signals will be ignored. IR receivers contain the necessary receiver chip, but IR transmitters are usually simply IR LEDs, so you will need to get the Arduino to modulate the led at the required frequency. This can be done by adjusting one of the PWM outputs to the correct frequency.

Where does this 20us come from.
Reliable beam-break over some distance (not specified) needs modulated IR.
And 3-pin receivers are relatively slow.
I think most of them need at least 15 pulses to output a LOW.
Leo..

A little late but I just ran across this.

The arduino timers can be set up to output a pwm directly to a pin and not use the processor at all. Thus once you set up the timer you can put the arduino to sleep and the timer will continue to output the pwm signal. To output a 20hz signal you will need to use Timer 1. Also a .1% duty cycle can easily be achieved. An excellent tutorial on using the timers can be found here: Secrets of Arduino PWM

Below I have posted a sketch that produces a 20hz phase correct PWM signal. While I did not need sleep. The processor is only used when adjusting the duty cycle. There is something like 6k steps between 0 and 100% duty cycle so much less than .1% per step.

/* ================= HEADER ==================
   PROJECT: Treadmill speed Control
            Using a MC-2100 controller that requires a 20 hz phase correct 
            PWM signal with a 0-85% dutycycle

   VERSION: 0.0.2

   IDE VERSION: 1.8.9

   HARDWARE: Nano (328p)
             Potentiometer
             MC-2100 REV.B Motor Controller
             Treadmill Motor
*/

// ================= CONSTANTS ================
constexpr uint8_t PWM_PIN = 9;
constexpr uint8_t SPEED_POT = A0;

// ================= VARIABLES ================


// ================================================================
// *                              SETUP                           *
// ================================================================

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

  // Initializes timer 1 to produce a 20 hz pwm
  init20hzPWM();

}// End setup()


// ================================================================
// *                       MAIN PROGRAM LOOP                      *
// ================================================================

void loop()
{
  applyDutyCycle(getDutyCycle());
  
}// End loop()


// ================================================================
// *                       getDutyCycle()                         *
// ================================================================

uint16_t getDutyCycle()
{
  constexpr uint16_t MIN_DUTY = 0;
  constexpr uint16_t MAX_DUTY = 5300; // 85% of TOP_COUNT
  uint16_t rawPot = analogRead(SPEED_POT);
  uint16_t dutyCycle = map(rawPot, 0, 1023, MIN_DUTY, MAX_DUTY);
  return dutyCycle;
}// End getDutyCycle()


// ================================================================
// *                       applyDutyCycle()                       *
// *                        *
// ================================================================

void applyDutyCycle(uint16_t dutyCycle)
{
  static uint16_t oldDutyCycle;
  if (oldDutyCycle != dutyCycle)
  { 
    oldDutyCycle = dutyCycle;
    
    // setting OCR1x applies dutyCycle
    OCR1A = dutyCycle;
  }
}// End applyDutyCycle()


// ================================================================
// *                       init20hzPWM()                          *
// *  Set up Timer1 for 20hz phase correct PWM output on pin 9    *
// ================================================================

void init20hzPWM()
{
  // clock divisor
  constexpr uint16_t PRESCALER = 64;

  // Desired Frequncy in Herz
  constexpr uint16_t FREQUENCY = 20; 
  
  // Formula derived from Secrets of Arduino PWM 
  // (http://www.righto.com/2009/07/secrets-of-arduino-pwm.html)
  constexpr uint16_t TOP_COUNT = F_CPU / PRESCALER / FREQUENCY / 2; 

  // Set prescaler to /64
  TCCR1B |= (1 << CS10) | (1 << CS11);
  
  // Set WGM mode 10 - phase correct pwm using ICR1 as TOP
  TCCR1A |= (1 << WGM11);  
  TCCR1B |= (1 << WGM13);
  ICR1 = TOP_COUNT;

  // Set Timer1 to output on pin 9(OC1A)
  TCCR1A |= (1 << COM1A1); 

  // setting OCR1x applies dutyCycle
  // initialize to 0(off)
  OCR1A = 0;   

}// End init20hzPWM()
1 Like