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 +}