Posts Tagged ‘Rmt’

Arduino IR remote control – more advanced

2009/01/02/1716

A few days ago, I demonstrated an Arduino Duemilanove circuit that would receive keypresses from a TV remote control. Well, I had so much fun with it that I made the code more advanced, and I made a new video demonstrating what I did. Watch the video, download the code, and let me know what changes you made.

After watching the video, you’ll know what to expect. The next step is to get my Arduino sketch, which is available right here:

ir_decodepde.zip

Next up, you need an IR Receiver. I use the RadioShack 38 kHz IR Receiver Module (part number 276-640). This costs $4, and it’s in almost any RadioShack I’ve ever been to (even the small ones that look like they only sell cellphones and toys). I know, I know – RadioShack has a reputation for selling shoddy parts, but whatever. I’ve only been burned once, and it’s worth it for the instant gratification of getting what I need without waiting for shipping.

Next, you need a solderless breadboard. I recommend the Arduino Protoshield, but since I haven’t assembled mine, I am using my breadboard (RS part number 276-169). I’m not sure if this is still for sale, so please let me know if you have any luck getting one.

Finally, you’ll need some small wires, some LEDs, and some resistors. Get two LEDs (the cheapest you can find), two 10K-ohm resistors, and a 220 ohm resistor.

Oh, and you’ll need a remote control. I’m using the Sony RMT-V202. This is up to you, and I can’t promise that my code will work unmodified with any other remote. However, I can tell you that my code is an excellent starting point, since it will give you all of the IR timings that you need to understand what your remote is “saying.” Remember how the video had a “debug mode” for looking at the timing of the IR pulses? This is your key to adapting the code to any remote, whatsoever.

If you need help understanding how to use a breadboard with the Arduino, I recommend watching the following video. The video demonstrates, in somewhat excruciating detail, how to build a totally different project with the Arduino. It’s kindof fun to watch, anyway…


How-to Tuesday: Fun with the Arduino Starter Kit from make magazine on Vimeo.

So, have fun! Also, I want to hear about your experiences using my code and video to play with your Arduino.

Arduino infra-red (IR) remote control

2008/12/31/1616

[UPDATE 2009-01-17]
This article is still valid, but I recommend checking out Arduino IR remote control – more advanced, which has a detailed explanation of the wiring and a zip file with some updated code.
[/UPDATE]

For the 2008 Winter Solstice, my wife got me an Arduino Duemilanove, and it rules! This little board is a ton of fun to play with, and although I don’t know a great deal about electronics, I am about to learn. For example, I’ve created this cool infrared receiver. It does work, and I’m publishing my results so that someone can help me debug the circuit.

My goal was to use an old Sony RMT-V202 remote control, then do something both on the Arduino board and on my computer. So, there’s a red LED that will light up when you press the power button on the remote, and the serial monitor now says “Power” when you push the power button. This is a proof of concept, more than anything else, since there are tons of buttons on the remote, and I can now do stuff with all of them.

For example, if you press the “display” button on my remote, you can see the ID of the keys you press. If you press the “record” button, you can see the length (in milliseconds) of the IR pulse that actually encodes the button you pressed. These key-mappings are handled in software, and can be reconfigured without rewiring the circuit at all. Using these two buttons, I figured out the encoding for the “power” button, and then mapped that onto the red LED.

I started with some code written by pmalmsten, which I found in the Arduino forum. I’ve heavily modified the original code, such that it is hardly like the version on the forum.

// 0.1 by pmalmsten
// 0.2 by farkinga

#define IR_BIT_LENGTH 12
#define BIT_1 1000          //Binary 1 threshold (Microseconds)
#define BIT_0 400           //Binary 0 threshold (Microseconds)
#define BIT_START 2000      //Start bit threshold (Microseconds)
#define DEBUG 0             //Serial connection must be started to debug
#define IR_PIN 7            //Sensor pin 1 wired through a 220 ohm resistor
#define LED_PIN 9           //"Ready to Recieve" flag, not needed but nice
#define POWER_PIN 11     // the red LED that indicates if the power button is pressed.

int runtime_debug = 0;
int output_key = 0;
int power_button = 0;

void setup() {
  pinMode(LED_PIN, OUTPUT);		//This shows when we're ready to recieve
  pinMode(POWER_PIN, OUTPUT);		//This is the "power on" indicator
  pinMode(IR_PIN, INPUT);
  digitalWrite(LED_PIN, LOW);	    //not ready yet
  Serial.begin(9600);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);	   //Ok, i'm ready to recieve

  int key = get_ir_key();		    //Fetch the key

  digitalWrite(LED_PIN, LOW);

  do_response(key);

  delay(200);
}

void do_response(int key)
{
  switch (key)
  {
    case 1437:
      Serial.println("toggle debug pulse");
      runtime_debug = 1 - runtime_debug;
      break;
    case 1498:
      Serial.println("Toggle key output");
      output_key = 1 - output_key;
      break;
    case 1429:
      Serial.println("Power");
      power_button = 1 - power_button;
      if (power_button)
      {
        digitalWrite(POWER_PIN, HIGH);
      }
      else
      {
        digitalWrite(POWER_PIN, LOW);
      }
      break;
    case 1424:
      Serial.println("Channel Up");
      break;
    case 1425:
      Serial.println("Channel Down");
      break;
    default:
      if (output_key)
      {
        Serial.print("Key ");
        Serial.print(key);
        Serial.println(" not programmed");
      }
      break;
  }
}

void read_pulse(int data[], int num_bits)
{
  for (int i = 0; i < num_bits; i++)
  {
    data[i] = pulseIn(IR_PIN, LOW);
  }
}

void pulse_to_bits(int pulse[], int bits[], int num_bits)
{
  if (DEBUG || runtime_debug) { Serial.println("-----"); }

  for(int i = 0; i < num_bits ; i++)
  {
    if (DEBUG || runtime_debug) { Serial.println(pulse[i]); }

    if(pulse[i] > BIT_1) //is it a 1?
    {
      bits[i] = 1;
    }
    else if(pulse[i] > BIT_0) //is it a 0?
    {
      bits[i] = 0;
    } 

    else //data is invalid...
    {
      Serial.println("Error");
    }
  }
}

int bits_to_int(int bits[], int num_bits)
{
  int result = 0;
  int seed = 1;

  //Convert bits to integer
  for(int i = 0 ; i < num_bits ; i++)
  {
    if(bits[i] == 1)
    {
	result += seed;
    }

    seed *= 2;
  }

  return result;
}

int get_ir_key()
{
  int pulse[IR_BIT_LENGTH];
  int bits[IR_BIT_LENGTH];  

  do {} //Wait for a start bit
  while(pulseIn(IR_PIN, LOW) < BIT_START);

  read_pulse(pulse, IR_BIT_LENGTH);

  pulse_to_bits(pulse, bits, IR_BIT_LENGTH);

  return bits_to_int(bits, IR_BIT_LENGTH);
}

Several runtime variables have become compiler constants, and large chunks of code have been modularized in what I consider to be a "sane manner." Here's the bottom line: when you press a button on the remote, you want the computer to receive a unique integer that corresponds to the button you pushed. The code above will accomplish this goal. Once you know what button you've pressed, then you can use simply logic to do different things when different keys are pressed.