Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
838 | - | 1 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
2 | * main.c - Servo controlled infrared transmitter |
||
3 | * |
||
4 | * Copyright (c) 2010-0xFFFF Stefan Pendsa |
||
5 | * Based on the nice IR decoder/encoder routines (IRMP/IRSND) from Frank Meyer => http://www.mikrocontroller.net/articles/IRMP |
||
6 | * |
||
7 | * ATMEGA8 @ 16 MHz |
||
8 | * |
||
9 | * Fuses: lfuse:0xAE hfuse:0xD9 |
||
10 | * |
||
11 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
12 | * This program is free software; you can redistribute it and/or modify |
||
13 | * it under the terms of the GNU General Public License as published by |
||
14 | * the Free Software Foundation; either version 2 of the License, or |
||
15 | * (at your option) any later version. |
||
16 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
17 | */ |
||
18 | |||
19 | #include <inttypes.h> |
||
20 | #include <avr/io.h> |
||
21 | #include <util/delay.h> |
||
22 | #include <avr/pgmspace.h> |
||
23 | #include <avr/interrupt.h> |
||
24 | #include <avr/eeprom.h> |
||
25 | #include "irmp.h" |
||
26 | #include "irsndconfig.h" |
||
27 | #include "irsnd.h" |
||
28 | |||
29 | #ifndef F_CPU |
||
30 | #error F_CPU unkown |
||
31 | #endif |
||
32 | |||
33 | |||
34 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
35 | * Global variables |
||
36 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
37 | */ |
||
38 | unsigned char key=0; // goes 1 when key was pressed |
||
39 | unsigned char ee_dummy EEMEM; // don't use the first byte in EEPROM, causes problems on some old AVRs... |
||
40 | unsigned char ee_check EEMEM; // Check-Byte to see if EEPROM is initialized |
||
41 | unsigned char active[5][5]; // Array to see which servo-combinations were populated with valid IR-codes |
||
42 | unsigned char ee_active[5][5] EEMEM; // Array to see which servo-combinations were populated with valid IR-codes (in EEPROM) |
||
43 | |||
44 | IRMP_DATA ir_data[5][5]; // Array with IR-codes for every servo-combination |
||
45 | IRMP_DATA ee_ir_data[5][5] EEMEM; // Array with IR-codes for every servo-combination (in EEPROM) |
||
46 | IRMP_DATA ir_temp; // Received IR-codes goes into here |
||
47 | |||
48 | |||
49 | |||
50 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
51 | * timer 1 initialization |
||
52 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
53 | */ |
||
54 | void timer_init (void) |
||
55 | { |
||
56 | OCR1A = (F_CPU / F_INTERRUPTS) - 1; // compare value: 1/10000 of CPU frequency |
||
57 | TCCR1B = (1 << WGM12) | (1 << CS10); // switch CTC Mode on, set prescaler to 1 |
||
58 | |||
59 | #if defined (__AVR_ATmega8__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__) || defined (__AVR_ATmega64__) || defined (__AVR_ATmega162__) |
||
60 | TIMSK = 1 << OCIE1A; // OCIE1A: Interrupt by timer compare (use TIMSK for ATMEGA162) |
||
61 | #else |
||
62 | TIMSK1 = 1 << OCIE1A; // OCIE1A: Interrupt by timer compare (use TIMSK for ATMEGA162) |
||
63 | #endif // __AVR... |
||
64 | } |
||
65 | |||
66 | |||
67 | |||
68 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
69 | * timer 1 compare handler, called every 1/20000 sec |
||
70 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
71 | */ |
||
72 | ISR(TIMER1_COMPA_vect) |
||
73 | { |
||
74 | if (!irsnd_ISR()) // call irsnd ISR |
||
75 | { // if not busy... |
||
76 | irmp_ISR(); // call irmp ISR |
||
77 | } |
||
78 | } |
||
79 | |||
80 | |||
81 | |||
82 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
83 | * LED control: 0 = off, >0 = on |
||
84 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
85 | */ |
||
86 | void LED(unsigned char bit) |
||
87 | { |
||
88 | if (bit == 0) PORTD |= 1<<PORTD7; |
||
89 | else PORTD &= ~(1<<PORTD7); |
||
90 | } |
||
91 | |||
92 | |||
93 | |||
94 | |||
95 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
96 | * LED Flash (on for time1, off for time2, repeated). Keypressing is checked in background |
||
97 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
98 | */ |
||
99 | void Flash(unsigned char time1, unsigned char time2, unsigned char repeat) |
||
100 | { |
||
101 | unsigned char i,j; |
||
102 | key = 0; |
||
103 | for (i=0;i<repeat;i++) |
||
104 | { |
||
105 | PORTD &= ~(1<<PORTD7); |
||
106 | for (j=0;j<time1;j++) |
||
107 | { |
||
108 | _delay_ms(1); |
||
109 | if (!(PINB & (1<<PINB2))) key = 1; |
||
110 | } |
||
111 | PORTD |= 1<<PORTD7; |
||
112 | for (j=0;j<time2;j++) |
||
113 | { |
||
114 | _delay_ms(1); |
||
115 | if (!(PINB & (1<<PINB2))) key = 1; |
||
116 | } |
||
117 | } |
||
118 | } |
||
119 | |||
120 | |||
121 | |||
122 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
123 | * LED Flash2 (on/off for time1, repeated, followed by delay of time2). Keypressing is checked in background |
||
124 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
125 | */ |
||
126 | void Flash2(unsigned char time1, unsigned int time2, unsigned char repeat) |
||
127 | { |
||
128 | unsigned int i,j; |
||
129 | key = 0; |
||
130 | |||
131 | for (i=0;i<repeat;i++) |
||
132 | { |
||
133 | PORTD &= ~(1<<PORTD7); |
||
134 | for (j=0;j<time1;j++) |
||
135 | { |
||
136 | _delay_ms(1); |
||
137 | if (!(PINB & (1<<PINB2))) key = 1; |
||
138 | } |
||
139 | PORTD |= 1<<PORTD7; |
||
140 | for (j=0;j<time1;j++) |
||
141 | { |
||
142 | _delay_ms(1); |
||
143 | if (!(PINB & (1<<PINB2))) key = 1; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | for (j=0;j<time2;j++) |
||
148 | { |
||
149 | _delay_ms(1); |
||
150 | if (!(PINB & (1<<PINB2))) key = 1; |
||
151 | } |
||
152 | } |
||
153 | |||
154 | |||
155 | |||
156 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
157 | * Waits for button release followed by a debounce delay |
||
158 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
159 | */ |
||
160 | void WaitForKeyRelease(void) |
||
161 | { |
||
162 | while(!(PINB & (1<<PINB2))); |
||
163 | _delay_ms(50); |
||
164 | } |
||
165 | |||
166 | |||
167 | |||
168 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
169 | * Get position from servo inputs 1 and 2. Returns 1/2/3 for down/middle/up and 0 for invalid signal |
||
170 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
171 | */ |
||
172 | unsigned char Servo(unsigned char chan) |
||
173 | { |
||
174 | cli(); |
||
175 | unsigned int i=0; |
||
176 | |||
177 | for (i=0;i<7500;i++) // wait max. 75 ms for signal going down |
||
178 | { |
||
179 | _delay_us(10); |
||
180 | if (!(PINC & (1<<(chan+1)))) break; |
||
181 | } |
||
182 | |||
183 | for (i=0;i<7500;i++) // wait max. 75 ms for signal going up |
||
184 | { |
||
185 | _delay_us(10); |
||
186 | if (PINC & (1<<(chan+1))) break; |
||
187 | } |
||
188 | |||
189 | for (i=0;i<255;i++) // measure time until signal goes down |
||
190 | { |
||
191 | if (!(PINC & (1<<(chan+1)))) break; |
||
192 | _delay_us(10); |
||
193 | } |
||
194 | |||
195 | |||
196 | sei(); |
||
197 | if (i < 75) return 0; // 0,00 - 0,74 ms => 0 (switch to GND) |
||
198 | else if (i > 74 && i < 125) return 1; // 0,75 - 1,24 ms => 1 (stick down) |
||
199 | else if (i > 124 && i < 175) return 2; // 1,25 - 1,74 ms => 2 (stick middle) |
||
200 | else if (i > 174 && i < 225) return 3; // 1,75 - 2,24 ms => 3 (stick up) |
||
201 | else if (i > 224) return 4; // 2,25 - ever ms => 4 (switch to VCC or open input) |
||
202 | return 0; |
||
203 | } |
||
204 | |||
205 | |||
206 | |||
207 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
208 | * Learning-Mode: When an IR signal arrives, it is saved in an array position related to the actual servo positions |
||
209 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
210 | */ |
||
211 | void Learn(void) |
||
212 | { |
||
213 | unsigned char i,j,Servo1,Servo2,mode=1; |
||
214 | for (i=0;i<5;i++) // first, forget every assignment |
||
215 | { |
||
216 | for (j=0;j<5;j++) |
||
217 | { |
||
218 | active[i][j] = 0; |
||
219 | } |
||
220 | } |
||
221 | |||
222 | WaitForKeyRelease(); |
||
223 | |||
224 | while(1) |
||
225 | { |
||
226 | if (irmp_get_data (&ir_temp)) // when IR code is decoded, |
||
227 | { |
||
228 | Servo1 = Servo(1); // get Servo positions |
||
229 | Servo2 = Servo(2); |
||
230 | ir_temp.flags = 0; // ignore reapeat-flag |
||
231 | ir_data[Servo1][Servo2] = ir_temp; // populate the array |
||
232 | active[Servo1][Servo2] = mode; // and flag it with the actually mode |
||
233 | Flash(25,25,10); // fast flash LED 10 times to indicate a learned code |
||
234 | } |
||
235 | |||
236 | Flash2(100,500,mode); // slow flash LED whole time to indicate we are in learning mode (flashing 1 or 2 times, depends on mode) |
||
237 | |||
238 | if (key) // toggle mode: single -> multi -> single -> multi ... |
||
239 | { |
||
240 | if (mode == 1) mode = 2; |
||
241 | else mode = 1; |
||
242 | |||
243 | _delay_ms(500); |
||
244 | if (!(PINB & (1<<PINB2))) break; // Leave learning mode when button is pressed for 500 ms |
||
245 | } |
||
246 | |||
247 | } |
||
248 | |||
249 | // Write to EEPROM |
||
250 | eeprom_write_block(&ir_data,&ee_ir_data,sizeof(unsigned char)*25*6); |
||
251 | eeprom_write_block(&active,&ee_active,sizeof(unsigned char)*25); |
||
252 | |||
253 | Flash(25,25,10); // fast flash LED 10 times to indicate that we are leaving the learning mode |
||
254 | WaitForKeyRelease(); |
||
255 | } |
||
256 | |||
257 | |||
258 | /*--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
259 | * MAIN: main routine |
||
260 | *--------------------------------------------------------------------------------------------------------------------------------------------------- |
||
261 | */ |
||
262 | int main (void) |
||
263 | { |
||
264 | unsigned char i,j,Servo1,Servo2,Servo1old=99,Servo2old=99; |
||
265 | |||
266 | DDRB = 0b00001000; // IRED output, Switch input |
||
267 | PORTB = 0b00000100; // PullUp for Switch |
||
268 | |||
269 | DDRC = 0b00000000; // Input for Servo-Signals |
||
270 | PORTC = 0b00001100; // PullUp for (unused) Servos |
||
271 | |||
272 | DDRD = 0b10000000; // Input for received IR, output for LED |
||
273 | PORTD = 0b11000000; // PullUp for received IR, LED off |
||
274 | |||
275 | |||
276 | if (eeprom_read_byte(&ee_check)!=0xE7) // When EEPROM is uninitialized, do it now |
||
277 | { |
||
278 | for (i=0;i<5;i++) |
||
279 | { |
||
280 | for (j=0;j<5;j++) |
||
281 | { |
||
282 | active[i][j] = 0; |
||
283 | } |
||
284 | } |
||
285 | |||
286 | eeprom_write_byte(&ee_check, 0xE7); |
||
287 | eeprom_write_block(&active,&ee_active,sizeof(unsigned char)*25); |
||
288 | } |
||
289 | |||
290 | else // else, read in the contents |
||
291 | { |
||
292 | eeprom_read_block(&ir_data,&ee_ir_data,sizeof(unsigned char)*25*6); |
||
293 | eeprom_read_block(&active,&ee_active,sizeof(unsigned char)*25); |
||
294 | } |
||
295 | |||
296 | |||
297 | irmp_init(); // initialize irmp |
||
298 | irsnd_init(); // initialize irsnd |
||
299 | timer_init(); // initialize timer |
||
300 | WaitForKeyRelease(); |
||
301 | sei (); // enable interrupts |
||
302 | |||
303 | |||
304 | while(1) // Main loop |
||
305 | { |
||
306 | if (!(PINB & (1<<PINB2))) Learn(); // Enter learning mode when the button is pressed |
||
307 | |||
308 | Servo1 = Servo(1); // get servo positions |
||
309 | Servo2 = Servo(2); |
||
310 | |||
311 | // when the actual posision was saved before, and the inputs are in a new position, send out its IR-code (single mode) |
||
312 | if (active[Servo1][Servo2] == 1 && (Servo1old != Servo1 || Servo2old != Servo2)) |
||
313 | { |
||
314 | LED(1); // light up LED while sending IR-code |
||
315 | irsnd_send_data(&ir_data[Servo1][Servo2],FALSE); |
||
316 | while (irsnd_is_busy()); // wait until the frame was sent |
||
317 | _delay_ms(100); |
||
318 | LED(0); |
||
319 | } |
||
320 | |||
321 | if (active[Servo1][Servo2] == 2) // when the actual position was saved before, send out its IR-code (multi-mode) |
||
322 | { |
||
323 | LED(1); // light up LED while sending IR-code |
||
324 | irsnd_send_data(&ir_data[Servo1][Servo2],FALSE); |
||
325 | while (irsnd_is_busy()); // wait until the frame was sent |
||
326 | LED(0); |
||
327 | } |
||
328 | |||
329 | Servo1old = Servo1; // save old positions for single-mode |
||
330 | Servo2old = Servo2; |
||
331 | } |
||
332 | |||
333 | } |
||
334 | |||
335 |