Subversion Repositories Projects

Rev

Rev 838 | Details | Compare with Previous | 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
/*---------------------------------------------------------------------------------------------------------------------------------------------------
841 - 169
 * Get position from servo inputs 1 and 2. Returns 1/2/3 for down/middle/up, 0 for GND and 4 for VCC
838 - 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);
841 - 230
      ir_temp.flags = 0;                 // ignore repeat-flag
838 - 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();
841 - 301
  sei();                                 // enable interrupts
838 - 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