5 #include <avr/interrupt.h>
7 #include <util/delay.h>
11 * I2C Register Map (8 Bit)
12 * 0x00 Register select
13 * 0x01 Distance left MSB
14 * 0x02 Distance left LSB
15 * 0x03 Distance right MSB
16 * 0x04 Distance right LSB
17 * 0x05 Distance forward1 MSB
18 * 0x06 Distance forward1 LSB
19 * 0x07 Distance backward MSB
20 * 0x08 Distance backward LSB
23 * 0x0B Distance forward2 MSB
24 * 0x0C Distance forward2 LSB
26 * 0x15 Distance forward1 MSB (read only)
27 * 0x16 Distance forward1 LSB (read only)
28 * 0x17 Distance backward MSB (read only)
29 * 0x18 Distance backward LSB (read only)
30 * 0x19 Distance forward2 MSB (read only)
31 * 0x1A Distance forward2 LSB (read only)
37 #define TWI_ACK TWCR = (1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
38 #define TWI_RESET TWCR &= ~((1 << TWSTO) | (1 << TWEN)); TWI_ACK
39 #define TWI_NAK TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
41 static volatile uint8_t ireg=0;
42 static volatile uint8_t bootloader=0;
43 static volatile uint16_t dist_left=0;
44 static volatile uint16_t dist_right=0;
45 static volatile uint16_t dist_forward1=0;
46 static volatile uint16_t dist_forward2=0;
47 static volatile uint16_t dist_backward=0;
48 static volatile uint8_t start_dist_fwd1=0;
49 static volatile uint8_t start_dist_fwd2=0;
50 static volatile uint8_t start_dist_bwd=0;
51 static volatile uint16_t voltage=0;
52 static volatile uint8_t pind_pre=0;
56 static int16_t tmp16=0;
60 case 0x60: // start write
66 case 0x00: // register select
69 if (ireg == 0x05) start_dist_fwd1=1;
70 if (ireg == 0x07) start_dist_bwd=1;
71 if (ireg == 0x09) start_dist_fwd2=1;
73 ireg--; // because we do ireg++ below
76 case 0xff: // bootloader
83 case 0xA8: // start read
86 case 0x01: // Distance left MSB
91 case 0x02: // Distance right LSB
95 case 0x03: // Distance right MSB
100 case 0x04: // Distance right LSB
104 case 0x05: // Distance forward1 MSB
105 tmp16 = dist_forward1;
109 case 0x06: // Distance forward1 LSB
113 case 0x07: // Distance backward MSB
114 tmp16 = dist_backward;
118 case 0x08: // Distance backward LSB
122 case 0x09: // Voltage MSB
127 case 0x0A: // Voltage LSB
131 case 0x0B: // Distance forward2 MSB
132 tmp16 = dist_forward2;
136 case 0x0C: // Distance forward2 LSB
140 case 0x15: // Distance forward1 MSB
141 tmp16 = dist_forward1;
145 case 0x16: // Distance forward1 LSB
149 case 0x17: // Distance backward MSB
150 tmp16 = dist_backward;
154 case 0x18: // Distance backward LSB
158 case 0x19: // Distance forward2 MSB
159 tmp16 = dist_forward2;
163 case 0x1A: // Distance forward2 LSB
179 uint16_t ReadChannel(uint8_t mux) {
183 ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
184 // setzen auf 8 (1) und ADC aktivieren (1)
186 ADMUX = mux; // Kanal waehlen
189 /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
190 also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
191 ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
192 while ( ADCSRA & (1<<ADSC) ) {
193 // auf Abschluss der Konvertierung warten
195 result = ADCW; // ADCW muss einmal gelesen werden,
196 // sonst wird Ergebnis der nächsten Wandlung
199 /* Eigentliche Messung - Mittelwert aus 5 aufeinanderfolgenden Wandlungen */
203 ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
204 while ( ADCSRA & (1<<ADSC) ) {
205 // auf Abschluss der Konvertierung warten
207 result += ADCW; // Wandlungsergebnisse aufaddieren
210 ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
212 result /= 5; // Summe durch 5 teilen = arithm. Mittelwert
218 static unsigned short get_distance(uint8_t i) {
219 return ReadChannel(i);
223 static unsigned short get_voltage(void) {
224 return ReadChannel(2)*1.46;
229 static uint16_t t_start=0;
230 uint16_t t_now = TCNT1;
233 if (bit_is_set(PIND, 2)) { // high level
237 t_diff = t_now - t_start;
238 dist_forward1 = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
239 // disable this interrupt
240 EIMSK &= ~(1 << INT0);
246 static uint16_t t_start=0;
247 uint16_t t_now = TCNT1;
250 if (bit_is_set(PIND, 3)) { // high level
254 t_diff = t_now - t_start;
255 dist_backward = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
256 // disable this interrupt
257 EIMSK &= ~(1 << INT1);
263 uint8_t pind_cur = PIND;
265 if ((pind_cur ^ pind_pre) & (1<<4)) { // PCINT20
266 static uint16_t t_start=0;
267 uint16_t t_now = TCNT1;
270 if (bit_is_set(pind_cur, 4)) { // high level
274 t_diff = t_now - t_start;
275 dist_forward2 = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
276 // disable this interrupt
277 PCMSK2 &= ~(1 << PCINT20);
294 // Timer 1: Normal mode, Top: 0xffff, Prescaler: F_CPU/256=62500Hz
296 TCCR1B = (1 << CS12);
298 // External Interrupts
299 EICRA = (1 << ISC10) | (1 << ISC00);
300 PCICR = (1 << PCIE2);
302 printf("\r\nStart\r\n");
304 set_sleep_mode(SLEEP_MODE_IDLE);
308 case 0x01: // ir left
309 dist_left = get_distance(0);
311 case 0x03: // ir right
312 dist_right = get_distance(1);
314 case 0x09: // voltage
315 voltage = get_voltage();
317 case 0xff: // Magic reg that starts the bootloader
318 if (bootloader == 0xa5) {
321 void (*start)(void) = (void*)0x1800;
328 if (start_dist_fwd1) {
337 // wait for interrupt
338 EIFR &= (1 << INTF0); // clear old interrupt before enabling
339 EIMSK |= (1 << INT0);
341 if (start_dist_bwd) {
350 // wait for interrupt
351 EIFR &= (1 << INTF1); // clear old interrupt before enabling
352 EIMSK |= (1 << INT1);
354 if (start_dist_fwd2) {
364 // wait for interrupt
366 PCMSK2 |= (1 << PCINT20);