nuclear@0: /* PORT USAGE nuclear@0: * nuclear@0: * D0-D3: data bus, connected to the D0-D3 pins of all the 4511 chips nuclear@0: * C0-C5,D4,D5: directly driving the 8 speed graph LEDs nuclear@0: * B0-B2: connected to the decoder controlling the 4511 latches as such: nuclear@0: * 000 - speed most significant nuclear@0: * 001 - speed least significant nuclear@0: * 010 - dist most significant nuclear@0: * 011 - dist middle nuclear@0: * 100 - dist least significant nuclear@0: * 101 - all latches are off (high) nuclear@0: * B3-B5: ISP. B4 also acts as generic pushbutton input nuclear@0: * B6,B7: XTAL nuclear@0: * D6,D7: comparator, hall effect sensor input and threshold trimpot. nuclear@0: */ nuclear@0: nuclear@0: /* 16mhz resonator */ nuclear@0: #define F_CPU 2000000 nuclear@0: nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: void latch(int n); nuclear@0: void update_display(void); nuclear@0: nuclear@0: int state; nuclear@0: int debug_mode = 1; nuclear@0: nuclear@0: unsigned long nrot; nuclear@0: nuclear@0: /* wheel perimeter in centimeters */ nuclear@0: #define WHEEL_PERIMETER 100 nuclear@0: nuclear@0: int main(void) nuclear@0: { nuclear@0: int i; nuclear@0: nuclear@0: DDRB = 0xf; /* only first four bits are outputs */ nuclear@0: DDRC = 0xff; /* speed leds 6 bits */ nuclear@0: DDRD = 0xff; /* 4bits data bus, 2 bits speed leds, 2 bits comparator (don't care) */ nuclear@0: nuclear@0: /* zero-out the displays and disable all pullups except for the reset pin */ nuclear@0: PORTB = 0; nuclear@0: PORTC = 0x40; /* 6th bit set, C6 is reset */ nuclear@0: PORTD = 0; nuclear@0: nuclear@0: for(i=0; i<5; i++) { nuclear@0: latch(i); nuclear@0: } nuclear@0: nuclear@0: /* read initial comparator state */ nuclear@0: state = (ACSR >> ACO) & 1; nuclear@0: nuclear@0: if(debug_mode) { nuclear@0: int i, j, leds, leds_val; nuclear@0: nuclear@0: for(i=0; ; i++) { nuclear@0: for(j=0; j<5; j++) { nuclear@0: /* set bits */ nuclear@0: PORTD = (PORTD & 0xf0) | (((i + j) % 10) & 0xf); nuclear@0: /* latch */ nuclear@0: latch(j); nuclear@0: } nuclear@0: nuclear@0: leds_val = 0; nuclear@0: leds = i % 8; nuclear@0: for(j=0; j<8; j++) { nuclear@0: if(j <= leds) { nuclear@0: leds_val |= (1 << j); nuclear@0: } nuclear@0: } nuclear@0: PORTC = leds_val; nuclear@0: PORTD = (PORTD & 0xf) | ((leds_val >> 2) & (3 << 4)); nuclear@0: nuclear@0: _delay_ms(1000); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: /* disable digital input buffer for the AINn pins */ nuclear@0: /*DIDR1 = 0;*/ nuclear@0: nuclear@0: ACSR = (1 << ACIE); nuclear@0: /* in debug mode we want an interrupt both on rising and falling edge nuclear@0: * to be able to blink leds when the wheel goes past. otherwise we only need nuclear@0: * a rising edge interrupt to increment the rotation counter. nuclear@0: */ nuclear@0: if(!debug_mode) { nuclear@0: /* rising edge interrupt */ nuclear@0: ACSR |= (3 << ACIS0); nuclear@0: } nuclear@0: nuclear@0: sei(); nuclear@0: nuclear@0: for(;;); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void latch(int n) nuclear@0: { nuclear@0: unsigned char upper = PORTB & 0xf0; nuclear@0: /* pull latch low */ nuclear@0: PORTB = upper | n; nuclear@0: asm volatile("nop"); nuclear@0: /* pull all latches high again */ nuclear@0: PORTB = upper | 5; nuclear@0: } nuclear@0: nuclear@0: ISR(ANALOG_COMP_vect) nuclear@0: { nuclear@0: if(debug_mode) { nuclear@0: int state = (ACSR >> ACO) & 1; nuclear@0: nuclear@0: if(state) { nuclear@0: PORTB |= 1; nuclear@0: nrot++; nuclear@0: } else { nuclear@0: PORTB &= ~1; nuclear@0: } nuclear@0: } else { nuclear@0: nrot++; nuclear@0: } nuclear@0: nuclear@0: update_display(); nuclear@0: } nuclear@0: nuclear@0: void update_display(void) nuclear@0: { nuclear@0: unsigned long dist_cm = (nrot * WHEEL_PERIMETER); nuclear@0: nuclear@0: /* TODO */ nuclear@0: }