Arduino Playground is read-only starting December 31st, 2018. For more info please look at this Forum Post

Multitasked IR transmission

Overview

This sketch lets you transmit a Sony remote code, and its main feature is that the sending function works in background, and that's why i decided to call it "multitasked transmission".

How to use it

 Software

All you have to do to send the Sony code is specify the code itself of course, and the number of bits you wish to transmit. The maximum code lenght is 32 bits, since the datatx variable is unsigned long (of course you can modify it if you need a longer code). In case you want this code to talk to a Sony device remember that for it to "understand" the code, it must be sent 3 times, and there must be a delay of 45 milliseconds between the start of each transmission (the coding for this is already included below). You can also use the code to transmit data to another arduino. (for reception you can use this library by Ken Shirriff: http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html)

 Hardware

You must connect an IR led on pin3. Remember to put a resistor in series.

More info

The library uses timer2 both to work in background (by calling an ISR with a frequency of 40KHZ, or once every 25us) and to generate PWM at 40KHz. It can be easily modified so that it uses timer1 instead.

Code

This example code uses the SonyIR() function to send a Sony remote code in background. It sends a code every 2500ms.

/*

 Multitasked IR transmission

 For more infos, check out https://playground.arduino.cc/Main/MultiIR
 or mail me at frsmnk@gmail.com

 created 13 July 2010
 by Riccardo Argiolas
 aka CaptainTuna

*/

#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));
      }
    }
  }

}

Credits

Many thanks go to Ken Shirriff for his great blog. It helped me a lot to understand how timers and background tasking work. Do check it out: http://www.arcfn.com/
Many thanks to the guys at the arduino forums who helped me solve my doubts.

Questions?

Feel free to mail me at frsmnk (at) gmail (dot) com