This Arduino code was written to simulate the 5ms flashes from an Elster AS300P electricity meter, for testing a photodiode-based sensor.

A red LED is between the D9 pin and ground in series with a 470 Ohm resistor

// Elster AS300P Electricity Meter LED simulator
// according to the manual, the 880nm LED flashes for 5ms

// Our 5V Arduino Pro Mini runs at 16MHz
// this makes our undivided timers tick at 62.5ns

// we can divide this by 1024 using a prescaler - this makes a tick 64us

// we want a 5ms flash -> 5000us -> 78.125 ticks, we'll go with 78 :-)

// we use the overflow interupt, which will trigger at count = 65535 and a counter
// compare match interrupt which will trigger at 65535 - 78 = 65457 (0xffb1)

// the counter will overflow every 64us * 65536 = 4.2s
// so we'll get a 5ms flash every 4.2s, which is good for testing

// - - - - - - - - - - - - Not to scale - - - - - - - - - - - - 
//
//
//  0xffff-------> |          |          |          |
//                /|         /|         /|         /|
//               / |        / |        / |        / |
//              /  |       /  |       /  |       /  |
//  0xffb1---> /|  |      /|  |      /|  |      /|  |
//            / |  |     / |  |     / |  |     / |  |
//           /  |  |    /  |  |    /  |  |    /  |  |    /
//          /   |  |   /   |  |   /   |  |   /   |  |   /
//         /    |  |  /    |  |  /    |  |  /    |  |  /
//        /     |  | /     |  | /     |  | /     |  | /
//       /      |  |/      |  |/      |  |/      |  |/     
//  0-> --------------------------------------------------> Time
//              |  ^          ^          ^          ^
//                 These are the counter overflow interrupts; for
//              |  the 16-bit timer 1 this overflows at 0xffff
//                 For a 16MHz clock and maximum 1024 prescaler
//              |  this happens every ~4.2s. We turn off the LED
//
//              ^           ^         ^           ^
//              These are the compare A interrupts, we calculate
//              a value such that it will trigger 5ms before the
//              overflow (0xffb1 c.f. 0xffff). We turn on the LED

// interrupt service routine for compare mode, value A
ISR(TIMER1_COMPA_vect)
{
  // Turn on the LED on pin 9 (aka PB1)
  // this is quicker than digitalWrite
  PORTB |= _BV(PB1);
}

// interrupt service routine for overflow (counter > 65535)
ISR(TIMER1_OVF_vect)
{
  // Turn off the LED on pin 9 (aka PB1)
  // this is quicker than digitalWrite
  PORTB &= ~_BV(PB1);
}

void setup()
{
  // LED connected to D9 (aka PB1)
  pinMode(9, OUTPUT);

  // turn LED off 
  PORTB &= ~_BV(PB1);
  
  noInterrupts(); // disable all interrupts

  // clear the Time/Counter control registers (A and B) for Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  
  // set the clock pre-scaler for Timer 1 to 1024 (slowest)
  // this sets bits CS12 and CS10 (see TCCR1B Timer/Counter1 Control Register in ATmega328P manual)
  TCCR1B |= (1 << CS12)|(1 << CS10);  

  // set the Timer/Counter Interrupt Mask Register
  // (see Timer/Counter1 Interrupt Mask Register in ATmega328P manual)
  TIMSK1 |= (1 << TOIE1);   // Set Timer/Counter1, Overflow Interrupt Enable
  TIMSK1 |= (1 << OCIE1A);  // Set Timer/Counter1, Output Compare A Match Interrupt Enable

  // set the Compare A value to be 65457 (hex ffb1)
  OCR1AH = 0xff;
  OCR1AL = 0xb1;
  
  interrupts(); // enable all interrupts
}

void loop() {
  // nothing to see here!
}

Arduino home