car004f/main.c

changeset 152
e787f47c084b
parent 151
0e71b51c83a5
child 153
80d869ac365b
--- 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

mercurial