The Arduino Microcontroller: Part Three

Part 3: More Blinky Lights!

Hello, and welcome to part three of Rudolph's foray into microcontroller fiddling. In this installment I'll hook up a bundle of LEDs and an infrared receiver to the Arduino to make a snazzy, remote-controlled, blinky light display of doom! To make this work semi-intelligently I used Arduino's handy attachInterrupt() function. Normally the micro wouldn't notice the button being pressed unless the press happened at the perfect split-second outside the loop(). Using the interrupt, just like it's name implies, allows me to catch a button press and interrupt the current processing to change the function currently running.

For part 3 you'll need the following;

  • An Arduino
  • USB Cable
  • Computer with Arduino software installed
  • Breadboard
  • 22 Guage hookup wire
  • A wad of LEDs and appropriate resistors
  • Matching Infrared remote control and receiver (mine were pirated from an old Sony VCR)

Acquired Parts:

As mentioned, I had an old Sony VCR lying about gathering dust. The only logical course of action was to rip it apart and steal some parts from it.

LED arrayThe first useful device I scored was this loverly LED array which was hidden behind the jog dial. Eight wondrous lights, just waiting for their opportunity to do something weird. Since they're green LEDs we'll connect all of them to the arduino with a ~220 Ohm resistor. This handy little module has all eight LED's and a common ground brought out (in the center).

Infrared receiver unit The other part I stole from the VCR was the infrared receiver. Using this allows me to use the remote control from the VCR to operate the blinky-ness of the LED array. This particular unit is a Sharp GP1U58X. Here it is stripped out of it's little stamped metal casing. A little bit of Googling and a datasheet was easily found. In this photo the pin on the left (of three, putting it in the center of the board) is Data, the middle pin is VCC, and the pin on the right is ground. The Data pin is connected to pin 2 on the Arduino through a 220 Ohm resistor (because that's what I read one is supposed to do).

The Wiring:

Circuit Diagram Here's a simple diagram of the circuit I built. This is the first time I've not hand-drawn a diagram, so if I did it wrong, deal with it :) In the thing I built there are eight LEDs, all are connected the same way to their respective pins on the Arduino (pins 3 through 10).

Put all these together on a breadboard, and you should end up with something similar to this. Now unless you managed to take apart the same model VCR as I did yours probably won't look exactly the same. If you plan on using the same code as I did I highly recommend using eight LEDs as I did. Please forgive the washed out look of everything, the lighting available in my work area is pretty bad...

Circuit layout

The Code:

Now the part that makes it all do something. Fire up your Arduino IDE (see previous article) and copy/paste the following block o' code into the editing area.

/* remote_led
 * takes sony remote input
 * changes speed via volume or cursor up/down
 * changes pattern via keypad numbers
 */

int ir_pin = 2;            //Sensor pin wired through a 220 ohm resistor
int start_bit = 2000;   //Start bit threshold (Microseconds)
int bin_1 = 1000;       //Binary 1 threshold (Microseconds)
int bin_0 = 400;        //Binary 0 threshold (Microseconds)

int count = 0;        //initialize count to step 0

// we declare these volatile because they're modified during the interrupt
volatile int key = 137;    // key 137 is "0", default to off
volatile int slowDown = 0;    // "need to slow down" flag
volatile int speedUp = 0;      // "need to speed up" flag
int speed = 250;                 // default speed in milliseconds
int cycle = 0;                      // initialize cycle to step 0
void setup() {                    // set ir_pin (pin 2) to INPUT, set up interrupt, set led pins to OUTPUT
  pinMode(ir_pin, INPUT);
  attachInterrupt(0, setOpts, LOW);    // catch interrupt 0 going LOW and send to setOpts()
  for (count=3;count<11;count++) {
    pinMode(count, OUTPUT);
  }
}

void loop() {                    // the actual program loop
  // vol or cursor up = speed up (delay less)
  if((speedUp == 1) and (speed >= 75)){
    speed -= 25;
    delay(100);
    speedUp = 0;
  }

  // vol or cursor down = slow down (delay more)
  if((slowDown == 1) and (speed < 500)){
    speed += 25;
    delay(100);
    slowDown = 0;
  }

  if((key == 137) or (key == 1432)){    // key 0 or [Stop] turn off
    allOff();
  }else if(key == 128){    // key number 1 turn all on
    allOn();
  }else if(key == 129){    // key 2
    blinkAll();
  }else if(key == 130){    // key 3
    runSequence();
  }else if(key == 131){  // key 4
    runSeqBack();
  }else if(key == 132){    // key 5
    fillOutIn();
  }else if(key == 133){    // key 6
    fillInOut();
  }else if(key == 134){    // key 7  
    scan();
  }
}

void scan() {
  if(cycle == 0){
    allOff();
  }else if(cycle == 1){
    digitalWrite(4, LOW);
    digitalWrite(3, HIGH);
  }else if(cycle == 2){
    digitalWrite(3, LOW);
    digitalWrite(4, HIGH);
  }else if(cycle == 3){
    digitalWrite(4, LOW);
    digitalWrite(5, HIGH);
  }else if(cycle == 4){
    digitalWrite(5, LOW);
    digitalWrite(6, HIGH);
  }else if(cycle == 5){
    digitalWrite(6, LOW);
    digitalWrite(7, HIGH);
  }else if(cycle == 6){
    digitalWrite(7, LOW);
    digitalWrite(8, HIGH);
  }else if(cycle == 7){
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
  }else if(cycle == 8){
    digitalWrite(9, LOW);
    digitalWrite(10, HIGH);
  }else if(cycle == 9){
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
  }else if(cycle == 10){
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
  }else if(cycle == 11){
    digitalWrite(8, LOW);
    digitalWrite(7, HIGH);
  }else if(cycle ==12){
    digitalWrite(7, LOW);
    digitalWrite(6, HIGH);
  }else if(cycle == 13){
    digitalWrite(6, LOW);
    digitalWrite(5, HIGH);
  }else if(cycle == 14){
    digitalWrite(5, LOW);
    digitalWrite(4, HIGH);
  }else if(cycle == 15){
    digitalWrite(4, LOW);
    digitalWrite(3, HIGH);
  }
  cycle = (cycle+1) % 16;
  delay(speed);
}

void fillInOut() {
  if(cycle == 0){
    allOff();
  }else if(cycle == 1){
    digitalWrite(6, HIGH);
    digitalWrite(7, HIGH);
  }else if(cycle == 2){
    digitalWrite(5, HIGH);
    digitalWrite(8, HIGH);
  }else if(cycle == 3){
    digitalWrite(4, HIGH);
    digitalWrite(9, HIGH);
  }else if(cycle == 4){
    digitalWrite(3, HIGH);
    digitalWrite(10, HIGH);
  }
  cycle = (cycle+1) % 5;
  delay(speed);
}

void fillOutIn() {
  if(cycle == 0){
    allOff();
  }else if(cycle == 1){
    digitalWrite(3, HIGH);
    digitalWrite(10, HIGH);
  }else if(cycle == 2){
    digitalWrite(4, HIGH);
    digitalWrite(9, HIGH);
  }else if(cycle == 3){
    digitalWrite(5, HIGH);
    digitalWrite(8, HIGH);
  }else if(cycle == 4){
    digitalWrite(6, HIGH);
    digitalWrite(7, HIGH);
  }
  cycle = (cycle+1) % 5;
  delay(speed);
}

void runSeqBack() {
  if(cycle == 0){
    allOff();
  }else if(cycle == 1){
    digitalWrite(10, HIGH);
  }else if(cycle == 2){
    digitalWrite(10, LOW);
    digitalWrite(9, HIGH);
  }else if(cycle == 3){
    digitalWrite(9, LOW);
    digitalWrite(8, HIGH);
  }else if(cycle == 4){
    digitalWrite(8, LOW);
    digitalWrite(7, HIGH);
  }else if(cycle == 5){
    digitalWrite(7, LOW);
    digitalWrite(6, HIGH);
  }else if(cycle == 6){
    digitalWrite(6, LOW);
    digitalWrite(5, HIGH);
  }else if(cycle == 7){
    digitalWrite(5, LOW);
    digitalWrite(4, HIGH);
  }else if(cycle == 8){
    digitalWrite(4, LOW);
    digitalWrite(3, HIGH);
  }
  cycle = (cycle+1) % 9;
  delay(speed);
}

void runSequence() {
  if(cycle == 0){
    allOff();
  }else if(cycle == 1){
    digitalWrite(3, HIGH);
  }else if(cycle == 2){
    digitalWrite(3, LOW);
    digitalWrite(4, HIGH);
  }else if(cycle == 3){
    digitalWrite(4, LOW);
    digitalWrite(5, HIGH);
  }else if(cycle == 4){
    digitalWrite(5, LOW);
    digitalWrite(6, HIGH);
  }else if(cycle == 5){
    digitalWrite(6, LOW);
    digitalWrite(7, HIGH);
  }else if(cycle == 6){
    digitalWrite(7, LOW);
    digitalWrite(8, HIGH);
  }else if(cycle == 7){
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
  }else if(cycle == 8){
    digitalWrite(9, LOW);
    digitalWrite(10, HIGH);
  }
  cycle = (cycle+1) % 9;
  delay(speed);
}

void blinkAll() {
  if(cycle == 0){
    allOff();
  }else{
    allOn();
  }
  cycle = (cycle+1) % 2;
  delay(speed);
}

void allOff() {
  for(count=3;count<11;count++){
    digitalWrite(count, LOW);
  }
}

void allOn() {
  for(count=3;count<11;count++){
    digitalWrite(count, HIGH);
  }
}

void setOpts() {    // this is run when ir_pin is interrupted
// code slightly modified from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1176098434

  int tempKey = getIRKey();
  if(tempKey > 1){
    if((tempKey == 146) or (tempKey == 1474)){
      speedUp = 1;
    }else if((tempKey == 147) or (tempKey == 1475)){
      slowDown = 1;
    }else{
      //allOff();
      cycle = 0;
      key = tempKey;
    }
  }
}

int getIRKey() {
  int data[12];
  if(pulseIn(ir_pin, LOW) < 2200) { //Wait for a start bit
    return -1;
  }
  data[0] = pulseIn(ir_pin, LOW);    //Start measuring bits, I only want low pulses
  data[1] = pulseIn(ir_pin, LOW);
  data[2] = pulseIn(ir_pin, LOW);
  data[3] = pulseIn(ir_pin, LOW);
  data[4] = pulseIn(ir_pin, LOW);
  data[5] = pulseIn(ir_pin, LOW);
  data[6] = pulseIn(ir_pin, LOW);
  data[7] = pulseIn(ir_pin, LOW);
  data[8] = pulseIn(ir_pin, LOW);
  data[9] = pulseIn(ir_pin, LOW);
  data[10] = pulseIn(ir_pin, LOW);
  data[11] = pulseIn(ir_pin, LOW);

  for(int i=0;i<11;i++) {          //Parse them         
    if(data[i] > bin_1) {          //is it a 1?
    data[i] = 1;
    }  else {
    if(data[i] > bin_0) {        //is it a 0?
      data[i] = 0;
    } else {
     data[i] = 2;              //Flag the data as invalid; I don't know what it is!
    }
    }
  }
 
  for(int i=0;i<11;i++) {          //Pre-check data for errors
    if(data[i] > 1) {           
    return -1;                 //Return -1 on invalid data
    }
  }
 
  int result = 0; 
  int seed = 1;                         
  for(int i=0;i<11;i++) {          //Convert bits to integer
    if(data[i] == 1) {
    result += seed;
    }
    seed = seed * 2;
  }
  return result;                 //Return key number
}

 Save all that as remote_led (or something else if you prefer), compile it, and upload it to the Arduino. After that, aim your remote at the IR receiver, and start poking buttons. Depending on how closely your setup matches mine you should see something similar to the following video.

The Motion Picture!

The End.

That's all there is, for now anyway!  Please feel free to send me a message or start up a conversation in the forums, I'll be happy to help!

Read Part 1 Of My Arduino Article Series

Read Part 2 Of My Arduino Article Series

Comments

Currahee's picture

i like that

dakkar's picture

Why the 220 ohm resistor on the output of the IR decoder?

Rudolph's picture

At the time it was because that's what I had read was supposed to be done. I have run the IR decoder thingy on other projects since without any resistor and haven't noticed a problem.

H3ADSH07's picture

yes, i have one question as of now. how did you find out the numbers to specify which button on the remote was pressed in the program? is that on the data sheet for the reciever or what?

thanks in advance,
nick

Rudolph's picture

I think I just poked buttons and made notes of which button returned which code. I don't remember for certain anymore though.

This used a standard Sony remote, and I've been told Sony is the easiest to decode, so there is probably some place out there that has a list of the Sony specific IR codes. Try this place as a jumping off point.