5 #include <avr/interrupt.h>
7 #include <util/delay.h>
9 #include <avr/eeprom.h>
14 * I2C Register Map (8 Bit)
15 * 0x00 Register select
16 * 0x01 Distance left MSB
17 * 0x02 Distance left LSB
18 * 0x03 Distance right MSB
19 * 0x04 Distance right LSB
20 * 0x05 Distance forward1 MSB
21 * 0x06 Distance forward1 LSB
22 * 0x07 Distance backward MSB
23 * 0x08 Distance backward LSB
26 * 0x0B Distance forward2 MSB
27 * 0x0C Distance forward2 LSB
29 * 0x15 Distance forward1 MSB (read only)
30 * 0x16 Distance forward1 LSB (read only)
31 * 0x17 Distance backward MSB (read only)
32 * 0x18 Distance backward LSB (read only)
33 * 0x19 Distance forward2 MSB (read only)
34 * 0x1A Distance forward2 LSB (read only)
40 #define TWI_ACK TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE)
41 #define TWI_NAK TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
42 #define TWI_RESET TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWSTO) | (1<<TWEN) | (1<<TWIE);
44 static volatile uint8_t ireg=0;
45 static volatile uint8_t bootloader=0;
46 static volatile uint16_t dist_left=0;
47 static volatile uint16_t dist_right=0;
48 static volatile uint16_t dist_forward1=0;
49 static volatile uint16_t dist_forward2=0;
50 static volatile uint16_t dist_backward=0;
51 static volatile uint8_t start_dist_fwd1=0;
52 static volatile uint8_t start_dist_fwd2=0;
53 static volatile uint8_t start_dist_bwd=0;
54 static volatile uint16_t voltage=0;
55 static volatile uint8_t pind_pre=0;
59 static int16_t tmp16=0;
63 case TW_SR_SLA_ACK: // start write
67 case TW_SR_DATA_ACK: // write
69 case 0x00: // register select
72 if (ireg == 0x05) start_dist_fwd1=1;
73 if (ireg == 0x07) start_dist_bwd=1;
74 if (ireg == 0x0b) start_dist_fwd2=1;
76 ireg--; // because we do ireg++ below
79 case 0xff: // bootloader
86 case TW_ST_SLA_ACK: // start read
87 case TW_ST_DATA_ACK: // read
89 case 0x01: // Distance left MSB
94 case 0x02: // Distance right LSB
98 case 0x03: // Distance right MSB
103 case 0x04: // Distance right LSB
107 case 0x05: // Distance forward1 MSB
108 tmp16 = dist_forward1;
112 case 0x06: // Distance forward1 LSB
116 case 0x07: // Distance backward MSB
117 tmp16 = dist_backward;
121 case 0x08: // Distance backward LSB
125 case 0x09: // Voltage MSB
130 case 0x0A: // Voltage LSB
134 case 0x0B: // Distance forward2 MSB
135 tmp16 = dist_forward2;
139 case 0x0C: // Distance forward2 LSB
143 case 0x15: // Distance forward1 MSB
144 tmp16 = dist_forward1;
148 case 0x16: // Distance forward1 LSB
152 case 0x17: // Distance backward MSB
153 tmp16 = dist_backward;
157 case 0x18: // Distance backward LSB
161 case 0x19: // Distance forward2 MSB
162 tmp16 = dist_forward2;
166 case 0x1A: // Distance forward2 LSB
185 uint16_t ReadChannel(uint8_t mux) {
189 ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
190 // setzen auf 8 (1) und ADC aktivieren (1)
192 ADMUX = mux; // Kanal waehlen
195 /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
196 also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
197 ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
198 while ( ADCSRA & (1<<ADSC) ) {
199 // auf Abschluss der Konvertierung warten
201 result = ADCW; // ADCW muss einmal gelesen werden,
202 // sonst wird Ergebnis der nächsten Wandlung
205 /* Eigentliche Messung - Mittelwert aus 5 aufeinanderfolgenden Wandlungen */
209 ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
210 while ( ADCSRA & (1<<ADSC) ) {
211 // auf Abschluss der Konvertierung warten
213 result += ADCW; // Wandlungsergebnisse aufaddieren
216 ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
218 result /= 5; // Summe durch 5 teilen = arithm. Mittelwert
224 static unsigned short get_distance(uint8_t i) {
225 return ReadChannel(i);
229 static unsigned short get_voltage(void) {
230 return ReadChannel(2)*1.46;
235 static uint16_t t_start=0;
236 uint16_t t_now = TCNT1;
239 if (bit_is_set(PIND, 2)) { // high level
243 t_diff = t_now - t_start;
244 dist_forward1 = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
245 // disable this interrupt
246 EIMSK &= ~(1 << INT0);
252 static uint16_t t_start=0;
253 uint16_t t_now = TCNT1;
256 if (bit_is_set(PIND, 3)) { // high level
260 t_diff = t_now - t_start;
261 dist_backward = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
262 // disable this interrupt
263 EIMSK &= ~(1 << INT1);
269 uint8_t pind_cur = PIND;
271 if ((pind_cur ^ pind_pre) & (1<<4)) { // PCINT20
272 static uint16_t t_start=0;
273 uint16_t t_now = TCNT1;
276 if (bit_is_set(pind_cur, 4)) { // high level
280 t_diff = t_now - t_start;
281 dist_forward2 = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
282 // disable this interrupt
283 PCMSK2 &= ~(1 << PCINT20);
300 // Timer 1: Normal mode, Top: 0xffff, Prescaler: F_CPU/256=62500Hz
302 TCCR1B = (1 << CS12);
304 // External Interrupts
305 EICRA = (1 << ISC10) | (1 << ISC00);
306 PCICR = (1 << PCIE2);
308 printf("\r\nStart\r\n");
310 set_sleep_mode(SLEEP_MODE_IDLE);
314 case 0x01: // ir left
315 dist_left = get_distance(0);
317 case 0x03: // ir right
318 dist_right = get_distance(1);
320 case 0x09: // voltage
321 voltage = get_voltage();
323 case 0xff: // Magic reg that starts the bootloader
324 if (bootloader == 0xa5) {
326 // write mark to first area in eeprom
327 eeprom_write_byte((uint8_t*)0, 123);
329 // Use watchdog to restart
330 wdt_enable(WDTO_15MS);
335 if (start_dist_fwd1) {
344 // wait for interrupt
345 EIFR &= (1 << INTF0); // clear old interrupt before enabling
346 EIMSK |= (1 << INT0);
348 if (start_dist_bwd) {
357 // wait for interrupt
358 EIFR &= (1 << INTF1); // clear old interrupt before enabling
359 EIMSK |= (1 << INT1);
361 if (start_dist_fwd2) {
371 // wait for interrupt
373 PCMSK2 |= (1 << PCINT20);