Skip to content

Commit fd1ef20

Browse files
committed
Initial commit
0 parents  commit fd1ef20

File tree

5 files changed

+493
-0
lines changed

5 files changed

+493
-0
lines changed

Makefile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#default values
2+
CONFIG=./avrdude.conf
3+
PORT=/dev/ttyUSB0
4+
BAUDRATE=19200
5+
PROCESSOR=attiny13
6+
PROGRAMMER=stk500v1
7+
VERBOSE=
8+
CC=avr-gcc
9+
10+
all: receiver.hex sender.hex
11+
@echo "Compiled. Use make flash-sender or make flash-receiver to program the microcontroler"
12+
13+
%.hex: %.elf
14+
avr-objcopy -j .text -j .data -O ihex $< $@
15+
16+
%.elf: %.c
17+
$(CC) -W -Wall -mmcu=$(PROCESSOR) -Os -o $@ $<
18+
19+
%.s: %.c
20+
$(CC) -W -Wall -mmcu=$(PROCESSOR) -S -Os -o $@ $<
21+
22+
flash-%: %.hex
23+
avrdude $(VERBOSE) -C $(CONFIG) -P $(PORT) -b $(BAUDRATE) -p $(PROCESSOR) -c $(PROGRAMMER) -U flash:w:$<:i
24+
25+
read-fuses:
26+
avrdude $(VERBOSE) -C $(CONFIG) -P $(PORT) -b $(BAUDRATE) -p $(PROCESSOR) -c $(PROGRAMMER) -U lfuse:r:-:h -U hfuse:r:-:h
27+
28+
read-eeprom:
29+
avrdude $(VERBOSE) -C $(CONFIG) -P $(PORT) -b $(BAUDRATE) -p $(PROCESSOR) -c $(PROGRAMMER) -U eeprom:r:-:h
30+
31+
.PHONY: all flash flash-% read-fuses read-eeprom

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
IR controlled light
2+
===================
3+
4+
This project is simple pair of IR sender/receiver based on ATTiny 13, which allows to control two lights remotely using infrared radiation.
5+
6+
Author
7+
------
8+
9+
Martin Habovštiak <[email protected]>

common.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#define RED_LED 0b00000100 // PB3 (physical pin 2); OUTPUT
2+
#define GREEN_LED 0b00000010 // PB2 (physical pin 7); OUTPUT
3+
4+
// Our address is answer to The question of life, universe and everything
5+
#define DEVICE_ADDRESS 42
6+

receiver.c

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
#define F_CPU 1000000UL /* Clock Frequency = 1Mhz */
2+
3+
#include <inttypes.h>
4+
#include <avr/io.h>
5+
#include <util/delay.h>
6+
#include <avr/interrupt.h>
7+
#include <avr/sleep.h>
8+
#include <avr/eeprom.h> // For debugging
9+
10+
#include "common.h"
11+
12+
#define UCSRB UCSR0B
13+
14+
#define RED_BUTTON 0b00010000 // PB4 (physical pin 3); INPUT;
15+
#define GREEN_BUTTON 0b00001000 // PB1 (physical pin 6); INPUT;
16+
#define IR_INPUT 0b00000001 // PB0 (physical pin 5; PCINT0); INPUT;
17+
// TSOP 4838 is connected here
18+
#define INTERNAL_PULLUPS GREEN_BUTTON | RED_BUTTON
19+
#define ALLOWED_BITS (RED_LED | GREEN_LED) // IR controllers are allowed to change LEDs
20+
21+
#define TIMER_SPEED ((1<<CS02) | (1<<CS00)) // 1/256 MHz
22+
#define BASE_LEN 6 // Length of shortest pulse in clock ticks
23+
#define TOLERANCE 1 / 3
24+
25+
//#define DEBUG_STATES
26+
27+
#ifdef DEBUG_PULSE_LENGTHS
28+
#define DEBUG
29+
#endif
30+
31+
#ifdef DEBUG_STATES
32+
#define DEBUG
33+
#endif
34+
35+
volatile char run;
36+
volatile char firsttime;
37+
volatile char bit_state = 0;
38+
volatile char byte_state = 0;
39+
volatile char recvd_data = 0; // Received bits
40+
volatile char recvd_bit = 0; // On which bit position we are
41+
volatile int last_pulse_length;
42+
volatile uint8_t *mem_pos = 0;
43+
44+
#ifdef DEBUG
45+
void append_byte(char byte) {
46+
if(mem_pos < (uint8_t *)64) {
47+
eeprom_write_byte((uint8_t *)mem_pos, byte);
48+
++mem_pos;
49+
}
50+
}
51+
#endif
52+
53+
signed char rangecmp(int time, int length) {
54+
if(time < length * BASE_LEN - BASE_LEN * TOLERANCE) return -1;
55+
if(time > length * BASE_LEN + BASE_LEN * TOLERANCE) return 1;
56+
return 0;
57+
}
58+
59+
void process_byte() {
60+
// Byte states:
61+
// 0 - waiting for device address
62+
// 1 - our device address set
63+
// 2 - ignore bytes until reset
64+
switch(byte_state) {
65+
case 0:
66+
if(recvd_data == DEVICE_ADDRESS) {
67+
byte_state = 1;
68+
} else {
69+
byte_state = 0;
70+
}
71+
break;
72+
case 1:
73+
PORTB = (PORTB & ~ALLOWED_BITS) | (recvd_data & ALLOWED_BITS); // Set outputs
74+
++byte_state;
75+
break;
76+
}
77+
}
78+
79+
void reset_bit_state() {
80+
recvd_data = 0;
81+
recvd_bit = 0;
82+
bit_state = 0;
83+
byte_state = 0;
84+
}
85+
86+
void read_bit(int ticks) {
87+
signed char r = rangecmp(ticks, 1);
88+
signed char r2 = rangecmp(ticks, 2);
89+
if(r < 0 || r2 > 0) { // Protocol error - reset state
90+
reset_bit_state();
91+
}
92+
93+
if(!(PINB & IR_INPUT)) { // There was space
94+
if(!r && !rangecmp(last_pulse_length, 2)) { // Correct signal of bit "1"
95+
recvd_data <<= 1;
96+
recvd_data |= 1;
97+
++recvd_bit;
98+
} else if(!r2 && !rangecmp(last_pulse_length, 1)) {// Correct signal of bit "0"
99+
recvd_data <<= 1;
100+
++recvd_bit;
101+
} else { // error
102+
reset_bit_state();
103+
}
104+
if(recvd_bit == 8) { // We've got whole byte
105+
process_byte();
106+
// NOT doing reset_bit_state, because there may come new data
107+
recvd_data = 0;
108+
recvd_bit = 0;
109+
}
110+
111+
} else { // There was signal
112+
last_pulse_length = ticks;
113+
}
114+
}
115+
116+
ISR(PCINT0_vect) {
117+
// Test if buttons are hold down
118+
if(!(PINB & GREEN_BUTTON)) {
119+
PORTB = (PORTB & ~RED_LED) | GREEN_LED;
120+
return;
121+
}
122+
if(!(PINB & RED_BUTTON)) {
123+
PORTB = (PORTB & ~GREEN_LED) | RED_LED;
124+
return;
125+
}
126+
int ticks = TCNT0; // Savetimer value
127+
TCNT0 = 0; // Reset timer
128+
if(!(TCCR0B & TIMER_SPEED)) {
129+
TCCR0B |= TIMER_SPEED; // Start timer (in case it's not running)
130+
return;
131+
}
132+
133+
#ifdef DEBUG_PULSE_LENGTHS
134+
if(mem_pos < (uint8_t *)64) {
135+
eeprom_write_byte((uint8_t *)mem_pos, ticks);
136+
++mem_pos;
137+
#ifdef VISUAL_DEBUG
138+
PORTB |= GREEN_LED;
139+
} else PORTB &= ~GREEN_LED;
140+
#else
141+
}
142+
#endif
143+
#endif
144+
145+
switch(bit_state) {
146+
case 0:
147+
if((PINB & IR_INPUT) && !rangecmp(ticks, 3)) ++bit_state;
148+
#ifdef DEBUG_STATES
149+
append_byte(bit_state);
150+
#endif
151+
break;
152+
case 1:
153+
if(!(PINB & IR_INPUT) && !rangecmp(ticks, 3))
154+
++bit_state;
155+
else
156+
bit_state = 0;
157+
#ifdef DEBUG_STATES
158+
append_byte(bit_state);
159+
#endif
160+
break;
161+
case 2:
162+
read_bit(ticks);
163+
#ifdef DEBUG_STATES
164+
append_byte(byte_state);
165+
append_byte(recvd_bit);
166+
append_byte(recvd_data);
167+
#endif
168+
break;
169+
}
170+
#ifdef VISUAL_DEBUG
171+
PORTB = (PORTB & ~RED_LED) | ((~PINB & IR_INPUT) << 3);
172+
#endif
173+
}
174+
175+
ISR(TIM0_OVF_vect) {
176+
TCCR0B &= ~((1 << CS00) | (1 << CS01) | (1 << CS02)); // Stop timer
177+
TCNT0 = 0; // Too long - reset timer
178+
179+
#ifdef DEBUG_PULSE_LENGTHS
180+
if(mem_pos < (uint8_t *)64) { // Log overflow
181+
eeprom_write_byte((uint8_t *)mem_pos, 0);
182+
++mem_pos;
183+
}
184+
#endif
185+
186+
}
187+
188+
int main() {
189+
// ================== IO Setup =================
190+
191+
DDRB = GREEN_LED | RED_LED; // Set IO pins. GREEN_LED and RED_LED are outputs
192+
PORTB = INTERNAL_PULLUPS; // Init internal pullups
193+
194+
PORTB |= GREEN_LED | RED_LED;
195+
_delay_ms(250);
196+
PORTB &= ~(GREEN_LED | RED_LED);
197+
198+
// ================ Timer Setup ================
199+
200+
TCCR0A = 0; // Normal mode
201+
//TCCR0B |= (1 << CS00); // Configure prescaler to 1MHz (one tick == one microsecond)
202+
TIMSK0 |= (1 << TOIE0); // Enable overflow interrupt
203+
TCNT0 = 0;
204+
205+
// ============== Interrupt Setup ==============
206+
207+
MCUCR |= (1<<ISC00); // PCINT0 is triggered on any edge
208+
PCMSK = IR_INPUT | RED_BUTTON | GREEN_BUTTON; // Enable interrupt on IR_INPUT
209+
GIMSK |= (1<<PCIE); // enable pin change interrupts
210+
211+
//Enable global interrupts
212+
sei();
213+
214+
run = 1;
215+
while (run) {
216+
}
217+
218+
sleep_enable();
219+
sleep_cpu();
220+
221+
return 0;
222+
}

0 commit comments

Comments
 (0)