Variable Frequency 50% Duty Cycle Square Wave

I've got an inelegant solution to a problem, but I'd love some input from other people.

I'm trying to design (and in the near future, build) some vision research equipment. This sounds like it should be the easiest thing to do, but I need to get it to turn on and off with a 50% duty cycle square wave. The issue is I need to be able to control the frequency over a wide range (probably 1Hz to 100Hz) with a high level of precision (preferably +/- 0.01Hz, but I'd be alright with +/- 0.1Hz) without bogging down the Arduino for too long and preventing it from handling sensor input for long.

The current (probably awful) plan is as follows:

  • Arduino sets the values for daisy chained SPI/I2C controlled digital pots rigged up in series.
  • The digital pots change the frequency of a 555 timer astable multivibrator.
  • The output from the 555 timer is fed into a JK or D type flip flop, generating a 50% duty cycle square wave at half of the 555 timer's output frequency. (Multiple flip flops can be used to further half the output frequency while maintaining the 50% duty cycle.)
  • pulseIn() is periodically called to sample the output of the final flip flop (averaged) and see if the digital pots need to be adjusted to correct the frequency.
  • When it's not actively sampling or adjusting the output frequency, the Arduino can handle data output, sensor input, etc.

From here, the questions I have are:

  • Is there a better way to generate the initial frequency than the 555 timer that won't require continuous input from the Arduino?
  • Is there a better way to adjust the frequency of a 555 timer (or other astable multivibrator).
  • Am I missing anything obvious?

Thanks in advance to anyone with any suggestions.

Why not let the Arduino generate the square wave? - -

It can generate an IRQ 1000 times per second (probably faster if you use micros internally)

(code not tested)

#include <MsTimer2.h>

#define SQW_PIN 6

int freq = 0;

void toggle() 
  static boolean state = HIGH;
  digitalWrite(SQW_PIN , state );
  state = !state;

void setup()
  pinMode(SQW_PIN, OUTPUT);
  freq = readPotMeter();  //To be elaborated
  MsTimer2::set(freq, toggle); // 500ms period

void loop()
  int newFreq = readPotMeter();  //To be elaborated
  if (newFreq != freq)
     freq = newFreq;
    MsTimer2::set(freq, toggle); // 500ms period

I think you might be better off using one of the Arduino's built-in timers. You can have 16-bit Timer/Counter1 directly toggle an output pin each time the timer reaches a value you set (no need for interrupts).

The output frequency depends on how fast you step the timer (16 MHz, 2 MHz, 250 KHz, 62.5 KHz, or 15.625 KHz) divided by the timer limit (1 to 65536). The output is toggled each interval so the output frequency is half the timer frequency. This gives a range from 8 MHz ((16/1)/2) to 0.12 Hz ((15,625 Hz / 65536) / 2).

The higher the base clock rate the more finely spaced the clock ticks but each range has a limit as to how low a frequency you can get:

16 MHz goes down to 122 Hz so it won't help in your case 2 MHz goes down to 15.25 Hz 250 KHz goes down to 1.9 Hz 62.5 KHz goes down to 0.48 Hz 15.625 KH goes down to 0.12 Hz

There are libraries to help with timer 1 setup:

First, thanks for the quick reply.

Second, I hadn't read about the MsTimer2, which looks pretty cool, so thanks for that as well.

Unfortunately, being able to increment/decrement the delay by 1ms works really well at very low frequencies, but changing the delay value by 1ms can cause a frequency change which is too high for my needs (e.g. 6ms to 5ms delay = 83.333Hz to 100Hz change). I don't think this is a feasible solution for my needs.

Thanks again, though.

Google "phase accumulator"

johnwasser, thanks for info. I've never played around with changing the frequencies in the Arduino, but now's as good of a time to learn as any.

AWOL, I'd never heard of a phase accumulator, so I've got a lot of reading to do. Thank you.

Apologies for awakening such an old post, but can anyone tell me whether this method of generating a tone would be affected by the need to receive and process serial data?

I've replied to this thread because the code above looks like it is interrupt driven and as such seems to be ideal for my use. It may not cause issues, but as I'm a newbie I'm not sure and would appreciate the confirmation or pointers.

My application would use a GPS receiver, extract the speed over ground value from a serial data stream, do some calculations and then update the tone (frequency) output periodically in order to drive a pulse driven analogue speedometer. Therefore I would want the tone output to continue without glitches until updated, irrespective of what the Arduino is doing at the time.

I'll experiment with it, but I know I'll struggle to prove it is correct without better test equipment.

Many thanks. :-)