#include #include #include #define F_CPU 12000000UL // 12 MHz /* * Valve data */ typedef enum { VALVE_CLOSED =0, VALVE_OPENED, VALVE_HOLDING, } ValveState; typedef struct { ValveState state; int msHold; int msStart; } ValveData; #define VALVE_COUNT 6 ValveData valves[VALVE_COUNT]; int pwmState; /* * Timer setup */ #define CYCLES_PER_MS (F_CPU / 1000UL) #define CLOCKS_PER_MS 187 #define MS_START 10 void configureTimer() { // TIMER 0 // Set prescaler to 1/64 // 187 cycles per ms // no output compare match pin // output compare register A triggers interrupt TCCR0A = 0x00; // compare TCCR0B = 0x03; // prescaler at 1/64 TCNT0 = 0x00; // initial cycle at 0 OCR0A = CLOCKS_PER_MS; TIMSK0 = 0x02; // interrupt on match A // TIMER 1 // Set prescaler to 1/16 // 750 cycles per ms // no output compare match pin // output compare register A triggers interrupt TCCR1A = 0x00; // compare TCCR1B = 0x01; // prescaler at 1/8 TCNT1 = 0x00; // initial cycle at 0 OCR1A = 100; // 8 PWM cycles/ms TIMSK1 = 0x02; // interrupt on match A } /* * Serial setup */ #define FLAG_PENDING_COMMAND 0x01 char flags = 0; #define RX_BUF_SIZE 64 char rxBuf[RX_BUF_SIZE]; int rxOffset; #define TX_BUF_SIZE 448 char txBuf[TX_BUF_SIZE]; char* pNextTx = NULL; void openValve( unsigned char valve ); void closeValve( unsigned char valve ); void dispense( unsigned char valve, unsigned int ms ); void dispense( unsigned char valve, unsigned int ms ) { if ( valve < VALVE_COUNT ) { openValve( valve ); valves[valve].state = VALVE_OPENED; if ( ms > MS_START ) { valves[valve].msStart = MS_START; valves[valve].msHold = ms - MS_START; } else { valves[valve].msStart = ms; valves[valve].msHold = 0; } } } void configureSerial() { // Setting to 9600 baud, 8N1. // 9600 baud: U2X = 0, UBRR = 71 UBRR0H = 0; UBRR0L = 77; UCSR0A = 0; // enable TX/RX UCSR0B = (1<= 6 ) { putString( "Valve out of range" ); } int whole = 0; int fract = 0; int frsig = 100; while (*pR >= '0' && *pR <= '9' ) { whole = (whole * 10) + (*(pR++) - '0'); } if ( *pR == '.' ) { pR++; while (*pR >= '0' && *pR <= '9' ) { fract += frsig * (*(pR++) - '0'); frsig /= 10; } } if ( *pR == '-' ) { dispense( v, whole*1000 + fract ); } else { putString( "No terminator" ); } } } /* * PC0-5 Configure as digital outputs for driving */ void configurePins() { PORTC = 0x00; DDRC = 0x3f; // Set C0-C5 as outputs } void openValve( unsigned char valve ) { if ( valve < 6 ) { PORTC |= 0x01 << valve; } } void closeValve( unsigned char valve ) { if ( valve < 6 ) { PORTC &= (0xff) ^ (0x01 << valve); } } void init() { int i; cli(); configurePins(); configureSerial(); set_sleep_mode( SLEEP_MODE_IDLE ); for ( i = 0; i < VALVE_COUNT; i++ ) { valves[i].state = VALVE_CLOSED; valves[i].msHold = 0; valves[i].msStart = 0; } pwmState = 0; configureTimer(); sei(); } ISR(USART_RX_vect) { rxBuf[ rxOffset ] = UDR0; if ( rxBuf[ rxOffset ] == '\n' ) { rxBuf[ rxOffset ] = '\0'; flags |= FLAG_PENDING_COMMAND; rxOffset = 0; } else { rxOffset = (rxOffset+1) % RX_BUF_SIZE; } } ISR(USART_UDRE_vect) { if (pNextTx == 0 || *pNextTx == '\0') { UCSR0B &= ~(1 << UDRIE0); } else { UDR0=*pNextTx; pNextTx++; } } ISR( TIMER0_COMPA_vect ) { int i; for ( i = 0; i < VALVE_COUNT; i++ ) { if ( valves[i].state == VALVE_OPENED ) { if ( valves[i].msStart == 0 ) { valves[i].state = VALVE_HOLDING; } else { valves[i].msStart--; } } if ( valves[i].state == VALVE_HOLDING ) { if ( valves[i].msHold == 0 ) { closeValve(i); valves[i].state = VALVE_CLOSED; } else { valves[i].msHold--; } } } } ISR( TIMER1_COMPA_vect ) { int i; pwmState=(pwmState==0)?1:0; for ( i = 0; i < VALVE_COUNT; i++ ) { if ( valves[i].state == VALVE_HOLDING ) { if ( pwmState == 0 ) { closeValve( i ); } else { openValve( i ); } } } } int main( void ) { init(); putString( "Initialized.\n" ); while (1) { //sleep_cpu(); if ( (flags & FLAG_PENDING_COMMAND) != 0 ) { processCommand(); } } return 0; }