2 #include <avr/interrupt.h>
3 #include <util/delay.h>
8 #define ECHO_TIMEOUT (CLOCK_HZ/10) // 100 ms
9 #define MEASUREMENT_WAIT (2*ECHO_TIMEOUT)
10 #define MEASUREMENT_SHIFT 0 // running avg (1 << M_SHIFT)
14 #define N_TRIG_SENSORS 4
16 // static int16_t distances[N_SENSORS];
18 // hold_regs[0] is unit ID
19 #define thresholds (hold_regs+1)
20 #define led1_sensors (hold_regs[13])
21 #define led2_sensors (hold_regs[14])
22 #define long_as_free (hold_regs[15])
23 #define long_thr (hold_regs[16])
25 #define led_bitmap (hold_regs[MB_N_HOLD_REGS_EEPROM])
26 #define distances (hold_regs+MB_N_HOLD_REGS_EEPROM+1)
27 #define free_bitmap (hold_regs[MB_N_HOLD_REGS_EEPROM+13])
28 #define err_bitmap (hold_regs[MB_N_HOLD_REGS_EEPROM+14])
29 #define long_bitmap (hold_regs[MB_N_HOLD_REGS_EEPROM+15])
30 #define max_distances (hold_regs+MB_N_HOLD_REGS_EEPROM+21)
31 #define err_counts (hold_regs+MB_N_HOLD_REGS_EEPROM+41)
33 static void pull_trigger(uint8_t trig)
36 case 0: PORTD |= _BV(PD7); _delay_us(10); PORTD &= ~_BV(PD7); break;
37 case 1: PORTB |= _BV(PB4); _delay_us(10); PORTB &= ~_BV(PB4); break;
38 case 2: PORTC |= _BV(PC4); _delay_us(10); PORTC &= ~_BV(PC4); break;
42 static uint16_t get_pin(uint8_t trig)
45 case 0: return (PIND & 0x78) >> 3;
46 case 1: return PINB & 0x0F;
47 default: return PINC & 0x0F;
51 static void do_measurement(unsigned char trig)
53 uint16_t starttimes[N_TRIG_SENSORS], starttime;
54 uint8_t to_start = (1 << N_TRIG_SENSORS) - 1;
55 uint8_t to_measure = 0, i;
60 starttime = get_clock();
62 while (to_start || to_measure) {
66 if (now-starttime >= ECHO_TIMEOUT)
71 for (i = 0; i < N_TRIG_SENSORS; i++) {
72 uint8_t mask = 1 << i;
74 if ((to_start & mask) && (bits & mask)) {
79 } else if ((to_measure & mask) && !(bits & mask)) {
80 #if MEASUREMENT_SHIFT > 0
84 uint8_t idx = trig*N_TRIG_SENSORS+i;
87 new_d = now - starttimes[i];
88 if (new_d > max_distances[idx])
89 max_distances[idx] = new_d;
91 #if MEASUREMENT_SHIFT > 0
92 old_d = distances[idx];
96 distances[idx] = new_d;
99 (old_d << MEASUREMENT_SHIFT)
102 ) >> MEASUREMENT_SHIFT;
105 distances[idx] = new_d;
111 for (i = 0; i < N_TRIG_SENSORS; i++) {
112 uint8_t off = trig*N_TRIG_SENSORS + i;
114 if (to_start & (1 << i)) { // echo not received
115 uint16_t err_count = err_counts[off] & 0xFF;
116 if (distances[off] != -1 && err_count < 255) {
118 err_counts[off] = (err_counts[off] & 0xFF00)
122 } else if (to_measure & (1 << i)) { // echo pulse too long
123 uint16_t err_count = err_counts[off] >> 8;
125 if (err_count < 255) {
127 err_counts[off] = (err_counts[off] & 0x00FF)
131 * If the echo pulse is too long, do not treat it
132 * as error, just count it as maximum length
133 * and notify the state in the bitmap.
135 distances[off] = now - starttimes[i];
140 static void led_set(uint8_t led, uint8_t state)
173 static void leds_update()
175 if (led_bitmap & 1) {
181 if (led_bitmap & 2) {
187 if (led_bitmap & 4) {
193 if (led_bitmap & 8) {
200 static void eval_bitmaps()
202 uint16_t free_b = 0, err_b = 0, long_b = 0, mask;
205 for (i = 0; i < N_SENSORS; i++) {
209 if (distances[i] == -1) {
211 } else if (distances[i] > thresholds[i]) {
212 if (long_thr && distances[i] > long_thr) {
214 if (long_as_free & mask) {
224 free_bitmap = free_b;
226 long_bitmap = long_b;
229 if (led1_sensors & err_bitmap) {
231 } else if (led1_sensors & free_bitmap) {
239 if (led2_sensors & err_bitmap) {
241 } else if (led2_sensors & free_bitmap) {
249 uint8_t hold_reg_is_valid(uint16_t reg, uint16_t val)
251 if (reg == MB_HOLD_REGS_BASE)
252 return val > 0 && val <= 247;
262 DDRD |= _BV(PD7); // Trig D
263 DDRB |= _BV(PB4) | _BV(PB5); // Trig B, LED 2
264 DDRC |= _BV(PC4) | _BV(PC5); // Trig C, LED 1
268 TCCR1B = _BV(CS12)|_BV(CS10); // CLK/1024
275 for (trig = 0; trig < N_TRIGGERS; trig++) {
277 do_measurement(trig);
279 while (get_clock()-now < MEASUREMENT_WAIT)
284 leds_update(); // might be written from modbus
286 // distances[4] > 100 || distances[11] > 100);