bicycle_odometer
diff odometer.c @ 2:f74f4561e71c
first version almost done
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 24 Aug 2011 07:51:12 +0300 |
parents | 0c1707508070 |
children | c0c68988bcdf |
line diff
1.1 --- a/odometer.c Tue Aug 23 19:01:38 2011 +0300 1.2 +++ b/odometer.c Wed Aug 24 07:51:12 2011 +0300 1.3 @@ -15,22 +15,49 @@ 1.4 */ 1.5 1.6 /* 16mhz resonator */ 1.7 -#define F_CPU 2000000 1.8 +#define F_CPU 16000000 1.9 1.10 #include <avr/io.h> 1.11 #include <avr/interrupt.h> 1.12 +#include <avr/power.h> 1.13 #include <util/delay.h> 1.14 1.15 +#define SEC_TICKS (F_CPU / 256 / 256) 1.16 + 1.17 +#define PRESCL_1 1 1.18 +#define PRESCL_8 2 1.19 +#define PRESCL_64 3 1.20 +#define PRESCL_256 4 1.21 +#define PRESCL_1024 5 1.22 + 1.23 + 1.24 +#define PB_CSEL_MASK 0x7 1.25 +#define PD_DATA_MASK 0xf 1.26 +#define PD_LEDS_MASK 0xc0 1.27 + 1.28 +#define RPS_TO_KMH(x) ((36 * WHEEL_PERIMETER * (x)) / 1000) 1.29 + 1.30 +#define DEBOUNCE_TICKS 1 1.31 + 1.32 +#define nop() asm volatile("nop") 1.33 + 1.34 +void init_timer(void); 1.35 void latch(int n); 1.36 void update_display(void); 1.37 +void disp_speed(int n); 1.38 +void disp_dist(int n); 1.39 +void disp_leds(int n); 1.40 1.41 int state; 1.42 -int debug_mode = 1; 1.43 +int debug_mode = 0; 1.44 + 1.45 +volatile long ticks; 1.46 1.47 unsigned long nrot; 1.48 +unsigned long speed_rps; 1.49 1.50 /* wheel perimeter in centimeters */ 1.51 -#define WHEEL_PERIMETER 100 1.52 +#define WHEEL_PERIMETER 220 1.53 1.54 int main(void) 1.55 { 1.56 @@ -38,7 +65,7 @@ 1.57 1.58 DDRB = 0xf; /* only first four bits are outputs */ 1.59 DDRC = 0xff; /* speed leds 6 bits */ 1.60 - DDRD = 0xff; /* 4bits data bus, 2 bits speed leds, 2 bits comparator (don't care) */ 1.61 + DDRD = 0x3f; /* 4bits data bus, 2 bits speed leds, 2 bits comparator (input) */ 1.62 1.63 /* zero-out the displays and disable all pullups except for the reset pin */ 1.64 PORTB = 0; 1.65 @@ -49,56 +76,51 @@ 1.66 latch(i); 1.67 } 1.68 1.69 + /* if the button at B4 is pressed during startup, enter debug mode */ 1.70 + if((PINB >> 4) & 1) { 1.71 + debug_mode = 1; 1.72 + PORTC |= 3 << 4; 1.73 + } 1.74 + 1.75 + init_timer(); 1.76 + 1.77 + /* disable digital input buffer for the AINn pins */ 1.78 + DIDR1 = 0; 1.79 + 1.80 /* read initial comparator state */ 1.81 state = (ACSR >> ACO) & 1; 1.82 1.83 - if(debug_mode) { 1.84 - int i, j, leds, leds_val; 1.85 - 1.86 - for(i=0; ; i++) { 1.87 - for(j=0; j<5; j++) { 1.88 - /* set bits */ 1.89 - PORTD = (PORTD & 0xf0) | (((i + j) % 10) & 0xf); 1.90 - /* latch */ 1.91 - latch(j); 1.92 - } 1.93 - 1.94 - leds_val = 0; 1.95 - leds = i % 8; 1.96 - for(j=0; j<8; j++) { 1.97 - if(j <= leds) { 1.98 - leds_val |= (1 << j); 1.99 - } 1.100 - } 1.101 - PORTC = leds_val; 1.102 - PORTD = (PORTD & 0xf) | ((leds_val >> 2) & (3 << 4)); 1.103 - 1.104 - _delay_ms(1000); 1.105 - } 1.106 - } 1.107 - 1.108 - /* disable digital input buffer for the AINn pins */ 1.109 - /*DIDR1 = 0;*/ 1.110 - 1.111 - ACSR = (1 << ACIE); 1.112 /* in debug mode we want an interrupt both on rising and falling edge 1.113 * to be able to blink leds when the wheel goes past. otherwise we only need 1.114 * a rising edge interrupt to increment the rotation counter. 1.115 */ 1.116 - if(!debug_mode) { 1.117 - /* rising edge interrupt */ 1.118 - ACSR |= (3 << ACIS0); 1.119 - } 1.120 + /* rising edge interrupt */ 1.121 + /*ACSR |= (2 << ACIS0);*/ 1.122 + 1.123 + /* comparator interrupt enable */ 1.124 + ACSR |= (1 << ACIE); 1.125 1.126 sei(); 1.127 1.128 - for(;;); 1.129 + for(;;) { 1.130 + } 1.131 return 0; 1.132 } 1.133 1.134 +void init_timer(void) 1.135 +{ 1.136 + power_timer0_enable(); 1.137 + 1.138 + TCCR0A = 0; 1.139 + TCCR0B = PRESCL_256; 1.140 + 1.141 + /* enable timer overflow interrupt */ 1.142 + TIMSK0 = 1; 1.143 +} 1.144 + 1.145 void latch(int n) 1.146 { 1.147 - unsigned char upper = PORTB & 0xf0; 1.148 + unsigned char upper = PORTB & ~PB_CSEL_MASK; 1.149 /* pull latch low */ 1.150 PORTB = upper | n; 1.151 asm volatile("nop"); 1.152 @@ -108,25 +130,109 @@ 1.153 1.154 ISR(ANALOG_COMP_vect) 1.155 { 1.156 - if(debug_mode) { 1.157 - int state = (ACSR >> ACO) & 1; 1.158 + volatile static long prev_time; 1.159 + unsigned char aco; 1.160 + 1.161 + nop(); 1.162 + nop(); 1.163 + nop(); 1.164 + 1.165 + aco = (ACSR >> ACO) & 1; 1.166 + 1.167 + if(aco != state && (ticks - prev_time) > DEBOUNCE_TICKS) { 1.168 + state = aco; 1.169 1.170 if(state) { 1.171 - PORTB |= 1; 1.172 nrot++; 1.173 - } else { 1.174 - PORTB &= ~1; 1.175 + 1.176 + update_display(); 1.177 } 1.178 - } else { 1.179 - nrot++; 1.180 } 1.181 1.182 - update_display(); 1.183 + prev_time = ticks; 1.184 +} 1.185 + 1.186 +ISR(TIMER0_OVF_vect) 1.187 +{ 1.188 + volatile static int sec_ticks; 1.189 + volatile static unsigned long last_rot; 1.190 + 1.191 + ticks++; 1.192 + sec_ticks++; 1.193 + 1.194 + if(sec_ticks >= SEC_TICKS) { 1.195 + speed_rps = nrot - last_rot; 1.196 + 1.197 + update_display(); 1.198 + 1.199 + sec_ticks = 0; 1.200 + last_rot = nrot; 1.201 + } 1.202 + 1.203 + 1.204 + if(debug_mode) { 1.205 + unsigned char state = (ACSR >> ACO) & 1; 1.206 + if(state) { 1.207 + PORTD |= (1 << 5); 1.208 + } else { 1.209 + PORTD &= ~(1 << 5); 1.210 + } 1.211 + } 1.212 } 1.213 1.214 void update_display(void) 1.215 { 1.216 - unsigned long dist_cm = (nrot * WHEEL_PERIMETER); 1.217 + if(debug_mode) { 1.218 + disp_dist(nrot); 1.219 + disp_speed(speed_rps); 1.220 1.221 - /* TODO */ 1.222 + if(state) { 1.223 + PORTD |= (1 << 5); 1.224 + } else { 1.225 + PORTD &= ~(1 << 5); 1.226 + } 1.227 + } else { 1.228 + unsigned long dist_cm = (nrot * WHEEL_PERIMETER); 1.229 + int speed_kmh = RPS_TO_KMH(speed_rps); 1.230 + 1.231 + disp_dist(dist_cm / 10000); 1.232 + disp_speed(speed_kmh); 1.233 + disp_leds(speed_kmh * 8); 1.234 + } 1.235 } 1.236 + 1.237 +void disp_speed(int n) 1.238 +{ 1.239 + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); 1.240 + latch(1); 1.241 + n /= 10; 1.242 + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); 1.243 + latch(0); 1.244 +} 1.245 + 1.246 +void disp_dist(int n) 1.247 +{ 1.248 + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); 1.249 + latch(4); 1.250 + n /= 10; 1.251 + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); 1.252 + latch(3); 1.253 + n /= 10; 1.254 + PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10); 1.255 + latch(2); 1.256 +} 1.257 + 1.258 +void disp_leds(int n) 1.259 +{ 1.260 + int i, count, bits; 1.261 + 1.262 + count = (n + 4) >> 5; 1.263 + bits = 0; 1.264 + 1.265 + for(i=0; i<count; i++) { 1.266 + bits |= (1 << i); 1.267 + } 1.268 + 1.269 + PORTC = bits; 1.270 + PORTD = (PORTD & PD_DATA_MASK) | ((bits & PD_LEDS_MASK) >> 2); 1.271 +}