/* Read keypresses from an RC5 remote control. Adam Sampson This uses the UIRT2's UIR protocol, so lirc's uirt2 driver will work with it. Note that uirt2 returns 48-bit codes, so you will probably need to say something like this in your lircd.conf to read from an RC5 remote: bits 48 toggle_bit 37 I've got an IR receiver, which demodulates the 38kHz signal itself, connected to analogue input 0. There's no particularly good reason to use an analogue input; it's just that it's next to the power pins, so the wiring's neater... There's a good description of how RC5 works in Atmel's application note AVR410: http://www.atmel.com/dyn/resources/prod_documents/doc1473.pdf */ void setup() { Serial.begin(115200); } // Read the IO pin connected to the receiver. // This should be 1 when there's no signal. // FIXME: this should just use a digital read int read_pin() { if (analogRead(0) >= 512) { return 1; } else { return 0; } } // Read a word of data from the remote control. void read_frame() { // RC5 bits are Manchester-coded: 1 is encoded as a 0-to-1 // transition in the middle of the bit period, and 0 as a // 1-to-0 transition. // Wait for the input to stay 1 for longer than 3.5ms. // This guarantees we aren't in the middle of a frame. long start = micros(); while (true) { long now = micros(); if (now - start >= 3500) break; if (read_pin() != 1) start = now; } // First, we have two start bits (so 0101...). // Find the first falling edge. while (read_pin() == 1) ; // Turn the LED on. digitalWrite(13, HIGH); // Measure the length of that half-bit; this gives us the bit time. long last_edge = micros(); while (read_pin() == 0) ; long bit_time = (micros() - last_edge) * 2; // Check the bit time isn't implausibly long. if (bit_time > 2500) return; // For each bit we expect to receive after that... int value = 0; int level = 1; for (int i = 0; i < 12; i++) { // Wait for a level transition (in the middle of the bit). while (read_pin() == level) { // If we've waited too long, give up. if (micros() > (last_edge + ((5 * bit_time) / 4))) return; } long edge = micros(); // Recompute the bit time. bit_time = edge - last_edge; last_edge = edge; // Delay for 3/4 of the period. // (delayMicroseconds() isn't very accurate, hence this // instead.) long until = edge + ((3 * bit_time) / 4); while (micros() < until) ; // Sample the value. level = read_pin(); value = (value << 1) | level; } // Send the code as six bytes over the serial port. for (int i = 0; i < 4; i++) { Serial.print(0, BYTE); } Serial.print(value >> 8, BYTE); Serial.print(value & 0xFF, BYTE); // Turn the LED off. digitalWrite(13, LOW); } void loop() { read_frame(); }