bicycle_odometer

annotate odometer.c @ 4:f883847a0591

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 26 Aug 2011 06:16:00 +0300
parents c0c68988bcdf
children
rev   line source
nuclear@0 1 /* PORT USAGE
nuclear@0 2 *
nuclear@0 3 * D0-D3: data bus, connected to the D0-D3 pins of all the 4511 chips
nuclear@0 4 * C0-C5,D4,D5: directly driving the 8 speed graph LEDs
nuclear@0 5 * B0-B2: connected to the decoder controlling the 4511 latches as such:
nuclear@0 6 * 000 - speed most significant
nuclear@0 7 * 001 - speed least significant
nuclear@0 8 * 010 - dist most significant
nuclear@0 9 * 011 - dist middle
nuclear@0 10 * 100 - dist least significant
nuclear@0 11 * 101 - all latches are off (high)
nuclear@0 12 * B3-B5: ISP. B4 also acts as generic pushbutton input
nuclear@0 13 * B6,B7: XTAL
nuclear@0 14 * D6,D7: comparator, hall effect sensor input and threshold trimpot.
nuclear@0 15 */
nuclear@0 16
nuclear@0 17 /* 16mhz resonator */
nuclear@2 18 #define F_CPU 16000000
nuclear@0 19
nuclear@0 20 #include <avr/io.h>
nuclear@0 21 #include <avr/interrupt.h>
nuclear@2 22 #include <avr/power.h>
nuclear@0 23 #include <util/delay.h>
nuclear@0 24
nuclear@3 25
nuclear@2 26 #define SEC_TICKS (F_CPU / 256 / 256)
nuclear@2 27
nuclear@2 28 #define PRESCL_1 1
nuclear@2 29 #define PRESCL_8 2
nuclear@2 30 #define PRESCL_64 3
nuclear@2 31 #define PRESCL_256 4
nuclear@2 32 #define PRESCL_1024 5
nuclear@2 33
nuclear@2 34
nuclear@2 35 #define PB_CSEL_MASK 0x7
nuclear@2 36 #define PD_DATA_MASK 0xf
nuclear@2 37 #define PD_LEDS_MASK 0xc0
nuclear@2 38
nuclear@4 39 /* 1800 2sec intervals per hour, \times perimeter, \times x, \over 100000 cm in a kilometer */
nuclear@4 40 #define RP2S_TO_KMH(x) ((18 * WHEEL_PERIMETER * (x)) / 1000)
nuclear@2 41
nuclear@2 42 #define DEBOUNCE_TICKS 1
nuclear@2 43
nuclear@3 44
nuclear@3 45 /* wheel perimeter in centimeters */
nuclear@3 46 #define WHEEL_PERIMETER 194
nuclear@3 47
nuclear@2 48 #define nop() asm volatile("nop")
nuclear@2 49
nuclear@3 50
nuclear@2 51 void init_timer(void);
nuclear@0 52 void latch(int n);
nuclear@4 53 void update_display(int idx);
nuclear@2 54 void disp_speed(int n);
nuclear@2 55 void disp_dist(int n);
nuclear@2 56 void disp_leds(int n);
nuclear@0 57
nuclear@0 58 int state;
nuclear@2 59 int debug_mode = 0;
nuclear@2 60
nuclear@2 61 volatile long ticks;
nuclear@0 62
nuclear@0 63 unsigned long nrot;
nuclear@4 64 unsigned long speed_rp2s;
nuclear@0 65
nuclear@0 66 int main(void)
nuclear@0 67 {
nuclear@0 68 int i;
nuclear@0 69
nuclear@0 70 DDRB = 0xf; /* only first four bits are outputs */
nuclear@0 71 DDRC = 0xff; /* speed leds 6 bits */
nuclear@2 72 DDRD = 0x3f; /* 4bits data bus, 2 bits speed leds, 2 bits comparator (input) */
nuclear@0 73
nuclear@0 74 /* zero-out the displays and disable all pullups except for the reset pin */
nuclear@0 75 PORTB = 0;
nuclear@0 76 PORTC = 0x40; /* 6th bit set, C6 is reset */
nuclear@0 77 PORTD = 0;
nuclear@0 78
nuclear@0 79 for(i=0; i<5; i++) {
nuclear@0 80 latch(i);
nuclear@0 81 }
nuclear@0 82
nuclear@2 83 /* if the button at B4 is pressed during startup, enter debug mode */
nuclear@2 84 if((PINB >> 4) & 1) {
nuclear@2 85 debug_mode = 1;
nuclear@2 86 PORTC |= 3 << 4;
nuclear@2 87 }
nuclear@2 88
nuclear@2 89 init_timer();
nuclear@2 90
nuclear@2 91 /* disable digital input buffer for the AINn pins */
nuclear@2 92 DIDR1 = 0;
nuclear@2 93
nuclear@0 94 /* read initial comparator state */
nuclear@0 95 state = (ACSR >> ACO) & 1;
nuclear@0 96
nuclear@0 97 /* in debug mode we want an interrupt both on rising and falling edge
nuclear@0 98 * to be able to blink leds when the wheel goes past. otherwise we only need
nuclear@0 99 * a rising edge interrupt to increment the rotation counter.
nuclear@0 100 */
nuclear@2 101 /* rising edge interrupt */
nuclear@2 102 /*ACSR |= (2 << ACIS0);*/
nuclear@2 103
nuclear@2 104 /* comparator interrupt enable */
nuclear@2 105 ACSR |= (1 << ACIE);
nuclear@0 106
nuclear@0 107 sei();
nuclear@0 108
nuclear@2 109 for(;;) {
nuclear@2 110 }
nuclear@0 111 return 0;
nuclear@0 112 }
nuclear@0 113
nuclear@2 114 void init_timer(void)
nuclear@2 115 {
nuclear@2 116 power_timer0_enable();
nuclear@2 117
nuclear@2 118 TCCR0A = 0;
nuclear@2 119 TCCR0B = PRESCL_256;
nuclear@2 120
nuclear@2 121 /* enable timer overflow interrupt */
nuclear@2 122 TIMSK0 = 1;
nuclear@2 123 }
nuclear@2 124
nuclear@0 125 void latch(int n)
nuclear@0 126 {
nuclear@2 127 unsigned char upper = PORTB & ~PB_CSEL_MASK;
nuclear@0 128 /* pull latch low */
nuclear@0 129 PORTB = upper | n;
nuclear@0 130 asm volatile("nop");
nuclear@0 131 /* pull all latches high again */
nuclear@0 132 PORTB = upper | 5;
nuclear@0 133 }
nuclear@0 134
nuclear@0 135 ISR(ANALOG_COMP_vect)
nuclear@0 136 {
nuclear@2 137 volatile static long prev_time;
nuclear@2 138 unsigned char aco;
nuclear@2 139
nuclear@2 140 nop();
nuclear@2 141 nop();
nuclear@2 142 nop();
nuclear@2 143
nuclear@2 144 aco = (ACSR >> ACO) & 1;
nuclear@2 145
nuclear@2 146 if(aco != state && (ticks - prev_time) > DEBOUNCE_TICKS) {
nuclear@2 147 state = aco;
nuclear@0 148
nuclear@0 149 if(state) {
nuclear@0 150 nrot++;
nuclear@2 151
nuclear@4 152 /*update_display();*/
nuclear@0 153 }
nuclear@4 154 prev_time = ticks;
nuclear@0 155 }
nuclear@2 156 }
nuclear@2 157
nuclear@2 158 ISR(TIMER0_OVF_vect)
nuclear@2 159 {
nuclear@4 160 volatile static int sec_ticks, sec;
nuclear@4 161 volatile static unsigned long last_rot[4];
nuclear@2 162
nuclear@2 163 ticks++;
nuclear@2 164 sec_ticks++;
nuclear@2 165
nuclear@4 166 if(sec_ticks >= SEC_TICKS / 2) {
nuclear@4 167 int idx = ++sec & 3;
nuclear@2 168
nuclear@4 169 speed_rp2s = nrot - last_rot[idx];
nuclear@4 170
nuclear@4 171 update_display(idx);
nuclear@2 172
nuclear@2 173 sec_ticks = 0;
nuclear@4 174 last_rot[idx] = nrot;
nuclear@2 175 }
nuclear@2 176
nuclear@2 177
nuclear@2 178 if(debug_mode) {
nuclear@2 179 unsigned char state = (ACSR >> ACO) & 1;
nuclear@2 180 if(state) {
nuclear@2 181 PORTD |= (1 << 5);
nuclear@2 182 } else {
nuclear@2 183 PORTD &= ~(1 << 5);
nuclear@2 184 }
nuclear@2 185 }
nuclear@0 186 }
nuclear@0 187
nuclear@4 188 void update_display(int idx)
nuclear@0 189 {
nuclear@2 190 if(debug_mode) {
nuclear@2 191 disp_dist(nrot);
nuclear@4 192 disp_speed(speed_rp2s);
nuclear@0 193
nuclear@2 194 if(state) {
nuclear@2 195 PORTD |= (1 << 5);
nuclear@2 196 } else {
nuclear@2 197 PORTD &= ~(1 << 5);
nuclear@2 198 }
nuclear@2 199 } else {
nuclear@2 200 unsigned long dist_cm = (nrot * WHEEL_PERIMETER);
nuclear@4 201 int speed_kmh = RP2S_TO_KMH(speed_rp2s);
nuclear@2 202
nuclear@2 203 disp_dist(dist_cm / 10000);
nuclear@2 204 disp_speed(speed_kmh);
nuclear@2 205 disp_leds(speed_kmh * 8);
nuclear@2 206 }
nuclear@0 207 }
nuclear@2 208
nuclear@2 209 void disp_speed(int n)
nuclear@2 210 {
nuclear@2 211 PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10);
nuclear@2 212 latch(1);
nuclear@2 213 n /= 10;
nuclear@2 214 PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10);
nuclear@2 215 latch(0);
nuclear@2 216 }
nuclear@2 217
nuclear@2 218 void disp_dist(int n)
nuclear@2 219 {
nuclear@2 220 PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10);
nuclear@2 221 latch(4);
nuclear@2 222 n /= 10;
nuclear@2 223 PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10);
nuclear@2 224 latch(3);
nuclear@2 225 n /= 10;
nuclear@2 226 PORTD = (PORTD & ~PD_DATA_MASK) | (n % 10);
nuclear@2 227 latch(2);
nuclear@2 228 }
nuclear@2 229
nuclear@2 230 void disp_leds(int n)
nuclear@2 231 {
nuclear@2 232 int i, count, bits;
nuclear@2 233
nuclear@2 234 count = (n + 4) >> 5;
nuclear@2 235 bits = 0;
nuclear@2 236
nuclear@2 237 for(i=0; i<count; i++) {
nuclear@2 238 bits |= (1 << i);
nuclear@2 239 }
nuclear@2 240
nuclear@2 241 PORTC = bits;
nuclear@2 242 PORTD = (PORTD & PD_DATA_MASK) | ((bits & PD_LEDS_MASK) >> 2);
nuclear@2 243 }