All projects
07Live
IR Remote
Decode an infrared remote and give every button its own color.
Decode
01
What you learn
Decoding the NEC protocol: each key sends a unique 32-bit code as light pulses of varying length. You time the pulses with a timer.
02
Parts you need
03
Wiring
| Module | Board | Note |
|---|---|---|
| S / OUT | PB2 | Receiver output |
| + / VCC | 3.3V | — |
| - / GND | GND | — |
04
Code
main.c
1#include <stdint.h>2#include <stdbool.h>3#include "inc/hw_memmap.h"4#include "driverlib/sysctl.h"5#include "driverlib/gpio.h"6#include "driverlib/timer.h"7 8#define LED_ALL (GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3)9#define IR_PORT GPIO_PORTB_BASE10#define IR_PIN GPIO_PIN_2 // PB211#define PWM_STEPS 25612 13static void showColor(uint8_t r, uint8_t g, uint8_t b, uint32_t periods) {14 volatile uint32_t p, i;15 for (p = 0; p < periods; p++)16 for (i = 0; i < PWM_STEPS; i++) {17 uint8_t out = 0;18 if (i < r) out |= GPIO_PIN_1;19 if (i < g) out |= GPIO_PIN_3;20 if (i < b) out |= GPIO_PIN_2;21 GPIOPinWrite(GPIO_PORTF_BASE, LED_ALL, out);22 SysCtlDelay(2);23 }24}25 26// 0..255 -> a rainbow color27static void wheel(uint8_t pos, uint8_t *r, uint8_t *g, uint8_t *b) {28 if (pos < 85) { *r = 255 - pos * 3; *g = pos * 3; *b = 0; }29 else if (pos < 170) { pos -= 85; *r = 0; *g = 255 - pos * 3; *b = pos * 3; }30 else { pos -= 170; *r = pos * 3; *g = 0; *b = 255 - pos * 3; }31}32 33static int irLevel(void) { return GPIOPinRead(IR_PORT, IR_PIN) ? 1 : 0; }34 35// Wait while the pin stays at 'level'; return how long it stayed (us)36static uint32_t waitWhile(int level) {37 uint32_t start = TimerValueGet(TIMER0_BASE, TIMER_A);38 uint32_t guard = 2000000;39 while (irLevel() == level)40 if (--guard == 0) break;41 return (TimerValueGet(TIMER0_BASE, TIMER_A) - start) / 50; // 50 MHz -> us42}43 44// Line has just gone LOW -> decode one NEC frame. 1 = ok.45static int irDecode(uint32_t *out) {46 uint32_t d, i, code = 0;47 d = waitWhile(0); // leader burst ~9 ms48 if (d < 7000 || d > 11000) return 0;49 d = waitWhile(1); // space ~4.5 ms (repeat = 2.25 ms -> reject)50 if (d < 3000 || d > 6000) return 0;51 for (i = 0; i < 32; i++) {52 waitWhile(0); // ~560 us burst53 uint32_t space = waitWhile(1); // 560 us = 0, 1690 us = 154 code <<= 1;55 if (space > 1000) code |= 1;56 }57 *out = code;58 return 1;59}60 61int main(void) {62 uint8_t r = 0, g = 0, b = 0; // current color (starts off)63 64 SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL |65 SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);66 67 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);68 while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)) {}69 GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, LED_ALL);70 71 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // IR output on PB272 while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)) {}73 GPIOPinTypeGPIOInput(IR_PORT, IR_PIN);74 75 SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // free-running us timer76 while (!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0)) {}77 TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC_UP);78 TimerLoadSet(TIMER0_BASE, TIMER_A, 0xFFFFFFFF);79 TimerEnable(TIMER0_BASE, TIMER_A);80 81 while (1) {82 if (irLevel() == 0) { // a frame may be starting83 uint32_t code;84 if (irDecode(&code)) {85 wheel((uint8_t)(code % 256), &r, &g, &b); // button -> color86 }87 }88 showColor(r, g, b, 2); // hold color, keep polling89 }90}05
Output
The simulation below runs in your browser — it mimics the real board.
- key
- —
- RGB
- 0,0,0