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

@nick
Your code produces output at pin 10 using timer 2. Can't I similarly produce output of 1 KHz using Timer1 at some other pin? Then connect this pin at the other end of led?

Yes you could do that. But this does it with only one pin:

const byte LED = 9;  // Timer 1 "A" output: OC1A

ISR (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_vect

void 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 setup

void loop()
  {
  // all done by interrupts 
  }

Output (pin D9 this time):

There is your 38 KHz signal pulsed at 1 KHz.

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.

// set up Timer 1 - gives us 38.095 MHz

!

Ah yes, I just put that there to make sure everyone was paying attention. :slight_smile:

That should read 38.095 KHz.

Come to think of it, it would be surprising to get a 38 MHz pulse out of a 16 MHz processor.

praky:
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.

:smiley:

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:

const byte LED = 10;  // 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() { }

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

As described in here: http://www.gammon.com.au/forum/?id=11504

The timer pins are:

Timer 0

input     T0     pin  6  (D4)

output    OC0A   pin 12  (D6)
output    OC0B   pin 11  (D5)

Timer 1

input     T1     pin 11  (D5)

output    OC1A   pin 15  (D9)
output    OC1B   pin 16  (D10)

Timer 2

output    OC2A   pin 17  (D11)
output    OC2B   pin  5  (D3)

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

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" microseconds

noTone(11);
//turn off 38kHz signal on pin 11

delayMicroseconds(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

// Example of modulating a 38 KHz frequency duty cycle by reading a potentiometer
// Author: Nick Gammon
// Date: 24 September 2012

const byte POTENTIOMETER = A0;
const byte LED = 10;  // Timer 1 "B" output: OC1B

// 16 MHz clock divided by 38 KHz frequency desired
const 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 setup

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

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.

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

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:

// Example of modulating a 38 KHz carrier frequency at 500 Hz with a variable duty cycle
// Author: Nick Gammon
// Date: 24 September 2012


const 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_vect


void 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 setup

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

That's awesome, I can't thank you enough. Looking at what it took, I don't think I would have been able to write this myself anytime soon. If I can ever return a favor, let me know (I don't have any programing knowledge but a lot of video/photography knowledge). Thank you so so much again... I really appreciate it :slight_smile:

I am experimenting with an infra red remote, sending my normal data that I usually send by radio modules, using VirtualWire, or maybe EasyTransfer later.

I am driving the base of an LED driver transistor , ( via a resistor ) with 38 Khz from a similar timer generator as Nicks ( but with one of 2 outputs for some reason dirt cheap wireless | CHEAP, FAT and OPEN ? )

The data I take from another pin ( using NewSoftSerial) to the base of the transistor with a diode chopping the 38 Khz stream.

It is working fine, and I want to try Nicks idea of reducing the duty cycle to pump the IREDs harder.
I am only sending a few bytes at a time at 2400 baud, and can afford to have 100mS gap between bursts to keep the average drive down a bit too.

I see the background 38Khz is all done in setup.

What are the implications with this if I want my remote to go into sleep mode ? ( The remote is 4.5 v battery operated )

This is my general enter sleep routine that I blatantly copied from Crossroads, with little knowledge of how it works :-

void enterSleep()


{
     
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, LOW);
  delay(50); // need this?
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // setting up for sleep ...
  sleep_enable();                       // setting up for sleep ...
  ADCSRA &= ~(1 << ADEN);
  PRR = 0xFF;
  sleep_mode();                         // now goes to Sleep and waits for the interrupt

  //************************************************************************************
  /* The program will continue from here after the interrupt. */
  detachInterrupt(0);                 //disable interrupts while we get ready to read the keypad 
  PRR = 0x00;
  /* First thing to do is disable sleep. */
  sleep_disable(); 
  
}  // end of  enterSleep()  function

Implications? Some sleep modes stop the timers, if that is what you are asking.

Hi Nick
Yes thats what I am asking really, I dont know if ADCSRA &= ~(1 << ADEN); and PRR = 0xFF; stop the timers.

And whether I can set the data and 38Khz pins high with pullups before sleeping ? ( I have a PNP driver transistor which would switch off )

I was trying to save some precious time, I guess I will write some code , connect an ammeter and suck it and see ! :slight_smile:

Nick, could you indulge me and explain how I might send some information as opposed to just modulating the carrier wave at some frequency? For example, I would like to have a network of basic sensors that would each have a unique identifying ID number that, when sent, would tell the mother ship 'here I am and I have reached the limit!'.