car004f/main.c

Sun, 22 Dec 2013 00:08:46 +0100

author
Malte Bayer <mbayer@neo-soft.org>
date
Sun, 22 Dec 2013 00:08:46 +0100
changeset 148
08cb88614d69
parent 147
f66c5b3b3ed2
child 149
1c3425af9aa0
permissions
-rw-r--r--

car firmware: finished pwm drive and lights switching

#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 "util/delay.h"


ISR ( USART_RXC_vect ) {
}

#define PULSE_PORT      PORTD
#define PULSE_BIT       PD2

typedef struct  {
    uint8_t slot;
    uint8_t light;
    unsigned program:1; // programming mode active
} config_t;


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 timeout = 0;
volatile uint8_t brake_timeout = 0;


uint8_t my_switch;
uint8_t my_speed;
config_t config;

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 (INT1_vect) {
}

ISR (TIMER0_OVF_vect) {
    TCNT0  = 100;            // TIMER0 vorladen mit 100
    if (brake_timeout > 1) brake_timeout--;
    if (timeout > 1) timeout--;
}

#define LIGHT_PORT      PORTC
#define LIGHT_FRONT     2
#define LIGHT_BRAKE     4

#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")


void config_save(void) {
    eeprom_write_block( (void*)&config, 0, sizeof(config) );
}


void brake_on(void) {
    LIGHT_PORT |= _BV(LIGHT_BRAKE); // brake light on
    BRAKE_PORT |= _BV(BRAKE); // brake on
    brake_timeout = 50;
}

void brake_off(void) {
    LIGHT_PORT &= ~_BV(LIGHT_BRAKE); // brake light off
    BRAKE_PORT &= ~_BV(BRAKE); // brake off
    brake_timeout = 0;
}

int main(void)
{
    // setup data bit timer2
    TCCR2 = (1<<CS21) | (1<<WGM21); //divide by 8, set compare match
    OCR2 = TIMER2_50US;


    // enable both external interrupts
    // int 0 = data RX
    MCUCR = _BV(ISC00) | _BV(ISC01) | _BV(ISC10) | _BV(ISC11); // INT0/1 rising edge
    GICR = _BV(INT0) | _BV(INT1) ; // Enable INT0 + INT1


    DDR(LIGHT_PORT) |= _BV(LIGHT_FRONT) | _BV(LIGHT_BRAKE);
    DDR(BRAKE_PORT) |= _BV(BRAKE);

    // config (from eeprom!)
    eeprom_read_block( (void*)&config, (const void*)0, sizeof(config) );


    TCCR1A = (1<<WGM10)|(1<<COM1A1)   // Set up the two Control registers of Timer1.
            |(1<<COM1B1);             // Wave Form Generation is Fast PWM 8 Bit,

    TCCR1B = (1<<WGM12)|(1<<CS10);     // OC1A and OC1B are cleared on compare match
                                       // and set at BOTTOM. Clock Prescaler is 1.


    //OCR1A = 63;                       // Dutycycle of OC1A = 25%
    //OCR1B = 127;                      // Dutycycle of OC1B = 50%
    OCR1A = 0;
    OCR1B = 0;

    // configure TIMER0 to overflow every 10ms at 4 MHz
    TIMSK = _BV(TOIE0);         // Timer0 Overflow INT erlauben
    TCNT0  = 100;            // TIMER0 vorladen mit 100
    TCCR0 = _BV(CS02) ;         // Vorteiler auf 256, ab hier läuft der TIMER0

    sei();


config.slot = 1;

    while (1) {
        // main loop

        if (brake_timeout == 1) { 
            DDRB &= ~_BV(2);                  // PB2 PWM Output disable
            brake_off();
        }

        if (my_speed != car_speed[config.slot]) {
            my_speed = car_speed[config.slot];
            OCR1B = (int) ((float)0xff * (float)((float)my_speed / (float)15));
            if (my_speed == 0) {
                DDRB &= ~_BV(2);                  // PB2 PWM Output disable
                brake_on();
            } else {
                brake_off();
                DDRB |= _BV(2);                   // PB2 PWM Output enable
            }
        }

        // Light cycle if switch pressed without speed
        if (car_speed[config.slot] == 0) {
            if (my_switch != car_switch[config.slot]) {
                my_switch = car_switch[config.slot];
                if (my_switch != 0) {
                    // cycle light
                    if (config.light == LIGHT_MODES) config.light = 0; else config.light++;
                }
            }
        }

        switch (config.light) {
            case 0:
                LIGHT_PORT &= ~_BV(LIGHT_FRONT); // switch lights off
                break;
            case 1:
                LIGHT_PORT |= _BV(LIGHT_FRONT); // switch lights on
                break;
        }


        /*
        _delay_ms(100);
        _delay_ms(100);
        */



    } // main loop end
};

mercurial