Hello guys.
After hours spent on the internet trying to understand how stuff works i came up with this piece of code. It simply sends out SONY remote codes, but the cool thing is that it does this in background, meaning that while your MCU sends out the code, you can carry on with your main loop, and you don't have to wait till the code has been sent to carry on with you sketch.
Even if this code sends out SONY codes, it can be easily adapted to send other protocols or even work at different frequencies and/or duty cycles (current is 50%). Here is the code...and please tell me if there's something you don't understand (i am willing to explain the different parts it's made of as soon as i have more time ;=) ).
Oh wait...i forgot to tell you how to use it. This is the function you're looking for: SonyIR(x, n). x is the code you want to send, while n is the number of bits it is made of. In the below example im sending it 3 times at a constant interval, because SONY "things" (tvs, recorders, etc..) only accept the code if repeated 3 times. You can use this code in combination with Ken Shirriff's library for receiving sony codes found at www.arcfn.com (got a lot of inspiration from his library).
#define TOPBIT 0x80000000
int timertx=0; int resettx=0; int bitstx=0; float elapsed=0; unsigned long datatx=0; boolean spacetx = false;
void setup(){
//set PWM: FastPWM, OC2A as top, OC2B sets at bottom, clears on compare //COM2B1=1 sets PWM active on pin3, COM2B1=0 disables it //Serial.begin(9600); pinMode(3, OUTPUT); pinMode(11, OUTPUT); TCCR2A = _BV(WGM21) | _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS21); OCR2A = 49; OCR2B = 24; delay(500);
}
void loop(){
delay(2500); elapsed=micros(); SonyIR(0xa90, 12); elapsed=45-((micros()-elapsed)/1000); delay(elapsed); SonyIR(0xa90, 12); delay(elapsed); SonyIR(0xa90, 12);
}
boolean SonyIR(unsigned long data, int nbits) {
if(bitstx == 0) { //if IDLE then transmit timertx=0; //reset timer TIMSK2 |= _BV(TOIE2); //activate interrupt on overflow (TOV flag, triggers at OCR2A) resettx=96; //initial header pulse is 2400us long. 2400/25us ticks = 96 spacetx = false; datatx=data << (32 - (nbits + 1)); //unsigned long is 32 bits. data gets shifted so that the leftmost (MSB) will be the first of the 32. TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output for transmission of header bitstx=nbits + 1; //bits left to transmit, including header return true; } else { return false; }
}
ISR(TIMER2_OVF_vect, ISR_NOBLOCK){
//RESET_TIMER2;
//TRANSMISSION
if(bitstx != 0) { //if we have got something to transmit
timertx++; if(timertx >= resettx) { //if reset value is reached
timertx=0; if(spacetx){ //it was a space that has just been sent thus a total "set" (bit + space) so.. spacetx = false; //we are not going to send a space now bitstx = bitstx - 1; //we got 1 less bit to send datatx <<= 1; //shift it so MSB becomes 1st digit TCCR2A |= _BV(COM2B1); //activate pin 3 PWM (ONE) if((datatx & TOPBIT)&&(bitstx != 0)) { resettx = 48; } else if(!(datatx & TOPBIT)&&(bitstx != 0)){ resettx = 24; } else{ TCCR2A &= ~(_BV(COM2B1)); //deactivate pin 3 PWM (end of transmission, no more bits to send) TIMSK2 &= ~(_BV(TOIE2)); //deactivate interrupts on overflow } } else { //we sent the bit, now we have to "send" the space spacetx = true; //we are sending a space resettx = 24; //600us/25us = 24 TCCR2A &= ~(_BV(COM2B1)); } } }
}
EDIT:
Just wanted to add a quick explanation on how that ISR function works. Basically in the setup function, i've started a timer (timer2 to be precise) which is basically a value that increments very rapidily, starting from 0 of course. Now, when this value reaches the value of OCR2A (check out the setup function), an overflow occurs and the timing value goes back to zero, and so on until it reaches OCR2A again. Now, by setting TIMSK2 |= _BV(TOIE2) in the SonyIR function i'm basically setting to 1 the TOIE2 bit in the TIMSK2 register, and if you check the manual, this corresponds to activating the ISR (or interrupt service routine) on overflow. This means that when an overflow occurs (aka timing value reaches OCR2A in our case), the ISR function is called. Basically an ISR is a function that occurs every "x" microsecond/millisecond, depending on how you set OCR2A and other stuff (like prescaling factors).
In the above code, the ISR takes place every 25 microseconds.