Arduino Output Wacky at Low Frequencies

I'm working on a project that needs to output a signal from the Arduino at different frequencies. Output frequencies above 1 kHz work fine, but we get aberrant readings on our oscilloscope for low frequencies; for instance, 10 Hz yields an output of 500Hz. The value the Arduino outputs compared to what we want seems to be random, so we can't modify our code to account for that. Worse, it holds even upon switching our Arduino UNO out for another one - and they will output different frequencies for he same 10 Hz! Here is our code:

/*
FT of square wave:
First delta at 0
Second delta at 1/T
Third at 2*1/T
*/

long T = 1000;
long duty = 50;
long T1 = T*duty/100;

void setup()
{
  pinMode(12, OUTPUT);
}

void loop()
{
  digitalWrite(12, HIGH);
  delayMicroseconds(T1);
  digitalWrite(12, LOW);
  delayMicroseconds(T - T1);
}

Any help would be greatly appreciated!

This might be the cause of your problem. You might be overflowing the input to DelayMicroseconds().

http://arduino.cc/hu/Reference/DelayMicroseconds

Description Pauses the program for the amount of time (in microseconds) specified as parameter. There are a thousand microseconds in a millisecond, and a million microseconds in a second. Currently, the largest value that will produce an accurate delay is 16383. This could change in future Arduino releases. For delays longer than a few thousand microseconds, you should use delay() instead.

Those #s don't yield 10 Hz tho. 1/10 = 0.1, or 100000uS. 50000uS high & low. T1 = 1000*50/100 = 500 so 500 low, 500 high = 1000uS cycle = 0.1mS = 1000Hz

high frequencies => small delays:

think the rounding of the integer math might cause errors, that + the granularity of the delayMicroseconds of 4 micros().

t=10 t1=10*50/100 = 5 => 8 or 4 t=9 t1 = 9*50/100 = 4 t=8 t1 = 8*50/100 = 4

For really small delays you need to check out direct port manipulation and other timing e.g. assembler nops

low frequencies => large delays The delayMicros() overflows at 65535 (IDE 0.22/1.0) as the param is an unsigned int and not an unsigned long!!

Give this a try...

/*
FT of square wave:
First delta at 0
Second delta at 1/T
Third at 2*1/T
*/

long T = 1000;
long duty = 50;
long T1 = T*duty/100;

unsigned long T1m = T1 /1000;  // time in millis()
unsigned int T1r = T1 %1000;  // remainder
unsigned long T2 = T - T1;
unsigned long T2m = T2 /1000;  // time in millis()
unsigned int T2r = T2 %1000;

void setup()
{
  pinMode(12, OUTPUT);
}

void loop()
{
  digitalWrite(12, HIGH);
  delay(T1m);
  delayMicroseconds(T1r);

  digitalWrite(12, LOW);
  delay(T2m);
  delayMicroseconds(T2r);
}

or define your own _delayMicros(), something like this..

void delayMicros(unsigned long us)
{
   uint32_t  a = micros() + 4 ; // + 4 is for finetuning, increase in steps of 4 :)
   while (micros() - us >= a); 
}