car004f/main.c

changeset 152
e787f47c084b
parent 151
0e71b51c83a5
child 153
80d869ac365b
equal deleted inserted replaced
151:0e71b51c83a5 152:e787f47c084b
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;
83 } 87 }
84 } 88 }
85 */ 89 */
86 } 90 }
87 91
92 // bugfix 20131223: timing errors, CLEAR timer2 flag before enable
93 // if this works, apply to track switches and pitlane too!
94 //GIFR = _BV(INTF0);
95
96 GICR |= _BV(INT0) ; // Enable INT0
88 97
89 } else { 98 } else {
90 bitbuf_len++; // increment bit counter 99 bitbuf_len++; // increment bit counter
91 bitbuf = bitbuf << 1; // shift bits 100 bitbuf = bitbuf << 1; // shift bits
92 if (state2 == 0) bitbuf |= 1; // receive logic one 101 if (state2 == 0) bitbuf |= 1; // receive logic one
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:

mercurial