// 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
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
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
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!'.
I could but it seems like they are very long numbers and I only need 40 or so distinct numbers. Also, I am trying to use an attiny so the library won't work. I'm not really trying to get you to do the work for me but I have a more reductionist approach to learning so having something to dismantle is immensely helpful.
Yes, but the library lets you send raw protocols (ie. a series of bits).
The low-level output might need tweaking for the Attiny, but the rest should be the same. You basically want to break your data down into X bits, and then send those bits, right?
Oh My Gosh!
"If you're going to use it for modulated IR, just connect one end of your LED to your constant 38kHz source, and the other end to another output pin.
Waggling the other output pin at your desired (<38kHz!) rate produces a modulated 38kHz IR beam."
AWOL, dude you are a genius. I was thinking about doing a logic gate for that. That is so dang simplistic and perfect. You can just have the the direction of the led to invert the signal. This is great. Thank you!