A simple TV remote control for Granny.

Well, my mother-in-law actually. Let's call her Hyacinth.

Hyacinth is elderly and suffers from arthritis which restricts her dexterity, and poor eyesight. She was recently forced down the satellite TV route. The problem for her is that the remote control for the satellite box (a Bush BFSAT02SD) has small buttons, small legends, and requires three key-presses to select a channel. She only wants to watch the 'original' four channels of BBC1, BBC2, ITV and Channel 4.

Son-in-law to the rescue.

I tried several large-button 'universal' remotes, none of which could be made to work. So I decided to make her a simple large button remote which would select the required channel with just one key-press.

I have been using the Arduino Duemilanove for some time now, and decided that the ATMega328 would be the basis of the project.

Here is the circuit diagram -

D1 to 4 are any small-signal diodes. R1 limits the IR LED current to 33 mA. R2 holds RESET high. I don't know if this is strictly necessary, but I didn't want to take the chance.

And here is the finished article -

The first job was to learn the codes sent by the remote. There are plenty of sources for how to do this, so I wont go into that. Here are the patterns that I acquired. The waveform represents the bursts and spaces sent by the remote. I noted that the first section was unchanging, so I called this the header. Presumably this is to sync the receiver.

The ATMega code is fairly self-explanatory -

Part 1, the setup, is straightforward.

Part 2 – the main loop.
Here I put the device to sleep to save the battery. Pressing any key generates an interrupt to wake the chip, the keys are then read in sequence to see which one was pressed. For example, assuming key 4 was pressed, the device sends a leader followed immediately by the variable sequence for button 1. Next is a ½ second delay followed by the leader and code for button 0. Another delay then the leader and code for button 4.
On the TV screen you will see 1 ? 0 ? 4. Just what's needed.
The device then sleeps again.

The remote needs to be modulated at 38 kHz. The function void sendHF(int y) function achieves this.

The functions sendLeader(), sendOne()....sendZero() all work in the same way. Apart from the start of leader, all bursts are the same length. Only the space duration varies.

I can't get all the code in one post, so part 2 follows in another post. Here http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1283692339

// *********************************************************************
//   Author:                         Simon Bell. 01/09/2010
//
// This may not be the best way to do it, but it's the way I've done it.
// *********************************************************************

#include <avr/sleep.h>

int ledPin =  13;       // IR LED connected to digital pin 13
int button1 = 4;
int button2 = 5;
int button3 = 6;
int button4 = 7;
int wakePin = 2;        // pin used for waking up

void wakeUpNow()  {     // here the interrupt is handled after wakeup. In this case, do nothing.
}

void trigger(){
  digitalWrite(12, HIGH);          // Scope trigger for debugging.
  delayMicroseconds(300);
  digitalWrite(12, LOW);
}

void setup()   {
pinMode(wakePin, INPUT);
pinMode(12,OUTPUT);
pinMode(button1, INPUT);           // set pins to input
digitalWrite(button1, HIGH);       // turn on pullup resistors
pinMode(button2, INPUT);
digitalWrite(button2, HIGH);
pinMode(button3, INPUT);
digitalWrite(button3, HIGH);
pinMode(button4, INPUT);
digitalWrite(button4, HIGH);
pinMode(wakePin, INPUT);
digitalWrite(wakePin, HIGH);
attachInterrupt(0, wakeUpNow, LOW);
}

void loop()  {
 set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
 sleep_enable();                        // enables the sleep bit in the mcucr register so sleep is possible.
 sleep_mode();                          // here the device is actually put to sleep!!
  // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
  trigger();   //Send scope trigger
if (digitalRead(button1) == 0)
  {
  sendLeader();
  sendOne();
  delay(500);
  sendLeader();
  sendZero();
  delay(500);
  sendLeader();
  sendOne();
  }  
if (digitalRead(button2) == 0)
  {
  sendLeader();
  sendOne();
  delay(500);
  sendLeader();
  sendZero();
  delay(500);
  sendLeader();
  sendTwo();
  }
if (digitalRead(button3) == 0)
  {
  sendLeader();
  sendOne();
  delay(500);
  sendLeader();
  sendZero();
  delay(500);
  sendLeader();
  sendThree();
  }
if (digitalRead(button4) == 0)
  {
  sendLeader();
  sendOne();
  delay(500);
  sendLeader();
  sendZero();
  delay(500);
  sendLeader();
  sendFour();
  }
}

void sendHF(int y)  {            // Modulator function.
  int x;
    for (x=1 ; x <=y; x++)
    {
    digitalWrite(ledPin, HIGH);
    delayMicroseconds(5);        //Delay times chosen by observation.
    digitalWrite(ledPin, LOW);   // The BFSAT02SD is not very fussy about timing or frequency.
    delayMicroseconds(13);
    }
  }

Let me just say that you are the best son in law ever!

Why don't you reply to your first post, so everything is contained in one single thread? Otherwise you will have comments in both threads, and it just makes things a big mess!

Nice work though, although I am unsure as to the purpose of the diodes on the buttons, in my (limited) experience, that would only really be required if you had them in a matrix of some sort.

Also, in your digit functions (sendone/etc) you have:

sendHF(21);
  digitalWrite(ledPin, LOW);
  delayMicroseconds(580);

and the very end of sendHF() is:

 digitalWrite(ledPin, LOW);   // The BFSAT02SD is not very fussy about timing or frequency.
    delayMicroseconds(13);
    }

Since you are setting the ledPin LOW at the end of the sendHF function, you probably don't need to set it low again after the function ends. It would speed things up a little bit (digitalWrite is very slow) and also reduce the size of the code.

Jeremy,
Steady on, old chap!

Nick,

Why don't you reply to your first post, so everything is contained in one single thread?

Point well made. I'm a bit new to this.

The diodes are there to pull the Interrupt pin low when any key is pressed. They perform a logical OR function.

I agree about the coding deficiencies, but neither speed or size are an issue in this case.

Thanks for the feedback.

Ah gotcha... now I see it :slight_smile: thanks for the clarification (and education :))