#include #include #include #include #include #include // macros for setting bits #define sbi(var, mask) ((var) |= (uint8_t)(1 << mask)) #define cbi(var, mask) ((var) &= (uint8_t)~(1 << mask)) #define ABS(x) ((x>0)?(x):(-x)) #define CAP(speed,max) ((speed> 8; UBRR0L = ((F_CPU / 16 + baud / 2) / baud - 1); UCSR0B = (1<>1; OCR1B = ICR1>>1; } void io_init() { DDRB = 0b11111111; DDRC = 0b11111111; DDRD = 0b11111110; } void eeprom_init() { max_speed = eeprom_read_byte(&EEmax_speed); max_change = eeprom_read_byte(&EEmax_change); } void set_motors(uint8_t speed, uint8_t dir, uint8_t motor) { enum {forward=0,stop,backward}; enum {lmotor=0xF0,rmotor=0x0F}; switch(motor) { case lmotor: ldest_speed = CAP(speed,max_speed); ldest_dir = dir; if(dir == stop) { ldest_speed = ICR1>>1; OCR1A = ICR1>>1; sbi(PORTB,L_DIS); } else cbi(PORTB,L_DIS); break; case rmotor: rdest_speed = CAP(speed,max_speed); rdest_dir = dir; if(dir == stop) { rdest_speed = ICR1>>1; OCR1B = ICR1>>1; sbi(PORTB,R_DIS); } else cbi(PORTB,R_DIS); break; default: break; } } int main(void) { enum {motor_state=0,direction_state,speed_state,checksum_state}; enum {forward=0,stop,backward}; enum {lmotor=0xF0,rmotor=0x0F}; uint8_t state = motor_state; uint8_t in; uint8_t temp; uint8_t motor=0; uint8_t speed=0; uint8_t dir=0; eeprom_init(); serial_init(9600); io_init(); pwm_init(); timer_init(); // interrupt every 16 ms sei(); // enable interrupts while (1) { in = usart_get(); switch (state) { case motor_state : motor = in; state = speed_state; break; case speed_state : speed = in; state = direction_state; break; case direction_state : dir = in; state = checksum_state; break; case checksum_state : temp = (motor ^ (3*speed) ^ (5*dir)) ^ in; // auchter's crazy checksum usart_put(temp); if (!temp) set_motors(speed,dir,motor); state = motor_state; break; default: state = motor_state; break; } } } // periodic interrupt, currently every 16ms // ramps speed to desired speed ISR(TIMER0_COMPA_vect) { uint8_t templ; uint8_t tempr; templ = (ICR1>>1) + ldest_speed * (ldest_dir - 1); tempr = (ICR1>>1) + rdest_speed * (rdest_dir - 1); OCR1A += (templ > OCR1A ? max_change : -max_change); OCR1B += (tempr > OCR1B ? max_change : -max_change); OCR1A = ABS(OCR1A - templ) < max_change ? templ : OCR1A; OCR1B = ABS(OCR1B - tempr) < max_change ? tempr : OCR1B; }