30.9.09

Arduino Frequency Generation

Probably a useful read for anyone trying to accurately generate frequencies in the kHz range using an arduino.

I need to accurately produce 38kHz signals for IR communication projects.
Not all pins give the same frequency output for the same code.

Results in brief: avoid PWM pins if you are not actually using the PWM feature.
In my code instructions took about 4microseconds per half wave form cycle.

Full results after break:



Code Used:

// Frequency Testing: extract from upcoming arduino Miles Tag code.
// http://j44industries.blogspot.com/

// Signal Properties
int IRpulse = 600; // Basic pulse duration of 600uS MilesTag standard 4*IRpulse for header bit, 2*IRpulse for 1, 1*IRpulse for 0.
int IRfrequency = 38; // Frequency in kHz Standard values are: 38kHz, 40kHz. Choose dependant on your receiver characteristics
int IRt = 0; // LED on time to give correct transmission frequency, calculated in setup.
int IRpulses = 0; // Number of oscillations needed to make a full IRpulse, calculated in setup.
int header = 4; // Header lenght in pulses
int maxSPS = 10; // Maximum Shots Per Seconds. Not yet coded in.
int TBS = 0; // Time between shots

int IRtransmitPin = 13; // Primary fire mode IR transmitter pin


void setup() {
Serial.begin(9600);
pinMode(IRtransmitPin, OUTPUT);
frequencyCalculations(); // calculates pulse lengths for desired frequency
Serial.println("Ready");
}

void loop() {
sendPulse(IRtransmitPin, 10);
}


void sendPulse(int pin, int length){ //importing variables like this allows for secondary fire modes etc.
int i = 0;
int o = 0;
while( i < length ){
i++;
while( o < IRpulses ){
o++;
digitalWrite(pin, HIGH);
delayMicroseconds(IRt);
digitalWrite(pin, LOW);
delayMicroseconds(IRt);
}
}
}


void frequencyCalculations() {
IRt = (int) (500/IRfrequency);
IRpulses = (int) (IRpulse / (2*IRt));
IRt = IRt - 5;
// Why -5 I hear you cry. Answer it just worked best (on Pin 3) that way, presumably something to do with the time taken to perform instructions

Serial.print("Oscilation time period /2: ");
Serial.println(IRt);
Serial.print("Pulses: ");
Serial.println(IRpulses);
//timeOut = IRpulse + 50;
}



Results:

Half time period delay: 8 Micros
Theoretical Frequency (instructions executed infinitely fast): 62.5kHz

Same for both a roboduino Nano (168 chip) and Arduino Dumilnove (328 chip).

Pin Frequency (kHz)
D2 : 40.94
D3 (PWM) : 36.94
D4 : 40.94
D5 (PWM) : 38.00
D6 (PWM) : 38.18
D7 : 40.94
D8 : 40.94
D9 (PWM) : 38.93
D10 (PWM) : 38.75
D11 (PWM) : 37.12
D12 : 40.94
D13 : 40.94




Conclusion:
Do not use PWM pins and reduce half time period by 4 micros for accurate frequency replication.