# HG changeset patch # User John Tsiombikas # Date 1314161472 -10800 # Node ID f74f4561e71c072746b6895c4cf46bf94e4c878b # Parent 5cbd47000b504279f11fc0bb09b394d04a54a2fe first version almost done diff -r 5cbd47000b50 -r f74f4561e71c Makefile --- a/Makefile Tue Aug 23 19:01:38 2011 +0300 +++ b/Makefile Wed Aug 24 07:51:12 2011 +0300 @@ -27,7 +27,7 @@ .PHONY: fuses fuses: - avrdude -c usbtiny -p $(mcu_dude) -U lfuse:w:0x66:m + avrdude -c usbtiny -p $(mcu_dude) -U lfuse:w:0xe6:m .PHONY: program program: $(hex) diff -r 5cbd47000b50 -r f74f4561e71c odometer.c --- a/odometer.c Tue Aug 23 19:01:38 2011 +0300 +++ b/odometer.c Wed Aug 24 07:51:12 2011 +0300 @@ -15,22 +15,49 @@ */ /* 16mhz resonator */ -#define F_CPU 2000000 +#define F_CPU 16000000 #include #include +#include #include +#define SEC_TICKS (F_CPU / 256 / 256) + +#define PRESCL_1 1 +#define PRESCL_8 2 +#define PRESCL_64 3 +#define PRESCL_256 4 +#define PRESCL_1024 5 + + +#define PB_CSEL_MASK 0x7 +#define PD_DATA_MASK 0xf +#define PD_LEDS_MASK 0xc0 + +#define RPS_TO_KMH(x) ((36 * WHEEL_PERIMETER * (x)) / 1000) + +#define DEBOUNCE_TICKS 1 + +#define nop() asm volatile("nop") + +void init_timer(void); void latch(int n); void update_display(void); +void disp_speed(int n); +void disp_dist(int n); +void disp_leds(int n); int state; -int debug_mode = 1; +int debug_mode = 0; + +volatile long ticks; unsigned long nrot; +unsigned long speed_rps; /* wheel perimeter in centimeters */ -#define WHEEL_PERIMETER 100 +#define WHEEL_PERIMETER 220 int main(void) { @@ -38,7 +65,7 @@ DDRB = 0xf; /* only first four bits are outputs */ DDRC = 0xff; /* speed leds 6 bits */ - DDRD = 0xff; /* 4bits data bus, 2 bits speed leds, 2 bits comparator (don't care) */ + DDRD = 0x3f; /* 4bits data bus, 2 bits speed leds, 2 bits comparator (input) */ /* zero-out the displays and disable all pullups except for the reset pin */ PORTB = 0; @@ -49,56 +76,51 @@ latch(i); } + /* if the button at B4 is pressed during startup, enter debug mode */ + if((PINB >> 4) & 1) { + debug_mode = 1; + PORTC |= 3 << 4; + } + + init_timer(); + + /* disable digital input buffer for the AINn pins */ + DIDR1 = 0; + /* read initial comparator state */ state = (ACSR >> ACO) & 1; - if(debug_mode) { - int i, j, leds, leds_val; - - for(i=0; ; i++) { - for(j=0; j<5; j++) { - /* set bits */ - PORTD = (PORTD & 0xf0) | (((i + j) % 10) & 0xf); - /* latch */ - latch(j); - } - - leds_val = 0; - leds = i % 8; - for(j=0; j<8; j++) { - if(j <= leds) { - leds_val |= (1 << j); - } - } - PORTC = leds_val; - PORTD = (PORTD & 0xf) | ((leds_val >> 2) & (3 << 4)); - - _delay_ms(1000); - } - } - - /* disable digital input buffer for the AINn pins */ - /*DIDR1 = 0;*/ - - ACSR = (1 << ACIE); /* in debug mode we want an interrupt both on rising and falling edge * to be able to blink leds when the wheel goes past. otherwise we only need * a rising edge interrupt to increment the rotation counter. */ - if(!debug_mode) { - /* rising edge interrupt */ - ACSR |= (3 << ACIS0); - } + /* rising edge interrupt */ + /*ACSR |= (2 << ACIS0);*/ + + /* comparator interrupt enable */ + ACSR |= (1 << ACIE); sei(); - for(;;); + for(;;) { + } return 0; } +void init_timer(void) +{ + power_timer0_enable(); + + TCCR0A = 0; + TCCR0B = PRESCL_256; + + /* enable timer overflow interrupt */ + TIMSK0 = 1; +} + void latch(int n) { - unsigned char upper = PORTB & 0xf0; + unsigned char upper = PORTB & ~PB_CSEL_MASK; /* pull latch low */ PORTB = upper | n; asm volatile("nop"); @@ -108,25 +130,109 @@ ISR(ANALOG_COMP_vect) { - if(debug_mode) { - int state = (ACSR >> ACO) & 1; + volatile static long prev_time; + unsigned char aco; + + nop(); + nop(); + nop(); + + aco = (ACSR >> ACO) & 1; + + if(aco != state && (ticks - prev_time) > DEBOUNCE_TICKS) { + state = aco; if(state) { - PORTB |= 1; nrot++; - } else { - PORTB &= ~1; + + update_display(); } - } else { - nrot++; } - update_display(); + prev_time = ticks; +} + +ISR(TIMER0_OVF_vect) +{ + volatile static int sec_ticks; + volatile static unsigned long last_rot; + + ticks++; + sec_ticks++; + + if(sec_ticks >= SEC_TICKS) { + speed_rps = nrot - last_rot; + + update_display(); + + sec_ticks = 0; + last_rot = nrot; + } + + + if(debug_mode) { + unsigned char state = (ACSR >> ACO) & 1; + if(state) { + PORTD |= (1 << 5); + } else { + PORTD &= ~(1 << 5); + } + } } void update_display(void) { - unsigned long dist_cm = (nrot * WHEEL_PERIMETER); + if(debug_mode) { + disp_dist(nrot); + disp_speed(speed_rps); - /* TODO */ + if(state) { + PORTD |= (1 << 5); + } else { + PORTD &= ~(1 << 5); + } + } else { + unsigned long dist_cm = (nrot * WHEEL_PERIMETER); + int speed_kmh = RPS_TO_KMH(speed_rps); + + disp_dist(dist_cm / 10000); + disp_speed(speed_kmh); + disp_leds(speed_kmh * 8); + } } + +void disp_speed(int n) +{ + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); + latch(1); + n /= 10; + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); + latch(0); +} + +void disp_dist(int n) +{ + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); + latch(4); + n /= 10; + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); + latch(3); + n /= 10; + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); + latch(2); +} + +void disp_leds(int n) +{ + int i, count, bits; + + count = (n + 4) >> 5; + bits = 0; + + for(i=0; i> 2); +}