--- a/car004f/main.c Mon Dec 23 10:59:14 2013 +0100 +++ b/car004f/main.c Mon Dec 23 14:05:53 2013 +0100 @@ -17,24 +17,27 @@ #define PULSE_BIT PD2 typedef struct { + uint8_t calibration; // AVR Chip calibration byte written by avrdude + uint8_t initialized; // if 0xff, reset config to defaults on first boot uint8_t slot; uint8_t light; uint8_t program; // 0xff = inactive ; programming mode active on slot X - uint8_t initialized; } config_t; -config_t EEMEM eeconfig = {0,0,0xff,0}; +config_t EEMEM eeconfig = {0,0,0,0xff,0}; config_t config; volatile uint16_t data = 0; volatile uint8_t data_len = 0; volatile uint8_t bitbuf_len = 0; volatile uint16_t bitbuf = 0; -volatile uint8_t car_speed[8]; -volatile uint8_t car_switch[8]; +volatile uint8_t car_speed[MAX_SLOTS]; +volatile uint8_t car_switch[MAX_SLOTS]; +volatile uint8_t car_timeout[MAX_SLOTS]; volatile uint8_t timeout = 0; volatile uint8_t brake_timeout = 0; +uint8_t old_switch[MAX_SLOTS]; uint8_t my_switch; uint8_t my_speed; @@ -46,7 +49,8 @@ // empfangene Bit in den Puffer bitbuf = 0; // init bitbuf_len = 0b10000000; // init 1 pulse received - TCNT2 = 0; + + TCNT2 = 10; TIMSK |= _BV(OCIE2); //enable timer2 interrupt } @@ -62,10 +66,10 @@ bitbuf_len &= ~_BV(7); // switch clock to low // second pulse of bit if ((state==state2) & state2) { + TIMSK &= ~_BV(OCIE2); //disable timer2 interrupt + // two cycles high: packet end received data_len = (bitbuf_len & 0b00111111); - TIMSK &= ~_BV(OCIE2); //disable timer2 interrupt - GICR |= _BV(INT0) ; // Enable INT0 //data = bitbuf; // output data // write data of controllers to array @@ -85,6 +89,11 @@ */ } + // bugfix 20131223: timing errors, CLEAR timer2 flag before enable + // if this works, apply to track switches and pitlane too! + //GIFR = _BV(INTF0); + + GICR |= _BV(INT0) ; // Enable INT0 } else { bitbuf_len++; // increment bit counter @@ -109,6 +118,8 @@ TCNT0 = 100; // TIMER0 vorladen mit 100 if (brake_timeout > 1) brake_timeout--; if (timeout > 1) timeout--; + for (uint8_t i=0; i<MAX_SLOTS; i++) + if (car_timeout[i] > 1) car_timeout[i]--; } #define LIGHT_PORT PORTC @@ -118,9 +129,6 @@ #define IR_PORT PORTB #define IR_LED 3 -#define BRAKE_PORT PORTB -#define BRAKE 0 - #define LIGHT_MODES 1 // anzahl der lichtmodi (ohne den modus "aus") #define BRAKE_OFF_TIMEOUT 60 // value * 10ms @@ -135,14 +143,12 @@ void brake_on(void) { LIGHT_PORT |= _BV(LIGHT_BRAKE); // brake light on - BRAKE_PORT |= _BV(BRAKE); // brake on - DDRB &= ~_BV(1); // PB1 PWM Output enable + DDRB |= _BV(1); // PB1 PWM Output enable brake_timeout = BRAKE_OFF_TIMEOUT; } void brake_off(void) { LIGHT_PORT &= ~_BV(LIGHT_BRAKE); // brake light off - BRAKE_PORT &= ~_BV(BRAKE); // brake off DDRB &= ~_BV(1); // PB1 PWM Output disable brake_timeout = 0; } @@ -187,6 +193,22 @@ int main(void) { + // config (from eeprom!) + eeprom_read_block( &config, &eeconfig, sizeof(config_t) ); + + // set the internal calibration byte + OSCCAL = config.calibration; + // TODO: Vielleicht den internen Takt des AVR anhand der Bitclock auf den Schienen synchronisieren??? + // Das Calibration byte scheint nicht zu stimmen + + if (config.initialized == 0xff) { + config.slot = 0; + config.light = 0; + config.program = 0xff; + config.initialized = 0; + config_save(); + } + uint8_t temp; // setup data bit timer2 @@ -201,7 +223,6 @@ DDR(LIGHT_PORT) |= _BV(LIGHT_FRONT) | _BV(LIGHT_BRAKE); - DDR(BRAKE_PORT) |= _BV(BRAKE); TCCR1A = (1<<WGM10)|(1<<COM1A1) // Set up the two Control registers of Timer1. |(1<<COM1B1); // Wave Form Generation is Fast PWM 8 Bit, @@ -212,7 +233,7 @@ //OCR1A = 63; // Dutycycle of OC1A = 25% //OCR1B = 127; // Dutycycle of OC1B = 50% - OCR1A = 0xff; // brake PWM?! + OCR1A = 0xff; // brake PWM! OCR1B = 0; // Motor drive PWM DDRB &= ~_BV(2); // PB2 PWM Output disable DDRB &= ~_BV(1); // PB1 PWM Output disable @@ -224,17 +245,6 @@ sei(); - // config (from eeprom!) - eeprom_read_block( &config, &eeconfig, sizeof(config_t) ); - - - if (config.initialized == 0xff) { - config.slot = 0; - config.light = 0; - config.program = 0xff; - config.initialized = 0; - config_save(); - } if ((config.program != 0xff) || (config.slot > 5 )) { temp = set_id(); @@ -282,19 +292,37 @@ my_switch = car_switch[config.slot]; if (my_switch == 0) { // cycle light - if (config.light == LIGHT_MODES) config.light = 0; else config.light++; - if (timeout > 1) { - // zweiter Tastendruck, Program Mode im EEPROM setzen - config.program = config.slot; // TODO: hier muss der slot rein welcher doppelclicked wurde (natuerlich dann auch nicht in der Lichtschaltelogik abfragen!) - } else { - // erster Tastendruck, timeout setzen - timeout = DOUBLE_CLICK_TIMEOUT; - } + if (config.light >= LIGHT_MODES) config.light = 0; else config.light++; config_save(); } } } + // check any car switch for a double click and speed = 0 + for (temp = 0; temp<MAX_SLOTS; temp++) if (car_switch[temp] != old_switch[temp]) { + old_switch[temp] = car_switch[temp]; + if ((car_speed[temp] == 0) && (old_switch[temp] == 0)) { + // key pressed + if (car_timeout[temp] > 1) { + // second key press within timeout, enter program mode for this key + config.program = temp; + config_save(); + car_timeout[temp] = 0xff; // the car has to be reset within this timeout + } else { + car_timeout[temp] = DOUBLE_CLICK_TIMEOUT; + } + } + + if (car_timeout[temp] == 1) { + if (config.program == temp) { + // cancel ID programming mode + config.program = 0xff; + config_save(); + } + car_timeout[temp] = 0; + } + } + switch (config.light) { case 0: LIGHT_PORT &= ~_BV(LIGHT_FRONT); // switch lights off