From OmegaV-wiki
Jump to: navigation, search
Receiver with remote

IrCom is a project aimed at creating an IR interface to use with a remote control. The main motivation for this project was to be able to control the robot in RoboCom with the nifty little apple universal remote. This involved a considerable amount of backwards-engineering, (or "hacking" if you wish), since the protocol used in the remote has not been officially published.

Reverse engineering the protocol

Portion of a signal from the IR sensor
Cutout from the signal above, showing the "data" part
Cutout from another signal, showing the "data" part

The first step was to find out what exactly the little remote control sends when you push a button. This was not quite easy, since the protocol appeared to be quite complex. Work had previosly been done on a Sony remote protocol, which is really simple in comparison. A sensor was attached to an AVR, which had an CP2103 USB to UART connected to it. Thus information received from the IR sensor could be sent to a computer. A test program was written for the AVR, for measuring the time between rising and falling flanks of the input from the sensor. This information was then sent to a computer, where some processing in MATLAB yielded some interresting results.

By comparing the subtle differences in a certain part of the signals, a general idea could be formed about how to write a program for identifying which button is pressed.

Building a reception circuit

The reception circuit is really quite simple. A small AVR Attiny13 was used. Four LEDs are connected to the tiny13's PORTB[0:3], which gives a four bit output and a way to visualize the output. (Especially useful during testing). The IR sensor, a Panasonic PNA4203 is also connected to the AVR. This IR-sensor is a standard 38 kHz infrared phototransistor with filtering and amplifying circuits onboard. Also attached to the circuit board is a 3.3V regulator.
PCB layout

Programming the reception circuit

While the reception circuit turned out pretty nice and ordered, the code it runs is a whole different story. The C-code posted here is merely for fun, you could say. If you are interrested in building or programming something like this yourself, I would recommend writing your own program, and not even try to understand mine. I barely do.

<source lang=c> //--------------------------------------------------------------// // !!!ADVARSEL!!! // // // // LUFTSLOTTKODE // // // // - bør støpes inn med smeltelim og aldri tulles mer med! // // // // Dewald de Bruyn - eksamensperioden høst 2007 // // // // !!!ADVARSEL!!! // //--------------------------------------------------------------//

  1. include <avr/io.h>
  2. include <avr/interrupt.h>
  3. define true 1
  4. define false 0
  5. define inputPin (PINB & (1<<PIN4))
  1. define MENUBUTTON 0x0F
  2. define PLAYBUTTON 0x09
  3. define LEFTBUTTON 0x01
  4. define RIGHTBUTTON 0x08
  5. define UPBUTTON 0x02
  6. define DOWNBUTTON 0x04
  7. define TIMEOUT 16

char interrupt_received; unsigned int timerTicks; int output = 0; void receiveNrBits(const int); int checkForPlayMenuRev(void);

ISR(PCINT0_vect){ TCNT0 = 0x00; timerTicks = 0; interrupt_received = true; //Set interrupt receive flag? }

ISR(TIM0_OVF_vect){ timerTicks++; if(timerTicks == TIMEOUT){ timerTicks = 0; PORTB = 0x00; } }

unsigned int startReceive(){ if(inputPin != 0)return 0; while((TCNT0 < 0xFF) && inputPin == 0); if(TCNT0 != 0xFF)return 0; while(inputPin == 0); unsigned int tmp = TCNT0; TCNT0 = 0x00; if(((tmp>>4) < 0x05)||((tmp>>4) > 0x06))return 0; while(inputPin != 0); tmp = TCNT0; TCNT0 = 0x00;

if((tmp>>4) < 0x0A){ return 0; }


while(inputPin != 0); tmp = TCNT0; TCNT0 = 0x00;

if((tmp>>4) == 0x03){ //Received Play, Menu or Rev for(int i = 0; i < 3; i++){ receiveNrBits(1); if(checkForPlayMenuRev()){ if(i == 0)return MENUBUTTON; if(i == 1)return PLAYBUTTON; if(i == 2)return LEFTBUTTON; } } return 0; } else{ //Received plus, minus or fwd receiveNrBits(1); while(inputPin != 0); tmp = TCNT0; TCNT0 = 0x00; if((tmp>>4) != 0x03)return DOWNBUTTON; receiveNrBits(1); while(inputPin != 0); tmp = TCNT0; TCNT0 = 0x00; if((tmp>>4) == 0x03)return RIGHTBUTTON; if((tmp>>4) != 0x03)return UPBUTTON; } return 0; }

int checkForPlayMenuRev(){ while(inputPin != 0); unsigned int tmp = TCNT0; TCNT0 = 0x00; if((tmp>>4) == 0x03){ return true; } else return false; }

void receiveNrBits(int nr){ for(int i = 0; i < nr; i++){ if(inputPin != 0){ while(inputPin != 0); } else{ while(inputPin == 0); } TCNT0 = 0x00; } }

int main(){ DDRB = 0x0F; GIMSK |= 1<<PCIE; PCMSK |= 1<<PCINT4; TCCR0B |= 1<<CS02; TIMSK0 |= 1<<TOIE0; sei(); while(1){ if(interrupt_received == true){ GIMSK &= ~(1<<PCIE); //Disable pin interrupts interrupt_received= false; //Clear interrupt receive flag unsigned int result = startReceive(); //Start receiving sequence if(result > 0)output = result; PORTB = (output & 0x0F); GIMSK |= 1<<PCIE; } } } </source>