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 forward MSB
18 * 0x06 Distance forward LSB
19 * 0x07 Distance backward MSB
20 * 0x08 Distance backward LSB
28 #define TWI_ACK TWCR = (1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
29 #define TWI_RESET TWCR &= ~((1 << TWSTO) | (1 << TWEN)); TWI_ACK
30 #define TWI_NAK TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
32 static volatile uint8_t ireg=0;
33 static volatile uint8_t bootloader=0;
34 static volatile uint16_t dist_left=0;
35 static volatile uint16_t dist_right=0;
36 static volatile uint16_t dist_forward=0;
37 static volatile uint16_t dist_backward=0;
38 static volatile uint8_t start_dist_fwd=0;
39 static volatile uint8_t start_dist_bwd=0;
40 static volatile uint16_t voltage=0;
44 static int16_t tmp16=0;
48 case 0x60: // start write
54 case 0x00: // register select
57 if (ireg == 0x05) start_dist_fwd=1;
58 if (ireg == 0x07) start_dist_bwd=1;
60 ireg--; // because we do ireg++ below
63 case 0xff: // bootloader
70 case 0xA8: // start read
73 case 0x01: // Distance left MSB
78 case 0x02: // Distance right LSB
82 case 0x03: // Distance right MSB
87 case 0x04: // Distance right LSB
91 case 0x05: // Distance forward MSB
96 case 0x06: // Distance forward LSB
100 case 0x07: // Distance backward MSB
101 tmp16 = dist_backward;
105 case 0x08: // Distance backward LSB
109 case 0x09: // Voltage MSB
114 case 0x0A: // Voltage LSB
130 uint16_t ReadChannel(uint8_t mux) {
134 ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
135 // setzen auf 8 (1) und ADC aktivieren (1)
137 ADMUX = mux; // Kanal waehlen
140 /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
141 also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
142 ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
143 while ( ADCSRA & (1<<ADSC) ) {
144 // auf Abschluss der Konvertierung warten
146 result = ADCW; // ADCW muss einmal gelesen werden,
147 // sonst wird Ergebnis der nächsten Wandlung
150 /* Eigentliche Messung - Mittelwert aus 5 aufeinanderfolgenden Wandlungen */
154 ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
155 while ( ADCSRA & (1<<ADSC) ) {
156 // auf Abschluss der Konvertierung warten
158 result += ADCW; // Wandlungsergebnisse aufaddieren
161 ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
163 result /= 5; // Summe durch 5 teilen = arithm. Mittelwert
169 static unsigned short get_distance(uint8_t i) {
170 return ReadChannel(i);
174 static unsigned short get_voltage(void) {
175 return ReadChannel(2)*1.46;
180 static uint16_t t_start=0;
181 uint16_t t_now = TCNT1;
184 if (bit_is_set(PIND, 2)) { // high level
188 t_diff = t_now - t_start;
189 dist_forward = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
190 // disable this interrupt
191 EIMSK |= (1 << INT0);
197 static uint16_t t_start=0;
198 uint16_t t_now = TCNT1;
201 if (bit_is_set(PIND, 3)) { // high level
205 t_diff = t_now - t_start;
206 dist_backward = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
207 // disable this interrupt
208 EIMSK |= (1 << INT1);
222 // Timer 1: Normal mode, Top: 0xffff, Prescaler: F_CPU/256=62500Hz
224 TCCR1B = (1 << CS12);
226 // External Interrupts
227 EICRA = (1 << ISC10) | (1 << ISC00);
229 printf("\r\nStart\r\n");
231 set_sleep_mode(SLEEP_MODE_IDLE);
235 case 0x01: // ir left
236 dist_left = get_distance(0);
238 case 0x03: // ir right
239 dist_right = get_distance(1);
241 case 0x09: // voltage
242 voltage = get_voltage();
244 case 0xff: // Magic reg that starts the bootloader
245 if (bootloader == 0xa5) {
248 void (*start)(void) = (void*)0x1800;
255 if (start_dist_fwd) {
264 // wait for interrupt
265 EIMSK |= (1 << INT0);
267 if (start_dist_bwd) {
276 // wait for interrupt
277 EIMSK |= (1 << INT1);