5 #include <avr/interrupt.h>
7 #include <util/delay.h>
9 #include <avr/eeprom.h>
11 #include <avr/pgmspace.h>
15 * I2C Register Map (8 Bit)
16 * 0x00 Register select
17 * 0x01 Distance left MSB
18 * 0x02 Distance left LSB
19 * 0x03 Distance right MSB
20 * 0x04 Distance right LSB
21 * 0x05 Distance forward1 MSB
22 * 0x06 Distance forward1 LSB
23 * 0x07 Distance backward MSB
24 * 0x08 Distance backward LSB
27 * 0x0B Distance forward2 MSB
28 * 0x0C Distance forward2 LSB
32 * 0x15 Distance forward1 MSB (read only)
33 * 0x16 Distance forward1 LSB (read only)
34 * 0x17 Distance backward MSB (read only)
35 * 0x18 Distance backward LSB (read only)
36 * 0x19 Distance forward2 MSB (read only)
37 * 0x1A Distance forward2 LSB (read only)
70 #define TWI_ACK TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE)
71 #define TWI_NAK TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE)
72 #define TWI_RESET TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWSTO) | (1<<TWEN) | (1<<TWIE);
74 static volatile uint8_t ireg=0;
75 static volatile uint8_t bootloader=0;
76 static volatile uint16_t dist_left=0;
77 static volatile uint16_t dist_right=0;
78 static volatile uint16_t dist_forward1=0;
79 static volatile uint16_t dist_forward2=0;
80 static volatile uint16_t dist_backward=0;
81 static volatile uint8_t start_dist_fwd1=0;
82 static volatile uint8_t start_dist_fwd2=0;
83 static volatile uint8_t start_dist_bwd=0;
84 static volatile uint16_t voltage=0;
85 static volatile uint16_t current=0;
86 static volatile uint8_t pind_pre=0;
90 static int16_t tmp16=0;
94 case TW_SR_SLA_ACK: // start write
98 case TW_SR_DATA_ACK: // write
100 case 0x00: // register select
103 if (ireg == 0x05) start_dist_fwd1=1;
104 if (ireg == 0x07) start_dist_bwd=1;
105 if (ireg == 0x0b) start_dist_fwd2=1;
107 ireg--; // because we do ireg++ below
110 case 0xff: // bootloader
115 if (ireg < 0xff) ireg++;
117 case TW_ST_SLA_ACK: // start read
118 case TW_ST_DATA_ACK: // read
120 case 0x01: // Distance left MSB
125 case 0x02: // Distance right LSB
129 case 0x03: // Distance right MSB
134 case 0x04: // Distance right LSB
138 case 0x05: // Distance forward1 MSB
139 tmp16 = dist_forward1;
143 case 0x06: // Distance forward1 LSB
147 case 0x07: // Distance backward MSB
148 tmp16 = dist_backward;
152 case 0x08: // Distance backward LSB
156 case 0x09: // Voltage MSB
161 case 0x0A: // Voltage LSB
165 case 0x0B: // Distance forward2 MSB
166 tmp16 = dist_forward2;
170 case 0x0C: // Distance forward2 LSB
174 case 0x0D: // Current MSB
179 case 0x0E: // Current LSB
183 case 0x15: // Distance forward1 MSB
184 tmp16 = dist_forward1;
188 case 0x16: // Distance forward1 LSB
192 case 0x17: // Distance backward MSB
193 tmp16 = dist_backward;
197 case 0x18: // Distance backward LSB
201 case 0x19: // Distance forward2 MSB
202 tmp16 = dist_forward2;
206 case 0x1A: // Distance forward2 LSB
227 uint16_t ReadChannel(uint8_t mux) {
231 ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
232 // setzen auf 128 (1) und ADC aktivieren (1)
235 ADMUX = mux; // Kanal waehlen
238 /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
239 also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
240 ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
241 while ( ADCSRA & (1<<ADSC) ) {
242 // auf Abschluss der Konvertierung warten
244 result = ADCW; // ADCW muss einmal gelesen werden,
245 // sonst wird Ergebnis der nächsten Wandlung
248 /* Eigentliche Messung - Mittelwert aus 5 aufeinanderfolgenden Wandlungen */
252 ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
253 while ( ADCSRA & (1<<ADSC) ) {
254 // auf Abschluss der Konvertierung warten
256 result += ADCW; // Wandlungsergebnisse aufaddieren
259 ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
261 result /= 5; // Summe durch 5 teilen = arithm. Mittelwert
267 static unsigned short get_distance(uint8_t i) {
268 return ReadChannel(i);
272 static unsigned short get_voltage(void) {
273 return ReadChannel(2)*1.46;
279 * sensitivity: 133mV/A
281 static unsigned short get_current(void) {
282 double volt = ReadChannel(3)*5.0171; // mV
283 return (volt-517.78)/0.12656; // mA
288 static uint16_t t_start=0;
289 uint16_t t_now = TCNT1;
292 if (bit_is_set(PIND, 2)) { // high level
296 t_diff = t_now - t_start;
297 dist_forward1 = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
298 // disable this interrupt
299 EIMSK &= ~(1 << INT0);
305 static uint16_t t_start=0;
306 uint16_t t_now = TCNT1;
309 if (bit_is_set(PIND, 3)) { // high level
313 t_diff = t_now - t_start;
314 dist_backward = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
315 // disable this interrupt
316 EIMSK &= ~(1 << INT1);
322 uint8_t pind_cur = PIND;
324 if ((pind_cur ^ pind_pre) & (1<<4)) { // PCINT20
325 static uint16_t t_start=0;
326 uint16_t t_now = TCNT1;
329 if (bit_is_set(pind_cur, 4)) { // high level
333 t_diff = t_now - t_start;
334 dist_forward2 = t_diff*2.7586 + 0.5; // t [µs] / 580 = mm
335 // disable this interrupt
336 PCMSK2 &= ~(1 << PCINT20);
353 // Timer 1: Normal mode, Top: 0xffff, Prescaler: F_CPU/256=62500Hz
355 TCCR1B = (1 << CS12);
357 // External Interrupts
358 EICRA = (1 << ISC10) | (1 << ISC00);
359 PCICR = (1 << PCIE2);
361 printf_P(PSTR("\r\nStart\r\n"));
363 set_sleep_mode(SLEEP_MODE_IDLE);
367 case 0x01: // ir left
368 dist_left = get_distance(0);
370 case 0x03: // ir right
371 dist_right = get_distance(1);
373 case 0x09: // voltage
374 voltage = get_voltage();
376 case 0x0d: // current
377 current = get_current();
379 case 0xff: // Magic reg that starts the bootloader
380 if (bootloader == 0xa5) {
382 // write mark to first area in eeprom
383 eeprom_write_byte((uint8_t*)0, 123);
385 // Use watchdog to restart
386 wdt_enable(WDTO_15MS);
391 if (start_dist_fwd1) {
400 // wait for interrupt
401 EIFR &= (1 << INTF0); // clear old interrupt before enabling
402 EIMSK |= (1 << INT0);
404 if (start_dist_bwd) {
413 // wait for interrupt
414 EIFR &= (1 << INTF1); // clear old interrupt before enabling
415 EIMSK |= (1 << INT1);
417 if (start_dist_fwd2) {
427 // wait for interrupt
429 PCMSK2 |= (1 << PCINT20);