17 #define PULSE_BIT PD2 |
17 #define PULSE_BIT PD2 |
18 |
18 |
19 typedef struct { |
19 typedef struct { |
20 uint8_t slot; |
20 uint8_t slot; |
21 uint8_t light; |
21 uint8_t light; |
22 unsigned program:1; // programming mode active |
22 uint8_t program; // 0xff = inactive ; programming mode active on slot X |
|
23 uint8_t initialized; |
23 } config_t; |
24 } config_t; |
24 |
25 config_t EEMEM eeconfig = {0,0,0xff,0}; |
|
26 config_t config; |
25 |
27 |
26 volatile uint16_t data = 0; |
28 volatile uint16_t data = 0; |
27 volatile uint8_t data_len = 0; |
29 volatile uint8_t data_len = 0; |
28 volatile uint8_t bitbuf_len = 0; |
30 volatile uint8_t bitbuf_len = 0; |
29 volatile uint16_t bitbuf = 0; |
31 volatile uint16_t bitbuf = 0; |
34 volatile uint8_t brake_timeout = 0; |
36 volatile uint8_t brake_timeout = 0; |
35 |
37 |
36 |
38 |
37 uint8_t my_switch; |
39 uint8_t my_switch; |
38 uint8_t my_speed; |
40 uint8_t my_speed; |
39 config_t config; |
|
40 |
41 |
41 ISR ( INT0_vect ) { |
42 ISR ( INT0_vect ) { |
42 GICR &= ~_BV(INT0) ; // Disable INT0 |
43 GICR &= ~_BV(INT0) ; // Disable INT0 |
43 // Startsignal erkannt, ab hier den Timer2 starten, |
44 // Startsignal erkannt, ab hier den Timer2 starten, |
44 // der liest dann alle 50µs den Zustand ein und schreibt das |
45 // der liest dann alle 50µs den Zustand ein und schreibt das |
118 #define IR_LED 3 |
119 #define IR_LED 3 |
119 |
120 |
120 #define BRAKE_PORT PORTB |
121 #define BRAKE_PORT PORTB |
121 #define BRAKE 0 |
122 #define BRAKE 0 |
122 |
123 |
123 #define LIGHT_MODES 1 // anzahl der lichtmodi (ohne den modus "aus") |
124 #define LIGHT_MODES 1 // anzahl der lichtmodi (ohne den modus "aus") |
124 |
125 #define BRAKE_OFF_TIMEOUT 60 // value * 10ms |
|
126 |
|
127 #define CAR_DEBUG 1 |
|
128 #define EE_CONFIG_ADDR 64 |
125 |
129 |
126 void config_save(void) { |
130 void config_save(void) { |
127 eeprom_write_block( (void*)&config, 0, sizeof(config) ); |
131 eeprom_write_block( &config, &eeconfig, sizeof(config_t) ); |
128 } |
132 } |
129 |
133 |
130 |
134 |
131 void brake_on(void) { |
135 void brake_on(void) { |
132 LIGHT_PORT |= _BV(LIGHT_BRAKE); // brake light on |
136 LIGHT_PORT |= _BV(LIGHT_BRAKE); // brake light on |
133 BRAKE_PORT |= _BV(BRAKE); // brake on |
137 BRAKE_PORT |= _BV(BRAKE); // brake on |
134 brake_timeout = 50; |
138 brake_timeout = BRAKE_OFF_TIMEOUT; |
135 } |
139 } |
136 |
140 |
137 void brake_off(void) { |
141 void brake_off(void) { |
138 LIGHT_PORT &= ~_BV(LIGHT_BRAKE); // brake light off |
142 LIGHT_PORT &= ~_BV(LIGHT_BRAKE); // brake light off |
139 BRAKE_PORT &= ~_BV(BRAKE); // brake off |
143 BRAKE_PORT &= ~_BV(BRAKE); // brake off |
140 brake_timeout = 0; |
144 brake_timeout = 0; |
141 } |
145 } |
142 |
146 |
|
147 uint8_t scan_id(void) { |
|
148 uint8_t temp; |
|
149 timeout = 1; |
|
150 // scan for any key press and assign to that controller |
|
151 while (car_speed[config.slot] == 0) { |
|
152 for (uint8_t i=0; i<6; i++) { |
|
153 if (car_switch[i] == 1) { |
|
154 // wait for second key press within timeout period to assign successfully |
|
155 brake_timeout = 0xff; |
|
156 temp = car_switch[i]; |
|
157 while (brake_timeout > 1) { |
|
158 if (temp != car_switch[i]) { |
|
159 temp = car_switch[i]; |
|
160 if (temp == 1) { |
|
161 config.slot = i; |
|
162 return 1; |
|
163 } |
|
164 } |
|
165 // toggle lights if timeout |
|
166 if (timeout == 1) { |
|
167 LIGHT_PORT ^= _BV(LIGHT_FRONT); |
|
168 timeout = 5; |
|
169 } |
|
170 } |
|
171 return 0; |
|
172 } |
|
173 } |
|
174 // toggle lights if timeout |
|
175 if (timeout == 1) { |
|
176 LIGHT_PORT ^= _BV(LIGHT_FRONT); |
|
177 timeout = 10; |
|
178 } |
|
179 } |
|
180 return 0; |
|
181 } |
|
182 |
143 int main(void) |
183 int main(void) |
144 { |
184 { |
|
185 uint8_t temp; |
|
186 |
145 // setup data bit timer2 |
187 // setup data bit timer2 |
146 TCCR2 = (1<<CS21) | (1<<WGM21); //divide by 8, set compare match |
188 TCCR2 = (1<<CS21) | (1<<WGM21); //divide by 8, set compare match |
147 OCR2 = TIMER2_50US; |
189 OCR2 = TIMER2_50US; |
148 |
190 |
149 |
191 |
154 |
196 |
155 |
197 |
156 DDR(LIGHT_PORT) |= _BV(LIGHT_FRONT) | _BV(LIGHT_BRAKE); |
198 DDR(LIGHT_PORT) |= _BV(LIGHT_FRONT) | _BV(LIGHT_BRAKE); |
157 DDR(BRAKE_PORT) |= _BV(BRAKE); |
199 DDR(BRAKE_PORT) |= _BV(BRAKE); |
158 |
200 |
159 // config (from eeprom!) |
|
160 eeprom_read_block( (void*)&config, (const void*)0, sizeof(config) ); |
|
161 |
|
162 |
|
163 TCCR1A = (1<<WGM10)|(1<<COM1A1) // Set up the two Control registers of Timer1. |
201 TCCR1A = (1<<WGM10)|(1<<COM1A1) // Set up the two Control registers of Timer1. |
164 |(1<<COM1B1); // Wave Form Generation is Fast PWM 8 Bit, |
202 |(1<<COM1B1); // Wave Form Generation is Fast PWM 8 Bit, |
165 |
203 |
166 TCCR1B = (1<<WGM12)|(1<<CS10); // OC1A and OC1B are cleared on compare match |
204 TCCR1B = (1<<WGM12)|(1<<CS10); // OC1A and OC1B are cleared on compare match |
167 // and set at BOTTOM. Clock Prescaler is 1. |
205 // and set at BOTTOM. Clock Prescaler is 1. |
169 |
207 |
170 //OCR1A = 63; // Dutycycle of OC1A = 25% |
208 //OCR1A = 63; // Dutycycle of OC1A = 25% |
171 //OCR1B = 127; // Dutycycle of OC1B = 50% |
209 //OCR1B = 127; // Dutycycle of OC1B = 50% |
172 OCR1A = 0; |
210 OCR1A = 0; |
173 OCR1B = 0; |
211 OCR1B = 0; |
|
212 DDRB &= ~_BV(2); // PB2 PWM Output disable |
174 |
213 |
175 // configure TIMER0 to overflow every 10ms at 4 MHz |
214 // configure TIMER0 to overflow every 10ms at 4 MHz |
176 TIMSK = _BV(TOIE0); // Timer0 Overflow INT erlauben |
215 TIMSK = _BV(TOIE0); // Timer0 Overflow INT erlauben |
177 TCNT0 = 100; // TIMER0 vorladen mit 100 |
216 TCNT0 = 100; // TIMER0 vorladen mit 100 |
178 TCCR0 = _BV(CS02) ; // Vorteiler auf 256, ab hier läuft der TIMER0 |
217 TCCR0 = _BV(CS02) ; // Vorteiler auf 256, ab hier läuft der TIMER0 |
179 |
218 |
180 sei(); |
219 sei(); |
181 |
220 |
182 |
221 // config (from eeprom!) |
183 config.slot = 1; |
222 eeprom_read_block( &config, &eeconfig, sizeof(config_t) ); |
|
223 |
|
224 |
|
225 #ifdef CAR_DEBUG |
|
226 if (config.initialized == 0) { |
|
227 LIGHT_PORT &= ~_BV(LIGHT_FRONT); |
|
228 for (temp = 0; temp <= config.slot; temp++) { |
|
229 LIGHT_PORT ^= _BV(LIGHT_FRONT); |
|
230 _delay_ms(250); |
|
231 LIGHT_PORT ^= _BV(LIGHT_FRONT); |
|
232 _delay_ms(250); |
|
233 } |
|
234 } |
|
235 #endif |
|
236 |
|
237 |
|
238 |
|
239 if (config.initialized != 0) { |
|
240 config.slot = 0; |
|
241 config.light = 0; |
|
242 config.program = 0; |
|
243 config.initialized = 0; |
|
244 config_save(); |
|
245 } |
|
246 |
|
247 if ((config.program != 0xff) || (config.slot > 5 )) { |
|
248 temp = scan_id(); |
|
249 config.program = 0xff; |
|
250 config_save(); |
|
251 if (temp == 1) { |
|
252 // acknowledge with the engine |
|
253 OCR1B = 25; |
|
254 DDRB &= ~_BV(2); // PB2 PWM Output disable |
|
255 for (temp = 0xff; temp > 0; temp--) { |
|
256 DDRB ^= _BV(2); // PB2 PWM Output toggle |
|
257 _delay_ms(5); // 50 hz |
|
258 DDRB ^= _BV(2); // PB2 PWM Output toggle |
|
259 _delay_ms(15); // 50 hz |
|
260 } |
|
261 |
|
262 } |
|
263 timeout = 0; |
|
264 } |
|
265 |
184 |
266 |
185 while (1) { |
267 while (1) { |
186 // main loop |
268 // main loop |
187 |
269 |
188 if (brake_timeout == 1) { |
270 if (brake_timeout == 1) brake_off(); |
189 DDRB &= ~_BV(2); // PB2 PWM Output disable |
|
190 brake_off(); |
|
191 } |
|
192 |
271 |
193 if (my_speed != car_speed[config.slot]) { |
272 if (my_speed != car_speed[config.slot]) { |
194 my_speed = car_speed[config.slot]; |
273 my_speed = car_speed[config.slot]; |
195 OCR1B = (int) ((float)0xff * (float)((float)my_speed / (float)15)); |
274 OCR1B = (int) ((float)0xff * (float)((float)my_speed / (float)15)); |
196 if (my_speed == 0) { |
275 if (my_speed == 0) { |
207 if (my_switch != car_switch[config.slot]) { |
286 if (my_switch != car_switch[config.slot]) { |
208 my_switch = car_switch[config.slot]; |
287 my_switch = car_switch[config.slot]; |
209 if (my_switch != 0) { |
288 if (my_switch != 0) { |
210 // cycle light |
289 // cycle light |
211 if (config.light == LIGHT_MODES) config.light = 0; else config.light++; |
290 if (config.light == LIGHT_MODES) config.light = 0; else config.light++; |
|
291 if (timeout > 1) { |
|
292 // zweiter Tastendruck, Program Mode im EEPROM setzen |
|
293 config.program = 1; // TODO: hier muss der slot rein welcher doppelclicked wurde (natuerlich dann auch nicht in der Lichtschaltelogik abfragen!) |
|
294 } else { |
|
295 // erster Tastendruck, timeout setzen |
|
296 timeout = 80; |
|
297 } |
|
298 config_save(); |
212 } |
299 } |
213 } |
300 } |
214 } |
301 } |
215 |
302 |
216 switch (config.light) { |
303 switch (config.light) { |