Skip to content

Commit e6806ff

Browse files
committed
Old code with added readme
0 parents  commit e6806ff

File tree

8 files changed

+352
-0
lines changed

8 files changed

+352
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.o
2+
*.elf
3+
*.hex
4+
*~

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
RC5 (36KHz Phillips protocol) Decoding library for AVR
2+
3+
Copyright (c) 2011 Filip Sobalski <[email protected]>
4+
Based on the idea presented by Guy Carpenter on http://deep.clearwater.com.au/rc5/
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.

Makefile

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
AVRDUDE_MCU = m328p
2+
AVRDUDE_PROGRAMMER = stk500v1
3+
AVRDUDE_PORT = /dev/ttyACM0
4+
AVRDUDE_BAUDRATE = 115200
5+
6+
AVRDUDE = avrdude
7+
AVRDUDEOPTS = -p $(AVRDUDE_MCU) \
8+
-c $(AVRDUDE_PROGRAMMER) \
9+
-P $(AVRDUDE_PORT) \
10+
-b $(AVRDUDE_BAUDRATE) \
11+
-F -D
12+
13+
FREQUENCY = 16000000
14+
MCU = atmega328p
15+
CC = avr-gcc
16+
CFLAGS = -mmcu=$(MCU) -O2 -DF_CPU=$(FREQUENCY)L -Wall
17+
OBJCOPY = avr-objcopy
18+
OBJCOPYFLAGS = -j .text -j .data -O ihex
19+
PROJNAME = rc5
20+
OBJECTS = main.o rc5.o
21+
LD = avr-gcc
22+
LDFLAGS = -mmcu=$(MCU)
23+
24+
all: $(PROJNAME).hex
25+
26+
$(PROJNAME).elf: $(OBJECTS)
27+
$(LD) $(LDFLAGS) $(OBJECTS) -o $@
28+
29+
$(PROJNAME).hex: $(PROJNAME).elf
30+
$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
31+
32+
%.o: %.c %.h
33+
$(CC) $(CFLAGS) -c $< -o $@
34+
35+
upload: $(PROJNAME).hex
36+
$(AVRDUDE) $(AVRDUDEOPTS) -U flash:w:$<
37+
38+
rebuild: clean all
39+
40+
clean:
41+
$(RM) $(PROJNAME) *.o *.elf *.hex *~
42+
43+
.PHONY: clean rebuild

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# RC5 (36KHz Phillips protocol) Decoding library for AVR
2+
3+
Based on the idea presented by *Guy Carpenter* on [his site](http://deep.clearwater.com.au/rc5/).
4+
5+
## What does it do?
6+
7+
It decodes control codes produces by most of your household infrared remotes.
8+
9+
## What can run it?
10+
11+
Tested on __ATmega328P__ with __avr-gcc__ toolchain. Designed for 16MHz crystal.
12+
Should work on the __ATmega{4/8/16/32}8__ (yes, that means Arduino too) family without modification.
13+
14+
Uses 16bit timer and an external interrupt.
15+
16+
I you use a different clock then adjust the timer prescaler and pulse lengths accordingly.
17+
18+
Should be trivial to adapt to other AVRs sporting a 16bit timer and an external interrupt.
19+
20+
## What do I need to run it?
21+
22+
The only additional component needed is an infrared receiver like __TSOP2236__ attached to PD2. Most of the
23+
standard receivers should work just fine.
24+
25+
## The docs
26+
27+
Check out the comments in headers/source. Example in `main.{c,h}` included.
28+
29+
## Does it work?
30+
31+
Yes, it does work flawlessly (at least for me). I built a project on it (*rlamp*) and never had any problems. The sensitivity achieved
32+
with __TSOP2236__ was astounding. I could point the remote anywhere, metres from the receiver and it would pick up
33+
the signal perfectly with every keypress.
34+
35+
Copyright &copy; 2011 Filip Sobalski <[email protected]>

main.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <avr/io.h>
2+
#include <avr/interrupt.h>
3+
#include <util/delay.h>
4+
#include <stdint.h>
5+
#include <stdlib.h>
6+
7+
#include "main.h"
8+
#include "rc5.h"
9+
10+
/* RC5 lib test
11+
* Attach a LED to PB5 */
12+
int main()
13+
{
14+
RC5_Init();
15+
16+
/* Set PB5 to output */
17+
DDRB |= _BV(PB5);
18+
19+
/* Enable interrupts */
20+
sei();
21+
22+
for(;;)
23+
{
24+
uint16_t command;
25+
26+
/* Poll for new RC5 command */
27+
if(RC5_NewCommandReceived(&command))
28+
{
29+
/* Reset RC5 lib so the next command
30+
* can be decoded. This is a must! */
31+
RC5_Reset();
32+
33+
/* Toggle the LED on PB5 */
34+
PORTB ^= _BV(PB5);
35+
36+
/* Do something with the command
37+
* Perhaps validate the start bits and output
38+
* it via UART... */
39+
if(RC5_GetStartBits(command) != 3)
40+
{
41+
/* ERROR */
42+
}
43+
44+
uint8_t toggle = RC5_GetToggleBit(command);
45+
uint8_t address = RC5_GetAddressBits(command);
46+
uint8_t cmdnum = RC5_GetCommandBits(command);
47+
}
48+
}
49+
50+
return 0;
51+
}

main.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#ifndef MAIN_H
2+
#define MAIN_H
3+
4+
5+
#endif

rc5.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#include "rc5.h"
2+
3+
#include <avr/io.h>
4+
#include <avr/interrupt.h>
5+
6+
#define SHORT_MIN 888 /* 444 microseconds */
7+
#define SHORT_MAX 2666 /* 1333 microseconds */
8+
#define LONG_MIN 2668 /* 1334 microseconds */
9+
#define LONG_MAX 4444 /* 2222 microseconds */
10+
11+
typedef enum {
12+
STATE_START1,
13+
STATE_MID1,
14+
STATE_MID0,
15+
STATE_START0,
16+
STATE_ERROR,
17+
STATE_BEGIN,
18+
STATE_END
19+
} State;
20+
21+
const uint8_t trans[4] = {0x01, 0x91, 0x9b, 0xfb};
22+
volatile uint16_t command;
23+
uint8_t ccounter;
24+
volatile uint8_t has_new;
25+
State state = STATE_BEGIN;
26+
27+
void RC5_Init()
28+
{
29+
/* Set INT0 to trigger on any edge */
30+
EICRA |= _BV(ISC00);
31+
/* Set PD2 to input */
32+
DDRD &= ~_BV(PD2);
33+
34+
/* Reset Timer1 Counter */
35+
TCCR1A = 0;
36+
/* Enable Timer1 in normal mode with /8 clock prescaling */
37+
/* One tick is 500ns with 16MHz clock */
38+
TCCR1B = _BV(CS11);
39+
40+
RC5_Reset();
41+
}
42+
43+
44+
void RC5_Reset()
45+
{
46+
has_new = 0;
47+
ccounter = 14;
48+
command = 0;
49+
state = STATE_BEGIN;
50+
51+
/* Enable INT0 */
52+
EIMSK |= _BV(INT0);
53+
}
54+
55+
56+
uint8_t RC5_NewCommandReceived(uint16_t *new_command)
57+
{
58+
if(has_new)
59+
{
60+
*new_command = command;
61+
}
62+
63+
return has_new;
64+
}
65+
66+
ISR(INT0_vect)
67+
{
68+
uint16_t delay = TCNT1;
69+
70+
/* TSOP2236 pulls the data line up, giving active low,
71+
* so the output is inverted. If data pin is high then the edge
72+
* was falling and vice versa.
73+
*
74+
* Event numbers:
75+
* 0 - short space
76+
* 2 - short pulse
77+
* 4 - long space
78+
* 6 - long pulse
79+
*/
80+
uint8_t event = (PIND & _BV(PIND2)) ? 2 : 0;
81+
82+
if(delay > LONG_MIN && delay < LONG_MAX)
83+
{
84+
event += 4;
85+
}
86+
else if(delay < SHORT_MIN || delay > SHORT_MAX)
87+
{
88+
/* If delay wasn't long and isn't short then
89+
* it is erroneous so we need to reset but
90+
* we don't return from interrupt so we don't
91+
* loose the edge currently detected. */
92+
RC5_Reset();
93+
}
94+
95+
if(state == STATE_BEGIN)
96+
{
97+
ccounter--;
98+
command |= 1 << ccounter;
99+
state = STATE_MID1;
100+
TCNT1 = 0;
101+
return;
102+
}
103+
104+
State newstate = (trans[state] >> event) & 0x03;
105+
106+
if(newstate == state || state > STATE_START0)
107+
{
108+
/* No state change or wrong state means
109+
* error so reset. */
110+
RC5_Reset();
111+
return;
112+
}
113+
114+
state = newstate;
115+
116+
/* Emit 0 - jest decrement bit position counter
117+
* cause data is already zeroed by default. */
118+
if(state == STATE_MID0)
119+
{
120+
ccounter--;
121+
}
122+
else if(state == STATE_MID1)
123+
{
124+
/* Emit 1 */
125+
ccounter--;
126+
command |= 1 << ccounter;
127+
}
128+
129+
/* The only valid end states are MID0 and START1.
130+
* Mid0 is ok, but if we finish in MID1 we need to wait
131+
* for START1 so the last edge is consumed. */
132+
if(ccounter == 0 && (state == STATE_START1 || state == STATE_MID0))
133+
{
134+
state = STATE_END;
135+
has_new = 1;
136+
137+
/* Disable INT0 */
138+
EIMSK &= ~_BV(INT0);
139+
}
140+
141+
TCNT1 = 0;
142+
}

rc5.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* RC5 (36KHz Phillips protocol) Decoding library for AVR
3+
* Copyright (c) 2011 Filip Sobalski <[email protected]>
4+
* based on the idea presented by Guy Carpenter
5+
* on http://deep.clearwater.com.au/rc5/
6+
*
7+
* Tested on ATmega328P. Designed for 16MHz crystal.
8+
* Should work on the ATmega{4/8/16/32}8 family
9+
* without modification. Uses 16bit timer and an
10+
* external interrupt.
11+
*
12+
* I you use a different clock then adjust the timer
13+
* prescaler and pulse lengths accordingly.
14+
*
15+
* Should be trivial to adapt to other AVRs sporting
16+
* a 16bit timer and an external interrupt.
17+
*
18+
*/
19+
#ifndef RC5_H
20+
#define RC5_H
21+
22+
#include <stdint.h>
23+
24+
#define RC5_GetStartBits(command) ((command & 0x3000) >> 12)
25+
#define RC5_GetToggleBit(command) ((command & 0x800) >> 11)
26+
#define RC5_GetAddressBits(command) ((command & 0x7C0) >> 6)
27+
#define RC5_GetCommandBits(command) (command & 0x3F)
28+
#define RC5_GetCommandAddressBits(command) (command & 0x7FF)
29+
30+
/* Initialize timer and interrupt */
31+
void RC5_Init();
32+
33+
/* Reset the library back to waiting-for-start state */
34+
void RC5_Reset();
35+
36+
/* Poll the library for new command.
37+
*
38+
* You should call RC5_Reset immediately after
39+
* reading the new command because it's halted once
40+
* receiving a full command to ensure you can read it
41+
* before it becomes overwritten. If you expect that only
42+
* one remote at a time will be used then library
43+
* should be polled at least once per ~150ms to ensure
44+
* that no command is missed.
45+
*/
46+
uint8_t RC5_NewCommandReceived(uint16_t *new_command);
47+
48+
49+
#endif
50+

0 commit comments

Comments
 (0)