pitlane/main.c

changeset 63
ea1e8dcbec44
child 64
61f88f973eba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pitlane/main.c	Fri Dec 09 20:02:17 2011 +0100
@@ -0,0 +1,325 @@
+#include <avr/interrupt.h>
+#include <avr/io.h>
+#include <avr/wdt.h>
+#include <avr/eeprom.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <avr/pgmspace.h>
+
+#include "main.h"
+
+#include "driver/rs232.h"
+#include "util/delay.h"
+
+
+ISR ( USART_RXC_vect ) {
+}
+
+#define PULSE_PORT      PORTD
+#define PULSE_BIT       PD2
+#define RESPONSE_PORT   PORTC
+#define RESPONSE_PIN    PC1
+#define SOLENOID_A_PORT PORTB
+#define SOLENOID_B_PORT PORTB
+#define SOLENOID_A_PIN  PB1
+#define SOLENOID_B_PIN  PB2
+
+#define TRACKSWITCH_TYPE 2 // 1=double, 2=single, 3=pitlane
+
+
+// internal analog comparator doesnt work well
+//#define ANALOG_COMPARATOR       1
+
+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 uint16_t car0, car1, car2;
+volatile uint16_t car0_new, car0_old;
+volatile uint16_t car1_new, car1_old;
+volatile uint16_t car2_new, car2_old;
+
+volatile uint8_t response = 0;
+uint8_t self_id = 0b1111; // ONLY ONE pitlane
+
+void send_response(uint16_t data) {
+    /* frame format:
+        1 startbit
+        2 car id
+        3 car id
+        4 car id
+        5 track change status bit 1
+        6 track change status bit 2
+        7 sender id
+        8 sender id
+        9 sender id
+        9 sender id
+        10 device type
+        11 device type
+        12 device type
+        13 device type
+        14 reserved
+        15 reserved
+        16 stopbit
+    */
+    uint8_t index = 16; // bit count maximum
+    uint8_t enable = DDR(RESPONSE_PORT) | _BV(RESPONSE_PIN);
+    uint8_t disable = DDR(RESPONSE_PORT) & ~_BV(RESPONSE_PIN);
+    data |= 0b100000000000001; // make sure start/stop bits are set
+    data = 0b1010101010101011;
+    while (index != 0) {
+        if ((data & 1) != 0) {
+            DDR(RESPONSE_PORT) = enable; // enable response output
+        } else {
+            DDR(RESPONSE_PORT) = disable; // disable response output
+        }
+        data = data >> 1; // next bit prepare
+        index--; // decrement index
+        _delay_us(49); // bit valid phase
+    }
+    // finally be sure to release the bus!
+    DDR(RESPONSE_PORT) = disable; // disable response output
+}
+
+
+ISR ( INT0_vect ) {
+    GICR &= ~_BV(INT0) ; // Disable INT0
+    // Startsignal erkannt, ab hier den Timer2 starten,
+    // der liest dann alle 50µs den Zustand ein und schreibt das
+    // empfangene Bit in den Puffer
+    bitbuf = 0; // init
+    bitbuf_len = 0b10000000; // init 1 pulse received
+    TCNT2 = 0;
+    TIMSK |= _BV(OCIE2); //enable timer2 interrupt
+}
+
+ISR ( TIMER2_COMP_vect ) {
+    uint8_t clock;
+    uint8_t state;
+    uint8_t state2;
+    if ((bitbuf_len & 0b10000000) == 0) clock = 0; else clock = 0xff;
+    if ((bitbuf_len & 0b01000000) == 0) state = 0; else state = 0xff;
+    if ((PIN(PULSE_PORT) & _BV(PULSE_BIT)) == 0) state2 = 0xff; else state2 = 0;
+
+    if (clock) {
+        bitbuf_len &= ~_BV(7); // switch clock to low
+        // second pulse of bit
+        if ((state==state2) & state2) {
+            // 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
+            if (data_len == 10) { // controller data packet
+                clock = (bitbuf >> 6) & 0b00000111;
+                car_speed[clock] = (bitbuf >> 1) & 0x0F;
+                car_switch[clock] = (bitbuf >> 5) & 1;
+                // current response for this car?
+                if (response != 0) {
+                    if ( ((response & 0b00001110) >> 1) == clock) {
+                        // add our ID to response:
+                        send_response(response | (self_id << 6));
+                        response = 0;
+                    }
+                }
+            }
+
+
+        } else {
+            bitbuf_len++; // increment bit counter
+            bitbuf = bitbuf << 1; // shift bits
+            if (state2 == 0) bitbuf |= 1; // receive logic one
+        }
+    } else {
+        bitbuf_len |= _BV(7); // switch clock to high
+        // first pulse of bit
+        if (state2) {
+            bitbuf_len |= _BV(6); // store new state
+        } else {
+            bitbuf_len &= ~_BV(6); // store new state
+        }
+    }
+}
+
+
+ISR (TIMER1_OVF_vect) {
+    // reset both car counters to overflow
+    car0_old = 0xffff;
+    car1_old = 0xffff;
+    // pitlane exit sensor
+    car2_old = 0xffff;
+}
+
+ISR (INT1_vect) {
+    // car0 detector
+    uint16_t tmp = 0;
+    car0_new = TCNT1; // get current counter
+    if (car0_old < car0_new) {
+        // calculate difference
+        if (car0 == 0) tmp = car0_new-car0_old;
+        if ( (tmp > 54) && (tmp < 74) ) car0 = 1;
+        if ( (tmp > 118) && (tmp < 138) ) car0 = 2;
+        if ( (tmp > 186) && (tmp < 206) ) car0 = 3;
+        if ( (tmp > 246) && (tmp < 266) ) car0 = 4;
+        if ( (tmp > 310) && (tmp < 330) ) car0 = 5;
+        if ( (tmp > 374) && (tmp < 394) ) car0 = 6;
+    }
+    car0_old = car0_new;
+}
+
+// ISR (TIMER1_CAPT_vect) {
+#ifdef ANALOG_COMPARATOR
+ISR (ANA_COMP_vect) {
+    // car1 detector
+    uint16_t tmp = 0;
+    car1_new = TCNT1; // get current counter
+    if (car1_old < car1_new) {
+        // calculate difference
+        if (car1 == 0) tmp = car1_new-car1_old;
+        if ( (tmp > 50) && (tmp < 78) ) car1 = 1;
+        if ( (tmp > 114) && (tmp < 146) ) car1 = 2;
+        if ( (tmp > 183) && (tmp < 210) ) car1 = 3;
+        if ( (tmp > 242) && (tmp < 270) ) car1 = 4;
+        if ( (tmp > 310) && (tmp < 330) ) car1 = 5;
+        if ( (tmp > 374) && (tmp < 394) ) car1 = 6;
+    }
+    car1_old = car1_new;
+}
+#else
+// ALTERNATIV:
+ISR (TIMER1_CAPT_vect) {
+    // car1 detector
+    uint16_t tmp = 0;
+    car1_new = TCNT1; // get current counter
+    if (car1_old < car1_new) {
+        // calculate difference
+        if (car1 == 0) tmp = car1_new-car1_old;
+        if ( (tmp > 50) && (tmp < 78) ) car1 = 1;
+        if ( (tmp > 114) && (tmp < 146) ) car1 = 2;
+        if ( (tmp > 183) && (tmp < 210) ) car1 = 3;
+        if ( (tmp > 242) && (tmp < 270) ) car1 = 4;
+        if ( (tmp > 310) && (tmp < 330) ) car1 = 5;
+        if ( (tmp > 374) && (tmp < 394) ) car1 = 6;
+    }
+    car1_old = car1_new;
+}
+#endif
+
+void solenoid_delay(void) {
+    _delay_ms(10);
+}
+
+
+
+
+int main(void)
+{
+    uint8_t car0_state, car1_state;
+
+    // setup data bit timer2
+    TCCR2 = (1<<CS21) | (1<<WGM21); //divide by 8, set compare match
+    OCR2 = TIMER2_50US;
+
+    // initialize timer1 for IR signal detection
+#ifdef ANALOG_COMPARATOR
+    TCCR1B = _BV(CS01) ; // 1mhz clock
+    TIMSK = _BV(OCIE2) | _BV(TOIE1) ; //enable timer1+2
+#else
+    TCCR1B = _BV(CS01) | _BV(ICNC1) | _BV(ICES1); // 1mhz clock, enable ICP on rising edge
+    TIMSK = _BV(OCIE2) | _BV(TOIE1) | _BV(TICIE1); //enable timer1+2 / ICP1
+#endif
+
+    // enable both external interrupts
+    // int 0 = data RX
+    // int 1 = car0 input
+    MCUCR = _BV(ISC00) | _BV(ISC01) | _BV(ISC10) | _BV(ISC11); // INT0/1 rising edge
+    GICR = _BV(INT0) | _BV(INT1) ; // Enable INT0 + INT1
+
+#ifdef ANALOG_COMPARATOR
+    ACSR = _BV(ACIE) | _BV(ACIS1) | _BV(ACIS0); // setup analog comparator
+#endif
+
+    // oscillator calibration
+    // atmega8@1mhz = 0xac
+    // @4mhz = ca 0xa0
+    //OSCCAL = 0xa0;
+    //OSCCAL = 0x9A;
+    //OSCCAL = 0xa0; // internal oscillator @ 4 mhz.... doesnt work accurate!
+
+    RS232_init(); // initialize RS232 interface
+    RS232_puts_p(PSTR("Freeslot TrackSwitch / Pitlane v1.3\n"));
+    sei();
+
+
+    DDR(SOLENOID_A_PORT) |= _BV(SOLENOID_A_PIN);
+    DDR(SOLENOID_B_PORT) |= _BV(SOLENOID_B_PIN);
+
+    DDR(RESPONSE_PORT) &= ~_BV(RESPONSE_PIN); // switch response off
+    RESPONSE_PORT &= ~_BV(RESPONSE_PIN); // switch response off
+
+    while (1) {
+        // main loop
+
+    /*
+        0 = AA
+        1 = AB
+        2 = BB
+        3 = BA
+    */
+        if (car0 != car0_state) {
+            car0_state = car0;
+            if ( (car0_state != 0) && (car_switch[car0_state-1] == 0) && (car_speed[car0_state-1]>0) ) {
+                response = (1 | ((car0_state-1)<<1) | (1 << 4));
+                // trigger solenoid A
+                RS232_putc('A');
+                RS232_putc('B');
+                RS232_putc('0'+car0_state);
+                RS232_putc('\n');
+
+                SOLENOID_A_PORT |= _BV(SOLENOID_A_PIN);
+                solenoid_delay();
+                SOLENOID_A_PORT &= ~_BV(SOLENOID_A_PIN);
+                solenoid_delay();
+            }
+            if (car0_state != 0) {
+                response = (1 | ((car0_state-1)<<1));
+                RS232_putc('A');
+                RS232_putc('A');
+                RS232_putc('0'+car0_state);
+                RS232_putc('\n');
+            }
+        } car0 = 0;
+
+
+        if (car1 != car1_state) {
+            car1_state = car1;
+            if ( (car1_state != 0) && (car_switch[car1_state-1] == 0) && (car_speed[car1_state-1]>0) ) {
+                response = (1 | ((car1_state-1)<<1) | (3 << 4));
+                // trigger solenoid B
+                RS232_putc('B');
+                RS232_putc('A');
+                RS232_putc('0'+car1_state);
+                RS232_putc('\n');
+
+                SOLENOID_B_PORT |= _BV(SOLENOID_B_PIN);
+                solenoid_delay();
+                SOLENOID_B_PORT &= ~_BV(SOLENOID_B_PIN);
+                solenoid_delay();
+            }
+            if (car1_state != 0) {
+                response = (1 | ((car1_state-1)<<1) | (2 << 4));
+                RS232_putc('B');
+                RS232_putc('B');
+                RS232_putc('0'+car1_state);
+                RS232_putc('\n');
+            }
+        } car1 = 0;
+
+
+    } // main loop end
+};
+

mercurial