How to create a 38 Khz pulse with arduino using timer or PWM?

I want to create a square wave of 38 KHz to be fed to an IR led.

One way is to make a pin high and low for 13 microseconds each. But I can not use that approach since this requires use of loop function.

My program is rather big and I would not be able to handle the complexities of doing other tasks as well as creating this 38 Khz wave both in loop() (if it can be done at all)

My question is, is there a way, by using a timer or something else to achieve this purpose? So that I can just start the timer in setup() and the pin in question will have 38Khz square as long as the program runs.

I am using ArduinoMEGA

Thanks

I don't have any experience with the Mega, but it looks like it has quite a few timers knocking about. It seems like it should be possible to take one of the unused timers and Have it toggle one of the OCxn pins.

Take a look at the timer section in the data sheet, and also have a look here AVR Timers – CTC Mode | maxEmbedded for more information on having a timer toggle a pin in the background purely through hardware.

Just make sure you don't tread on anything else that is using a particular timer, or there might be issues.

Sounds like the BackgroundIR class I wrote as part of my project is just what you need. It runs entirely at interrupt level from timer interrupts and pulls the length of the next pulse off a circular buffer you can fill at any time (if you don't wait too long, anyway :-).

You can find the latest version in the tarball pointed at here:

http://home.comcast.net/~tomhorsley/hardware/arduino/software.html

A lot of the code was adapted from:

(but I moved it all to interrupts).

praky:
I want to create a square wave of 38 KHz to be fed to an IR led.

Are you absolutely determined to do this in software? If not, have you considered doing it with a 555 timer?

If this can't be done in software then only I wish to go to a 555 timer.

praky:
If this can't be done in software then only I wish to go to a 555 timer.

You have several software options open to you. Or a 555 timer.

Yes you can do it with the timers with no overhead.
This code fires off an ISR every cycle but there is no need to do this:-

/* Code to pulse pin 3 with a modulated signal
* Can be used to drive an IR LED to keep a TSOP IR reciever happy
* This allows you to use a modulated reciever and a continious beam detector
* By Mike Cook Nov 2011 - Released under the Open Source licence
*/
 volatile byte pulse = 0;

ISR(TIMER2_COMPB_vect){  // Interrupt service routine to pulse the modulated pin 3
    pulse++;
  if(pulse >= 8) { // change number for number of modulation cycles in a pulse
    pulse =0;
    TCCR2A ^= _BV(COM2B1); // toggle pin 3 enable, turning the pin on and off
  }
}

void setIrModOutput(){  // sets pin 3 going at the IR modulation rate
  pinMode(3, OUTPUT);
  TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // Just enable output on Pin 3 and disable it on Pin 11
  TCCR2B = _BV(WGM22) | _BV(CS22);
  OCR2A = 51; // defines the frequency 51 = 38.4 KHz, 54 = 36.2 KHz, 58 = 34 KHz, 62 = 32 KHz
  OCR2B = 26;  // deines the duty cycle - Half the OCR2A value for 50%
  TCCR2B = TCCR2B & 0b00111000 | 0x2; // select a prescale value of 8:1 of the system clock
}

void setup(){
  setIrModOutput();
  TIMSK2 = _BV(OCIE2B); // Output Compare Match B Interrupt Enable
}

void loop(){
// do something here
}

Ok. I will try this. But please note that I also make use of serial communication (Serial & Serial1) and a single interrupt(0) in my code.

Will the above code interfere with these?

since you code uses interrupt which interrupt I can't utilize in further coding?

Also I understand pin 3 and pin 11 cannot be use for any other purpose. Any other pins used and not available?

Will the above code interfere with these?

No.

since you code uses interrupt which interrupt I can't utilize in further coding?

As the code uses pin 3 you can't use that pin as an interrupt, but if that is a problem just change it to use pin 11 instead of pin 3.

Also I understand pin 3 and pin 11 cannot be use for any other purpose

If that is what you understand then you are wrong.

This code fires off an ISR every cycle but there is no need to do this:-

What do you mean by that?

P.s. I am no pro in assembly programming with avr. Though I know assembly with 8085 and 8051.

Grumpy_Mike:

Also I understand pin 3 and pin 11 cannot be use for any other purpose

If that is what you understand then you are wrong.

Please explain. I am not an experienced coder.

I see in the comments that pin 11 is being disabled for the output that why i said i t is not available for use.
As for pin 3, i meant that since the 38 Khz wave will be available on that pin, it has been made use of.

Why not just use the Tone() function?
http://arduino.cc/en/Reference/Tone

This code generates 38 KHz on pin D11 on the Mega2560:

const byte LED = 11;  // Timer 2 "A" output: OC2A

void setup() {
  pinMode (LED, OUTPUT);
  
  // set up Timer 2
  TCCR2A = _BV (COM2A0) | _BV(WGM21);  // CTC, toggle OC2A on Compare Match
  TCCR2B = _BV (CS20);   // No prescaler
  OCR2A =  209;          // compare A register value (210 * clock speed)
                         //  = 13.125 nS , so frequency is 1 / (2 * 13.125) = 38095

}  // end of setup

void loop() { }

It does not use interrupts and does not interfere with any other pin.

(edit) Changed from D10 to D11. OC2A outputs on D11.

ErikEnglund:
Why not just use the Tone() function?
http://arduino.cc/en/Reference/Tone

This looks interesting!! and hugely simplistic.

Can this produce a freq. as large as 38 Khz? In the example they are using quite low frequencies. will test this tomorrow.

void setup ()
{
tone (10, 38000);
}
void loop () {}

That generates a 38 KHz output, more or less. However it's not as smooth as the hardware timer.

The tone library uses a timer, but that causes an interrupt. Inside the interrupt it does a counter. When the counter is met it toggles the pin. So there is a bit of jitter (because other interrupts might fire), and it consumes CPU resources.

The pure hardware solution described above runs without any code being called at all (once you set it up).

Thanks for the explanation. This method it is, then!

I used the following 2 fxn to measure frequency using your (nick gammon's timer method) code.

long getFrequencySampled()
{
#define SAMPLES 4096
long freq = 0;
for(unsigned int j=0; j<SAMPLES; j++) freq+= 500000/pulseIn(pin, HIGH, 250000);
return freq / SAMPLES;
}

long getFrequency()
{
long duration=pulseIn(pin, HIGH, 250000);
Serial.print("duration of pulse is: ");
Serial.println(duration); //in microseconds
duration=duration*2;
Serial.print("duration of pulse is: ");
Serial.println(duration); //in microseconds
freq = 1000000/duration;
Serial.print("Frequency is: ");
Serial.println(freq);

return freq;
}

getFrequencySampled() returned a value of 40.5-41 Khz.
getFrequency() returns a value that alternates randomly between 35 Khz and 41 Khz. (for pulse durations of 12 & 14 microseconds)

Any idea why the frequency doesn't equal the theoretical value?

praky:
long duration=pulseIn(pin, HIGH, 250000);

My code doesn't use pulseIn. Can you post the whole sketch?

I used pulseIn to measure the freq.

Here is the whole code...

const int pin = 7;
unsigned long duration;
long x;
long freq;
const byte LED = 10;  // Timer 2 "A" output: OC2A
void setup()
{
  pinMode(pin, INPUT);
  Serial.begin(9600);
  
  //
  pinMode (LED, OUTPUT);
  
  // set up Timer 2
  TCCR2A = _BV (COM2A0) | _BV(WGM21);  // CTC, toggle OC2A on Compare Match
  TCCR2B = _BV (CS20);   // No prescaler
  OCR2A =  209;          // compare A register value (210 * clock speed)
                         //  = 13.125 nS , so frequency is 1 / (2 * 13.125) = 38095
  
//  tone (10, 38000);
}
long getFrequency() 
{
  long duration=pulseIn(pin, HIGH, 250000);
  Serial.print("duration of pulse is: ");
  Serial.println(duration);  //in microseconds
  duration=duration*2;
  Serial.print("duration of pulse is: ");
  Serial.println(duration);  //in microseconds
  freq = 1000000/duration;
  Serial.print("Frequency is: ");
  Serial.println(freq);
  
  return freq;
}
void loop()
{
  x=getFrequency();
  Serial.print("Frequency is: ");
  Serial.println(x);
  
}
long getFrequencySampled() 
{
  #define SAMPLES 4096
  long freq = 0;
  for(unsigned int j=0; j<SAMPLES; j++) freq+= 500000/pulseIn(pin, HIGH, 250000);
  return freq / SAMPLES;
}

Is it possible to create a 38 khz modulated wave by the same method?