Go Down

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

#### nickgammon

#30
##### Apr 26, 2012, 07:54 amLast Edit: Apr 26, 2012, 09:08 am by Nick Gammon Reason: 1
Yes you could do that. But this does it with only one pin:

Code: [Select]
`const byte LED = 9;  // Timer 1 "A" output: OC1AISR (TIMER2_COMPA_vect){   TCCR1A ^= _BV (COM1A0) ;  // Toggle OC1A on Compare Match     if ((TCCR1A & _BV (COM1A0)) == 0)     digitalWrite (LED, LOW);  // ensure off     }  // end of TIMER2_COMPA_vectvoid setup() {  pinMode (LED, OUTPUT);    // set up Timer 1 - gives us 38.095 MHz (correction: 38.095 KHz)  TCCR1A = 0;  TCCR1B = _BV(WGM12) | _BV (CS10);   // CTC, No prescaler  OCR1A =  209;          // compare A register value (210 * clock speed)                         //  = 13.125 nS , so frequency is 1 / (2 * 13.125) = 38095    // Timer 2 - gives us our 1 mS counting interval  // 16 MHz clock (62.5 nS per tick) - prescaled by 128  //  counter increments every 8 uS.  // So we count 125 of them, giving exactly 1000 uS (1 mS)  TCCR2A = _BV (WGM21) ;   // CTC mode  OCR2A  = 124;            // count up to 125  (zero relative!!!!)  TIMSK2 = _BV (OCIE2A);   // enable Timer2 Interrupt  TCCR2B =  _BV (CS20) | _BV (CS22) ;  // prescaler of 128}  // end of setupvoid loop()  {  // all done by interrupts  }`

Output (pin D9 this time):

There is your 38 KHz signal pulsed at 1 KHz.
Please post technical questions on the forum, not by personal message. Thanks!

#### praky

#31
##### Apr 26, 2012, 08:37 am
Can't thank you enough mate.

Just one question, Since Timer 2 is assigned pins 9 & 10, I won't use them for other purposes as a precaution while using this code. Any pther precaution?

Again, thanks a lot mate.

#### AWOL

#32
##### Apr 26, 2012, 08:43 am
Code: [Select]
`// set up Timer 1 - gives us 38.095 MHz`
!
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

#### nickgammon

#33
##### Apr 26, 2012, 09:02 am
Ah yes, I just put that there to make sure everyone was paying attention.

That should read 38.095 KHz.
Please post technical questions on the forum, not by personal message. Thanks!

#### nickgammon

#34
##### Apr 26, 2012, 09:04 am
Come to think of it, it would be surprising to get a 38 MHz pulse out of a 16 MHz processor.
Please post technical questions on the forum, not by personal message. Thanks!

#### nickgammon

#35
##### Apr 26, 2012, 09:11 am

Just one question, Since Timer 2 is assigned pins 9 & 10, I won't use them for other purposes as a precaution while using this code. Any pther precaution?

The latest version, above, only uses pin 9. Feel free to use the other pins for whatever you want. Other precautions? Avoid bad dates.
Please post technical questions on the forum, not by personal message. Thanks!

#### praky

#36
##### Apr 26, 2012, 09:54 amLast Edit: Apr 26, 2012, 09:56 am by praky Reason: 1

Just one question, Since Timer 2 is assigned pins 9 & 10, I won't use them for other purposes as a precaution while using this code. Any pther precaution?

Other precautions? Avoid bad dates.

#### scottyjr

#37
##### Aug 05, 2012, 12:37 am
Hello Nick. The project I am working on is currently using the TLC5940 library and the IRremote library. The two both utilize pin 2 on the Uno. Within the IRremote library I found a place to designate the IR output pin to pin 9.

// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
#else
#define IR_USE_TIMER1   // tx = pin 9 //uncommented for Tlc5940 project
//#define IR_USE_TIMER2     // tx = pin 3 //commented for Tlc5940 project

However, the TLC5940 library also uses pin 9.

I've been poking around the net for a couple of days now seeking a solution and just recently came across your post using this code:

Code: [Select]
`const byte LED = 10;  // Timer 2 "A" output: OC2Avoid 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 setupvoid loop() { }`

Could this code be adapted for use on a Uno and not use pins 3 or 9? - Scotty

#### nickgammon

#38
##### Aug 05, 2012, 02:27 am
As described in here: http://www.gammon.com.au/forum/?id=11504

The timer pins are:

Code: [Select]
`Timer 0input     T0     pin  6  (D4)output    OC0A   pin 12  (D6)output    OC0B   pin 11  (D5)Timer 1input     T1     pin 11  (D5)output    OC1A   pin 15  (D9)output    OC1B   pin 16  (D10)Timer 2output    OC2A   pin 17  (D11)output    OC2B   pin  5  (D3)`
Please post technical questions on the forum, not by personal message. Thanks!

#### cordvision

#39
##### Sep 24, 2012, 01:13 amLast Edit: Sep 24, 2012, 04:34 am by cordvision Reason: 1
Hello Everybody
I have a little issue, and I just can't get it worked out. I already spent a good amount of time on it but I'm still super new to the Arduino board.

I would like to pulse width modulate a 38kHz carrier signal at 500hz, and adjust the duty cycle of the 500hz signal by reading a value from a potentiometer (value between 256 and 0 (100% to 0% duty cycle)).

So far, I came up with the code bellow, which does the following: It uses the tone() command to output a 38kHz signal on pin 11 and uses the delayMicroseconds() command to modulate it at 500hz. By
adjusting the delays for the on/off period of the 38kHz signal (by using a value I get from the Potentiometer), I can adjust the duty cycle of the 500hz modulated signal. (In the example below, I have 2048 increments by which I can adjust the duty cycle, but I would only need 256.)

Code: [Select]
`void loop () {  Bval = analogRead(PodPin) * 2;//(Read Potentiometer, then multiplay value by x2 and store it in "Bval" (Value will be between 0 and 2048)tone(11,38000);//create 38kHz signal on pin 11)delayMicroseconds(Bval);//delay for "Bval" microsecondsnoTone(11);//turn off 38kHz signal on pin 11delayMicroseconds(2048 - Bval);//delay for "2048 - Bval" microseconds.}`

For some reason, my code doesn't work very reliable. My guess would be that everything is extremely "time sensitive" and by doing it with "delays" it will never be very accurate. I think it should be possible to do it much more reliably with timers but I just can't get it to work (I tried to play with code posted above by Nick Gammon, but didn't have much luck yet). Any chance somebody could help me on this? I would greatly appreciate any input...

PS: I have an Arduino Uno

#### nickgammon

#40
##### Sep 24, 2012, 06:28 amLast Edit: Sep 24, 2012, 07:16 am by Nick Gammon Reason: 1
Code: [Select]
`// Example of modulating a 38 KHz frequency duty cycle by reading a potentiometer// Author: Nick Gammon// Date: 24 September 2012const byte POTENTIOMETER = A0;const byte LED = 10;  // Timer 1 "B" output: OC1B// 16 MHz clock divided by 38 KHz frequency desiredconst long timer1_OCR1A_Setting = 16000000L / 38000L;void setup() {  pinMode (LED, OUTPUT);  // set up Timer 1 - gives us 38.005 KHz  // Fast PWM top at OCR1A  TCCR1A = _BV (WGM10) | _BV (WGM11) | _BV (COM1B1); // fast PWM, clear OC1B on compare  TCCR1B = _BV (WGM12) | _BV (WGM13) | _BV (CS10);   // fast PWM, no prescaler  OCR1A =  timer1_OCR1A_Setting - 1;                 // zero relative    }  // end of setupvoid loop()  {  // alter Timer 1 duty cycle in accordance with pot reading  OCR1B = (((long) (analogRead (POTENTIOMETER) + 1) * timer1_OCR1A_Setting) / 1024L) - 1;    // do other stuff here  }`

That uses the hardware timer to output 38 KHz and modulates the duty cycle in hardware based on a pot reading.

Example:

Note the frequency is correct and in this particular case I have a 27% duty cycle.
Please post technical questions on the forum, not by personal message. Thanks!

#### nickgammon

#41
##### Sep 24, 2012, 07:23 am
My code above is a bit dodgy at the edge conditions (pot at zero or 1023). They should really be detected and translated into some other output. After all, modulating with 100% duty cycle (or 0%) doesn't make any sense. That's because 100% on or 0% on isn't actually modulating at all.
Please post technical questions on the forum, not by personal message. Thanks!

#### nickgammon

#42
##### Sep 24, 2012, 07:39 am
Quote
I would like to pulse width modulate a 38kHz carrier signal at 500hz, and adjust the duty cycle of the 500hz signal by reading a value from a potentiometer (value between 256 and 0 (100% to 0% duty cycle)).

Looks like I answered the wrong question. Give me a bit of time to do the correct answer ...
Please post technical questions on the forum, not by personal message. Thanks!

#### nickgammon

#43
##### Sep 24, 2012, 08:22 am
I think I got it this time. You want a standard 38 KHz pulse, which itself turns on and off at 500 Hz with a duty cycle controlled by a pot? This seems to do it:

Code: [Select]
`// Example of modulating a 38 KHz carrier frequency at 500 Hz with a variable duty cycle// Author: Nick Gammon// Date: 24 September 2012const byte POTENTIOMETER = A0;const byte LED = 9;  // Timer 1 "A" output: OC1A// 16 MHz clock divided by 500 Hz frequency desired (allowing for prescaler of 128)const long timer2_OCR2A_Setting = 16000000L / 500L / 128L;ISR (PCINT2_vect)   {       // if pin 3 now high, turn on toggling of OC1A on compare   if (PIND & _BV (3))     {     TCCR1A |= _BV (COM1A0) ;  // Toggle OC1A on Compare Match     }   else     {     TCCR1A &= ~_BV (COM1A0) ;  // DO NOT Toggle OC1A on Compare Match     digitalWrite (LED, LOW);  // ensure off     }  // end of if        }  // end of PCINT2_vectvoid setup() {  pinMode (LED, OUTPUT);  pinMode (3, OUTPUT);  // OC2B    // set up Timer 1 - gives us 38.095 KHz  TCCR1A = 0;   TCCR1B = _BV(WGM12) | _BV (CS10);   // CTC, No prescaler  OCR1A =  (16000000L / 38000L / 2) - 1;  // zero relative    // Timer 2 - gives us our 1 mS counting interval  // 16 MHz clock (62.5 nS per tick) - prescaled by 128  //  counter increments every 8 uS.   // So we count 250 of them, giving exactly 2000 uS (2 mS period = 500 Hz frequency)  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1);   // Fast PWM mode  TCCR2B = _BV (WGM22) | _BV (CS20) | _BV (CS22) ;  // prescaler of 128  OCR2A  = timer2_OCR2A_Setting - 1;                // count up to 250  (zero relative!!!!)    // pin change interrupt  PCMSK2 |= _BV (PCINT19);  // want pin 3  PCIFR  |= _BV (PCIF2);    // clear any outstanding interrupts  PCICR  |= _BV (PCIE2);    // enable pin change interrupts for D0 to D7  }  // end of setupvoid loop()  {  // alter Timer 2 duty cycle in accordance with pot reading  OCR2B = (((long) (analogRead (POTENTIOMETER) + 1) * timer2_OCR2A_Setting) / 1024L) - 1;  // other stuff here  }  // end of loop`

Results:

I am outputting 38 Khz on pin 9 (output of timer 1 "A" side) and turning that on and off with a pin-change interrupt. The interrupt is generated by timer 2 "B" side which is the output of a fast PWM 500 Hz timer where the duty cycle is variable by the potentiometer input.

You can see from the image when pin 3 (timer 2) goes on and off (in this case with a 24.8% duty cycle) and that the 38 KHz signal on pin 9 is switched on and off corresponding to that.
Please post technical questions on the forum, not by personal message. Thanks!