Go Down

Topic: How to create a 38 Khz pulse with arduino using timer or PWM? (Read 22578 times) previous topic - next topic

praky

Apr 22, 2012, 02:01 am Last Edit: Apr 22, 2012, 02:10 am by praky Reason: 1
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

a.d

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 http://maxembedded.wordpress.com/2011/07/14/avr-timers-ctc-mode/ 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.

Claghorn

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:

http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html

(but I moved it all to interrupts).
http://home.comcast.net/~tomhorsley/hardware/arduino/arduino.html

PeterH


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?
I only provide help via the forum - please do not contact me for private consultancy.

praky

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

a.d


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.

Grumpy_Mike

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: [Select]
/* 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
}

praky

#7
Apr 22, 2012, 11:16 pm Last Edit: Apr 22, 2012, 11:25 pm by praky Reason: 1
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?

Grumpy_Mike

Quote
Will the above code interfere with these?

No.

Quote
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.

Quote
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.

praky

Quote
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.

praky


Quote
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.

ErikEnglund

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

Nick Gammon

#12
Apr 23, 2012, 12:05 am Last Edit: Mar 14, 2013, 09:57 am by Nick Gammon Reason: 1
This code generates 38 KHz on pin D11 on the Mega2560:

Code: [Select]

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.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

praky

#13
Apr 23, 2012, 12:21 am Last Edit: Apr 23, 2012, 12:23 am by praky Reason: 1

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.

Nick Gammon

Code: [Select]
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).
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Go Up