IMPLEMENTED SO FAR

- Support for 4x20 LCD Display and large number display
- Brightness and contrast adjustment with remote
- (OPUS/Wolfson WM8741) DAC volume control: remote and rotary encoder
- (OPUS/Wolfson WM8741) DAC random filter selection 1 to 5 with remote
- (OPUS/Wolfson WM8741) DAC upsampling selection (L, M, H -this is the OSR setting)
- I2C level shifting (5V to 3.3V)
- Optimized power-up sequence

Saturday, May 16, 2009

Simplest Arduino Sony Remote Code



Following the example indicated in the previous post, I've modified the remote control code to a simpler version. I've deleted all the error checking because the code only acts upon a valid code (uses a switch statement) thus if a code is invalid, nothing will be done and therefore the error checking is not necessary. Just like before, it is interrupt driven.

The Sony TV remote protocol is the simplest to program because we only need to detect the start pulse and then determine if the length of the next 12 pulses (13 pulses total).
  • The pulses are only measured while low
  • The first pulse, the start pulse, lasts about 2.4 ms (2400 microseconds)
  • The following pulses are 1.2 ms (1200 microseconds) for a 1, 0.6 ms (600 microseconds) for a 0
  • Each data pulse is about 0.3 ms (300 microseconds) apart
  • Every set of 13 pulses is about 20-30 ms apart from each other, repeating when a button is held down
The code below will watch for a 13 pulse set and returns the set's integer equivalent,

The interrupt service routine is very simple. The remote signal is connected to pin 3 (which in Arduino is interrupt 1). When there is a pulse, an interrupt is generated and the service routine sets a flag:
void remoting() // The ISR
{
remoteOn=1;
}
And in the setup portion of the Arduino code, the interrupt routine is attached:
attachInterrupt (1, remoting, FALLING);
We detect the FALLING edge of the pulse because the pulses pull down. Once the flat is set (indicating that there is remote control signals, we proceed to detect and decode the pulses with the following code:
int getIRKey() {
  int duration=1;
  int result=0;
  while((duration=pulseIn(IRPIN, LOW, 50000)) < 2200 && duration!=0)
  {
    //do nothing waiting for start pulse
  }

  int mask = 1;        // set mask to bit 0
  for (int idx = 0; idx < 12; idx++)     // get all 12 bits
  {
    duration = pulseIn(IRPIN, LOW, 2000);   // measure the bit pulse
    if (duration > ONEPULSE)      // 1 bit?
 result |= mask;       // yes, update ir code
    mask <<= 1;        // shift mask to next bit
  }
  return result;
}
The while loop waits for the start pulse, however when there is no start pulse and we are still inside this loop, we need a way to exit this loop. We use the duration!=0 condition.

In the main remote loop we detect the pulses and perform the functions specified by the codes as follows:
while (remoteOn==1)
{
int key = getIRKey(); //Fetch the key

// Interpret the keys and do something: increase volume, etc
// I use a switch statement

delay (30);
remoteOn=0; //reset flag
}
I found that I needed some delay to get rid of "spurious interrupts" (interrupts that resulted in invalid code). You may or may not need this delay. Invalid code are innocuous because they are ignored in the switch statement.

Note: some parts of the code is missing. Please see the full code from the link above.

3 comments:

insulated copper wire said...

I’m not sure I understand your question. The ir command can be sent several hundred times a second. The camera is limited by it’s design to a few shots a second. Even if I have the intervalometer set as fast as it can go, my d40 shoots 3 frames per second until the card gets bogged down, and then it slows down.

rade95 said...

Hi, could you please publish the whole version of the code with your changes. I don't see the link you are referring to. thanks

Rade M.

Anonymous said...

The link is in the side bar: v0.7 is the one I use now.