15 |
15 |
16 #define PULSE_PORT PORTD |
16 #define PULSE_PORT PORTD |
17 #define PULSE_BIT PD2 |
17 #define PULSE_BIT PD2 |
18 |
18 |
19 typedef struct { |
19 typedef struct { |
|
20 uint8_t calibration; // AVR Chip calibration byte written by avrdude |
|
21 uint8_t initialized; // if 0xff, reset config to defaults on first boot |
20 uint8_t slot; |
22 uint8_t slot; |
21 uint8_t light; |
23 uint8_t light; |
22 uint8_t program; // 0xff = inactive ; programming mode active on slot X |
24 uint8_t program; // 0xff = inactive ; programming mode active on slot X |
23 uint8_t initialized; |
|
24 } config_t; |
25 } config_t; |
25 config_t EEMEM eeconfig = {0,0,0xff,0}; |
26 config_t EEMEM eeconfig = {0,0,0,0xff,0}; |
26 config_t config; |
27 config_t config; |
27 |
28 |
28 volatile uint16_t data = 0; |
29 volatile uint16_t data = 0; |
29 volatile uint8_t data_len = 0; |
30 volatile uint8_t data_len = 0; |
30 volatile uint8_t bitbuf_len = 0; |
31 volatile uint8_t bitbuf_len = 0; |
31 volatile uint16_t bitbuf = 0; |
32 volatile uint16_t bitbuf = 0; |
32 volatile uint8_t car_speed[8]; |
33 volatile uint8_t car_speed[MAX_SLOTS]; |
33 volatile uint8_t car_switch[8]; |
34 volatile uint8_t car_switch[MAX_SLOTS]; |
34 |
35 |
|
36 volatile uint8_t car_timeout[MAX_SLOTS]; |
35 volatile uint8_t timeout = 0; |
37 volatile uint8_t timeout = 0; |
36 volatile uint8_t brake_timeout = 0; |
38 volatile uint8_t brake_timeout = 0; |
37 |
39 |
|
40 uint8_t old_switch[MAX_SLOTS]; |
38 |
41 |
39 uint8_t my_switch; |
42 uint8_t my_switch; |
40 uint8_t my_speed; |
43 uint8_t my_speed; |
41 |
44 |
42 ISR ( INT0_vect ) { |
45 ISR ( INT0_vect ) { |
44 // Startsignal erkannt, ab hier den Timer2 starten, |
47 // Startsignal erkannt, ab hier den Timer2 starten, |
45 // der liest dann alle 50µs den Zustand ein und schreibt das |
48 // der liest dann alle 50µs den Zustand ein und schreibt das |
46 // empfangene Bit in den Puffer |
49 // empfangene Bit in den Puffer |
47 bitbuf = 0; // init |
50 bitbuf = 0; // init |
48 bitbuf_len = 0b10000000; // init 1 pulse received |
51 bitbuf_len = 0b10000000; // init 1 pulse received |
49 TCNT2 = 0; |
52 |
|
53 TCNT2 = 10; |
50 TIMSK |= _BV(OCIE2); //enable timer2 interrupt |
54 TIMSK |= _BV(OCIE2); //enable timer2 interrupt |
51 } |
55 } |
52 |
56 |
53 ISR ( TIMER2_COMP_vect ) { |
57 ISR ( TIMER2_COMP_vect ) { |
54 uint8_t clock; |
58 uint8_t clock; |
60 |
64 |
61 if (clock) { |
65 if (clock) { |
62 bitbuf_len &= ~_BV(7); // switch clock to low |
66 bitbuf_len &= ~_BV(7); // switch clock to low |
63 // second pulse of bit |
67 // second pulse of bit |
64 if ((state==state2) & state2) { |
68 if ((state==state2) & state2) { |
|
69 TIMSK &= ~_BV(OCIE2); //disable timer2 interrupt |
|
70 |
65 // two cycles high: packet end received |
71 // two cycles high: packet end received |
66 data_len = (bitbuf_len & 0b00111111); |
72 data_len = (bitbuf_len & 0b00111111); |
67 TIMSK &= ~_BV(OCIE2); //disable timer2 interrupt |
|
68 GICR |= _BV(INT0) ; // Enable INT0 |
|
69 |
73 |
70 //data = bitbuf; // output data |
74 //data = bitbuf; // output data |
71 // write data of controllers to array |
75 // write data of controllers to array |
72 if (data_len == 10) { // controller data packet |
76 if (data_len == 10) { // controller data packet |
73 clock = (bitbuf >> 6) & 0b00000111; |
77 clock = (bitbuf >> 6) & 0b00000111; |
107 |
116 |
108 ISR (TIMER0_OVF_vect) { |
117 ISR (TIMER0_OVF_vect) { |
109 TCNT0 = 100; // TIMER0 vorladen mit 100 |
118 TCNT0 = 100; // TIMER0 vorladen mit 100 |
110 if (brake_timeout > 1) brake_timeout--; |
119 if (brake_timeout > 1) brake_timeout--; |
111 if (timeout > 1) timeout--; |
120 if (timeout > 1) timeout--; |
|
121 for (uint8_t i=0; i<MAX_SLOTS; i++) |
|
122 if (car_timeout[i] > 1) car_timeout[i]--; |
112 } |
123 } |
113 |
124 |
114 #define LIGHT_PORT PORTC |
125 #define LIGHT_PORT PORTC |
115 #define LIGHT_FRONT 2 |
126 #define LIGHT_FRONT 2 |
116 #define LIGHT_BRAKE 4 |
127 #define LIGHT_BRAKE 4 |
117 |
128 |
118 #define IR_PORT PORTB |
129 #define IR_PORT PORTB |
119 #define IR_LED 3 |
130 #define IR_LED 3 |
120 |
131 |
121 #define BRAKE_PORT PORTB |
|
122 #define BRAKE 0 |
|
123 |
|
124 #define LIGHT_MODES 1 // anzahl der lichtmodi (ohne den modus "aus") |
132 #define LIGHT_MODES 1 // anzahl der lichtmodi (ohne den modus "aus") |
125 #define BRAKE_OFF_TIMEOUT 60 // value * 10ms |
133 #define BRAKE_OFF_TIMEOUT 60 // value * 10ms |
126 |
134 |
127 //#define CAR_DEBUG 1 |
135 //#define CAR_DEBUG 1 |
128 #define EE_CONFIG_ADDR 64 |
136 #define EE_CONFIG_ADDR 64 |
133 } |
141 } |
134 |
142 |
135 |
143 |
136 void brake_on(void) { |
144 void brake_on(void) { |
137 LIGHT_PORT |= _BV(LIGHT_BRAKE); // brake light on |
145 LIGHT_PORT |= _BV(LIGHT_BRAKE); // brake light on |
138 BRAKE_PORT |= _BV(BRAKE); // brake on |
146 DDRB |= _BV(1); // PB1 PWM Output enable |
139 DDRB &= ~_BV(1); // PB1 PWM Output enable |
|
140 brake_timeout = BRAKE_OFF_TIMEOUT; |
147 brake_timeout = BRAKE_OFF_TIMEOUT; |
141 } |
148 } |
142 |
149 |
143 void brake_off(void) { |
150 void brake_off(void) { |
144 LIGHT_PORT &= ~_BV(LIGHT_BRAKE); // brake light off |
151 LIGHT_PORT &= ~_BV(LIGHT_BRAKE); // brake light off |
145 BRAKE_PORT &= ~_BV(BRAKE); // brake off |
|
146 DDRB &= ~_BV(1); // PB1 PWM Output disable |
152 DDRB &= ~_BV(1); // PB1 PWM Output disable |
147 brake_timeout = 0; |
153 brake_timeout = 0; |
148 } |
154 } |
149 |
155 |
150 uint8_t set_id(void) { |
156 uint8_t set_id(void) { |
185 return 0; |
191 return 0; |
186 } |
192 } |
187 |
193 |
188 int main(void) |
194 int main(void) |
189 { |
195 { |
190 uint8_t temp; |
|
191 |
|
192 // setup data bit timer2 |
|
193 TCCR2 = (1<<CS21) | (1<<WGM21); //divide by 8, set compare match |
|
194 OCR2 = TIMER2_50US; |
|
195 |
|
196 |
|
197 // enable both external interrupts |
|
198 // int 0 = data RX |
|
199 MCUCR = _BV(ISC00) | _BV(ISC01) | _BV(ISC10) | _BV(ISC11); // INT0/1 rising edge |
|
200 GICR = _BV(INT0) | _BV(INT1) ; // Enable INT0 + INT1 |
|
201 |
|
202 |
|
203 DDR(LIGHT_PORT) |= _BV(LIGHT_FRONT) | _BV(LIGHT_BRAKE); |
|
204 DDR(BRAKE_PORT) |= _BV(BRAKE); |
|
205 |
|
206 TCCR1A = (1<<WGM10)|(1<<COM1A1) // Set up the two Control registers of Timer1. |
|
207 |(1<<COM1B1); // Wave Form Generation is Fast PWM 8 Bit, |
|
208 |
|
209 TCCR1B = (1<<WGM12)|(1<<CS10); // OC1A and OC1B are cleared on compare match |
|
210 // and set at BOTTOM. Clock Prescaler is 1. |
|
211 |
|
212 |
|
213 //OCR1A = 63; // Dutycycle of OC1A = 25% |
|
214 //OCR1B = 127; // Dutycycle of OC1B = 50% |
|
215 OCR1A = 0xff; // brake PWM?! |
|
216 OCR1B = 0; // Motor drive PWM |
|
217 DDRB &= ~_BV(2); // PB2 PWM Output disable |
|
218 DDRB &= ~_BV(1); // PB1 PWM Output disable |
|
219 |
|
220 // configure TIMER0 to overflow every 10ms at 4 MHz |
|
221 TIMSK = _BV(TOIE0); // Timer0 Overflow INT erlauben |
|
222 TCNT0 = 100; // TIMER0 vorladen mit 100 |
|
223 TCCR0 = _BV(CS02) ; // Vorteiler auf 256, ab hier läuft der TIMER0 |
|
224 |
|
225 sei(); |
|
226 |
|
227 // config (from eeprom!) |
196 // config (from eeprom!) |
228 eeprom_read_block( &config, &eeconfig, sizeof(config_t) ); |
197 eeprom_read_block( &config, &eeconfig, sizeof(config_t) ); |
229 |
198 |
|
199 // set the internal calibration byte |
|
200 OSCCAL = config.calibration; |
|
201 // TODO: Vielleicht den internen Takt des AVR anhand der Bitclock auf den Schienen synchronisieren??? |
|
202 // Das Calibration byte scheint nicht zu stimmen |
230 |
203 |
231 if (config.initialized == 0xff) { |
204 if (config.initialized == 0xff) { |
232 config.slot = 0; |
205 config.slot = 0; |
233 config.light = 0; |
206 config.light = 0; |
234 config.program = 0xff; |
207 config.program = 0xff; |
235 config.initialized = 0; |
208 config.initialized = 0; |
236 config_save(); |
209 config_save(); |
237 } |
210 } |
|
211 |
|
212 uint8_t temp; |
|
213 |
|
214 // setup data bit timer2 |
|
215 TCCR2 = (1<<CS21) | (1<<WGM21); //divide by 8, set compare match |
|
216 OCR2 = TIMER2_50US; |
|
217 |
|
218 |
|
219 // enable both external interrupts |
|
220 // int 0 = data RX |
|
221 MCUCR = _BV(ISC00) | _BV(ISC01) | _BV(ISC10) | _BV(ISC11); // INT0/1 rising edge |
|
222 GICR = _BV(INT0) | _BV(INT1) ; // Enable INT0 + INT1 |
|
223 |
|
224 |
|
225 DDR(LIGHT_PORT) |= _BV(LIGHT_FRONT) | _BV(LIGHT_BRAKE); |
|
226 |
|
227 TCCR1A = (1<<WGM10)|(1<<COM1A1) // Set up the two Control registers of Timer1. |
|
228 |(1<<COM1B1); // Wave Form Generation is Fast PWM 8 Bit, |
|
229 |
|
230 TCCR1B = (1<<WGM12)|(1<<CS10); // OC1A and OC1B are cleared on compare match |
|
231 // and set at BOTTOM. Clock Prescaler is 1. |
|
232 |
|
233 |
|
234 //OCR1A = 63; // Dutycycle of OC1A = 25% |
|
235 //OCR1B = 127; // Dutycycle of OC1B = 50% |
|
236 OCR1A = 0xff; // brake PWM! |
|
237 OCR1B = 0; // Motor drive PWM |
|
238 DDRB &= ~_BV(2); // PB2 PWM Output disable |
|
239 DDRB &= ~_BV(1); // PB1 PWM Output disable |
|
240 |
|
241 // configure TIMER0 to overflow every 10ms at 4 MHz |
|
242 TIMSK = _BV(TOIE0); // Timer0 Overflow INT erlauben |
|
243 TCNT0 = 100; // TIMER0 vorladen mit 100 |
|
244 TCCR0 = _BV(CS02) ; // Vorteiler auf 256, ab hier läuft der TIMER0 |
|
245 |
|
246 sei(); |
|
247 |
238 |
248 |
239 if ((config.program != 0xff) || (config.slot > 5 )) { |
249 if ((config.program != 0xff) || (config.slot > 5 )) { |
240 temp = set_id(); |
250 temp = set_id(); |
241 config.program = 0xff; |
251 config.program = 0xff; |
242 config_save(); |
252 config_save(); |
280 if (car_speed[config.slot] == 0) { |
290 if (car_speed[config.slot] == 0) { |
281 if (my_switch != car_switch[config.slot]) { |
291 if (my_switch != car_switch[config.slot]) { |
282 my_switch = car_switch[config.slot]; |
292 my_switch = car_switch[config.slot]; |
283 if (my_switch == 0) { |
293 if (my_switch == 0) { |
284 // cycle light |
294 // cycle light |
285 if (config.light == LIGHT_MODES) config.light = 0; else config.light++; |
295 if (config.light >= LIGHT_MODES) config.light = 0; else config.light++; |
286 if (timeout > 1) { |
|
287 // zweiter Tastendruck, Program Mode im EEPROM setzen |
|
288 config.program = config.slot; // TODO: hier muss der slot rein welcher doppelclicked wurde (natuerlich dann auch nicht in der Lichtschaltelogik abfragen!) |
|
289 } else { |
|
290 // erster Tastendruck, timeout setzen |
|
291 timeout = DOUBLE_CLICK_TIMEOUT; |
|
292 } |
|
293 config_save(); |
296 config_save(); |
294 } |
297 } |
|
298 } |
|
299 } |
|
300 |
|
301 // check any car switch for a double click and speed = 0 |
|
302 for (temp = 0; temp<MAX_SLOTS; temp++) if (car_switch[temp] != old_switch[temp]) { |
|
303 old_switch[temp] = car_switch[temp]; |
|
304 if ((car_speed[temp] == 0) && (old_switch[temp] == 0)) { |
|
305 // key pressed |
|
306 if (car_timeout[temp] > 1) { |
|
307 // second key press within timeout, enter program mode for this key |
|
308 config.program = temp; |
|
309 config_save(); |
|
310 car_timeout[temp] = 0xff; // the car has to be reset within this timeout |
|
311 } else { |
|
312 car_timeout[temp] = DOUBLE_CLICK_TIMEOUT; |
|
313 } |
|
314 } |
|
315 |
|
316 if (car_timeout[temp] == 1) { |
|
317 if (config.program == temp) { |
|
318 // cancel ID programming mode |
|
319 config.program = 0xff; |
|
320 config_save(); |
|
321 } |
|
322 car_timeout[temp] = 0; |
295 } |
323 } |
296 } |
324 } |
297 |
325 |
298 switch (config.light) { |
326 switch (config.light) { |
299 case 0: |
327 case 0: |