ATmega168: подключение нескольких ультразвуковых сенсоров HC-SR04 используя аналоговый компаратор

разделы: AVR , HC-SR04 , myRobot , дата: 6 марта 2016г.

Компаратор это единственная периферия в AVR которая включена по умолчанию. Поэтому, если он не используется, его следует выключать. Допустимая ошибка (напряжение смещения) не более 40мВ, время отклика не более 0,5 мкс. Рабочие пины: прямой AIN0 и инверсный AIN1. Так же AIN0 называют положительным, а AIN1 отрицательным. Результат заносится в ACO бит регистра ACSR.

Официальный datasheet на ATmega168: http://www.atmel.com/images/doc2545.pdf работа компаратора описана в главе 23.2 на странице 246

    Хорошие справочные обзоры по работе компаратора в AVR можно найти здесь:
  1. Учебный курс AVR. Аналоговый компаратор
  2. AVR. Учебный курс. Использование аналогового компаратора

Я потратил немного времени на перевод официального руководства, с которым и предлагаю далее ознакомится.

Описание регистра ACSR

Компаратор управляется через регистр "Analog comparator control and status register" т.е. ACSR:

где:

 Bit 7 – ACD: Analog comparator disable. When this bit is written logic one, the power to the Analog Comparat or is switched off. This bit can be set at any time to turn off the Analog Comparator. This will reduce power consumption in Active and Idle mode. When changing the ACD bit, the Analog Comparator Interrupt must be disabled by clearing the ACIE bit in ACSR. Otherwise an interrupt can occur when the bit is changed.

Отключение аналогового компаратора. Когда в этот бит записана единица, питание снимается с аналогового компаратора. Этот бит может быть установлен в любой момент, что приведет к отключению аналогового компаратора. Это может быть полезно в активном и Idle режимах энергосбережения. Когда меняется ACD бит, прерывание аналогового компаратора должно быть выключено очисткой бита ACIE в ACSR регистре. Иначе оно может сработать когда ACD бит был изменен.

 Bit 6 – ACBG: Analog comparator bandgap select. When this bit is set, a fixed andgap reference voltage replaces the positive input to the Analog Comparator. hen this bit is cleared, AIN0 is applied to the positive input of the Analog Comparator. When the bandgap reference voltage is used as input to the Analog Comparator, it will take a certain time for the voltage to stabilize. If not stabilized, the first conversion may give a wrong value. See “Internal voltage reference” on page 48.

Подключение внутреннего источника опорного напряжения (ИОН или бандгап). Когда бит установлен, ИОН заменяет положительный AIN0 вход аналогового компаратора. Если использовать  ИОН то будет небольшая задержка для определения стабилизированного значения напряжения ИОН. Если не использовать задержку то на вход может попасть пиковое значение пульсации, и результат может оказаться не верным.

 Bit 5 – ACO: Analog comparator output. The output of the Analog Comparator is synchronized and then directly connected to ACO. The synchronization introduces a delay of 1 - 2 clock cycles.

Выход аналогового компаратора. Он синхронизирован с тактовым генератором и напрямую подключен к ACO. Синхронизация дает задержку в 1-2 такта.

 Bit 4 – ACI: Analog comparator interrupt flag. This bit is set by hardware when a comparator output event triggers the interrupt mode defined by ACIS1 and ACIS0. The Analog Comparator interrupt routine is executed if the ACIE bit is set and the I-bit in SREG is set. ACI is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, ACI is cleared by writing a logic one to the flag.

Флаг  прерывания аналогового компаратора. Устанавливается аппаратно, когда на выходе компаратора наступает событие установленное триггерами режима прерывания ACIS1 и ACIS0 Тогда  прерывание выполняется, если установлены биты: ACIE и I-бит регистра SREG. ACI очищается аппаратно, когда устанавливается соответствующий вектор прерывания. ACI очищается при программной  записи единицы в данный флаг.

 Bit 3 – ACIE: Analog comparator interrupt enable. When the ACIE bit is written logic one and the I-bit in the Status Register is set, the Analog Comparator interrupt is activated. When written logic zero, the interrupt is disabled.

Если ACIE бит установлен в единицу, а так же установлен I-бит регистра SREG, тогда прерывания аналогового компаратора разрешены. Иначе они запрещены.

 Bit 2 – ACIC: Analog comparator input capture enable. When written logic one, this bit enables the input capture function in Timer/Counter1 to be triggered by the Analog Comparator. The comparator output is in this case directly connected to the input capture front-end logic, making the comparator utilize the noise canceler and edge select features of the Timer/Counter1 Input Capture interrupt. When written logic zero, no connection between the Analog Comparator and the input capture function exists. To make the comparator trigger the Timer/Counter1 Input Capture interrupt, the ICIE1 bit in the Timer Interrupt Mask Register (TIMSK1) must be set.

ACIC бит установленный в единицу, подключает  функцию захвата таймера Timer/Counter1 к триггеру срабатывания аналогового компаратора. В этом случае, выход компаратора напрямую подключен к входу схеме схемы захвата таймера Timer/Counter1. Это добавляет схеме захвата сигнала функцию шумоподавления и  возможность выбора фронта сигнала(падающего или растущего). Если ACIC-бит сброшен в ноль, то связь с схемой захвата отсутствует. Чтобы включить прерывание по захвату таймера Timer/Counter1 подключенного к  выходу аналогового компаратора, должен быть установлен ICIE1-бит регистра TIMSK1.

Bits 1, 0 – ACIS1, ACIS0: Analog comparator interrupt mode select. These bits determine which comparator events that trigger the Analog Comparator interrupt. The different settings are shown in Table 23-2 
When changing the ACIS1/ACIS0 bits, the Analog Comparator Interrupt must be disabled by clearing its Interrupt Enable bit in the ACSR Register. Otherwise an interrupt can occur when the bits are changed. 

Эти биты определяют событие при котором будет вызвано прерывание аналогового компаратора.
ACIS1 = 0 и ACIS0 = 0,  то страбатывание на любое измение фронта;
ACIS1 = 0 и ACIS0 = 1,  не используется;
ACIS1 = 1 и ACIS0 = 0,  то страбатыванеи по падающему фронту;
ACIS1 = 1 и ACIS0 = 1,  то срабатывание по растущему фронту.

Когда меняются биты ACIS1/ACIS0, прерывание  аналогового компраратора должно запрещено очисткой ACIE флага. Иначе прерывание может произойти когда, биты уже были изменены.

Переключение входа аналогового компаратора.

 Bit 6 – ACME: Analog comparator multiplexer enable. When this bit is written logic one and the ADC is switched off (ADEN in ADCSRA is zero), the ADC multiplexer selects the negative input to the Analog Comparator. When this bit is written logic zero, AIN1 is applied to the negative input of the Analog Comparator.

Если в ACME-бит установлена единица, и АЦП выключен(ADEN-бит регистра ADCSRA сброшен в ноль), то мультиплексор АЦП выбирает отрицательный вход аналогового компаратора.  Когда в этот в ACME-бит записывается ноль, AIN1 подключается к отрицательному входу аналогового компаратора.  

Таблица коммутации отрицательного входа компаратора:

Принцип работы компаратора заключается в том, что когда напряжение на положительном входе больше напряжения отрицательного входа, то ACO-бит принимает положительное значение, иначе - отрицательное.

Типовой пример использования аналогового компаратора - это монитор питания. Этот пример рассмотрен в книге Юрия Ревича "Практическое программирование микроконтроллеров AVR на языке ассемблера". Меня же в компараторе заинтересовал мультиплексор, т.е. возможность комутации нескольких сенсоров.

Если мы  подключим ИОН на положительный вход, а на отрицательный будем подавать цифровой сигнал, то получим инвертор сигнала. Потому что, при напряжении ИОН ~1,22  Вольта, и логическом положительном сигнале(+5В) на отрицательном входе, получим логический ноль в ACO-бите. В свою очередь, при нуле на отрицательном входе компаратора, получим получим единицу в ACO. И т.о. мы получаем еще один пин на который можно повесить прерывание.

Для проверки того, что все работает как следует, можно собрать такую отладочную схему:

Здесь, на PD2 будем подавать периодический сигнал, на ADC0 подключим компаратор в режиме захвата. Т.е. работать он будет аналогично ICP1 пину с той разницей, что  будет инвертирующим.

Таблица распиновки ATmega168/Arduino:

Для стендовых испытаний я использую плату CraftDuino с честным FT232RL (поэтому на макетке поставил Arduino Nano ), в которой я, по необходимости, меняю чипы. Сейчас  там сабжевый  ATmega168

Прошивки компилируются путем использования avr-gcc-4.9.2, прошивка заливается через загрузчик Arduino(работает через ft232rl).

теперь пишем такой проверочный код:

#include <util/delay.h> #include <avr/io.h> #include <avr/interrupt.h> #include <uart.h> #define LED PB5 #define LED_PORT PORTB #define WIRE PD2 #define WIRE_PORT PORTD static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); volatile uint8_t cmp_value; ISR(ANALOG_COMP_vect) { cmp_value=ACSR & (1<<ACO); if(cmp_value) { LED_PORT &= ~(1<<LED); } else { LED_PORT |= (1<<LED); } } int main(void) { //---- init init_uart(); DDRB |= (1<<LED); // led indicator DDRD |= (1<<WIRE); // output // comparator ACSR = (1<<ACIE)|(1<<ACBG);// bandgap ON; interrupt ON; comparator ON ADCSRB |=(1<<ACME); // enable multiplexer ADMUX = 0; // ADC0 on negative input of the Analog Comparator //---- ready indication blink13(3); stdout = &mystdout; printf("Ok, I'm ready!\n"); sei(); //---- main body for (;;) { WIRE_PORT |=(1<<WIRE); // ON _delay_ms(1000); WIRE_PORT &= ~(1<<WIRE); // OFF _delay_ms(2000); }; return 0; }

здесь, на отрицательный вход компаратора подается периодический сигнал с PD2. В прерывании анализируется знак операции и светодиод на PB5(pin 13) зажигается или тушится. Должно быть так: одну секунду горит, две нет. И т.д.

Следующий пример будет поинтереснее. На выход компаратора подключим схему захвата. Это будет уже конвеер. С помощью этого фокуса определим продолжительность пикового сигнала.

#include <util/delay.h> #include <avr/io.h> #include <avr/interrupt.h> #include <uart.h> #define LED PB5 #define LED_PORT PORTB #define WIRE PD2 #define WIRE_PORT PORTD static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); volatile uint16_t time; volatile uint8_t sec; ISR(TIMER1_OVF_vect) { sec++; } ISR(TIMER1_CAPT_vect) { uint16_t tmp; time=(uint16_t)ICR1L; tmp=(uint16_t)ICR1H; tmp<<=8; time|=tmp; } ISR(ANALOG_COMP_vect) { TCNT1H=0; TCNT1L=0;// clearing cunter sec=0; uint8_t cmp_value; cmp_value=ACSR & (1<<ACO); if(cmp_value) { LED_PORT &= ~(1<<LED); } else { LED_PORT |= (1<<LED); } } int main(void) { //---- init init_uart(); DDRB |= (1<<LED); // led indicator DDRD |= (1<<WIRE); // output // init 16-bit timer TIMSK1 =(1<<ICIE1) |(1<<TOIE1); // Timer1: enable overflow and capture interrupts TCCR1B= (1<<ICES1)| (1<<CS12);// prescaler 1/256, overflow period 1 sec on 16MHz Quarz // comparator ACSR = (1<<ACIE)|(1<<ACIC)|(1<<ACBG);// bandgap ON; capture interrupt ON; comparator interrupt ON ADCSRB |=(1<<ACME); // enable multiplexer ADMUX = 0; // ADC0 on negative input of the Analog Comparator //---- ready indication blink13(3); stdout = &mystdout; printf("Ok, I'm ready!\n"); sei(); //---- main body for (;;) { WIRE_PORT |=(1<<WIRE); // ON _delay_ms(200); WIRE_PORT &= ~(1<<WIRE); // OFF _delay_ms(800); printf("sec: %d timer: %u\n", sec,time); }; return 0; }

здесь, при работе, светодиод на PB5(pin 13) мигает на 0.2 сек и гаснет на 0.8 сек. На последовательном порту получаем такой лог:

Немного пояснениий. 16-битный Timer1 запускаем с пределителем 256, один тик таймера равен 1/65536 секунды, т.е. переполняться он будет один раз в секунду. Соответственно  в прерывании по переполнению таймера считаются секунды. На вход компаратора одается такой сигнал:

Прерывание компаратора вызывается при любом изменении фронта. В этом прерывании очищается счетчик таймера. Требуется измерить продолжительность пикового  сигнала, двительность которого, в данном случае,  200ms(синяя стрелка).

На выходе компаратора и, следственно, на входе схемы захвата имеем инверсный сигнал:

Причем прерывание по захвату срабатывает на растущий фронт (бит ICES1 установлен).  Т.о. удается измерить положительный полупериод исходного сигнала. Любопытно, что схема захвата  успевает сбросить в регистры захвата значение таймера до того, как оно очистится в прерывании компаратора.

Ну и  цифра 12500, которая выводится на UART, это 12500/65536 ~ 0.19 секунды.

Теперь вспоминаем диаграмму работы сенсора HC-SR04:

Определяя положительный полупериод Echo линии, мы получим измеряемое расстояние. А используя мультиплексор, возможно подлючение нескольких ультразвуковых сенсоров с их последовательным опросом.

В чем смысл использования двух сенсоров HC-SR04?

Когда я собрал свою первую машинку с одним ультразвуковым сенсором, она по поведению напоминала таракана с оторванной головой. Т.е. она могла только ехать по прямой, "видеть" какое-то препятствие и сворачивать в сторону. Все. Это бьл только бегающий жужжащий таракан. С одним сенсором нельзя сделать никаких выводов о характере препятствия, с которым столкнулся Искусственный Интелелект. С двумя же сенсорами можно сделать многое.


рисунок 1

Как известно, уравнение прямой можно составить по двум точкам. Тогда при столкновении со сплошной стеной, во время движения робо-платформы вперед, сенсоры будут измерять расстояния до различных участков стены. И если они будут подчиняться уравнению прямой, то можно будет сделать вывод о том, что это сплошное ровное препятствие, например, стена.


рисунок 2

Если же участки исследуемой поверхности не подчиняются уравнению прямой, то будет ясно, что это неровная поверхность. А когда, по мере приближения, они начнут подчиняться уравнению прямой, то это будет значить, что мы прошли угол. В случае, изображенном на рисунке 2, можно будет взять значения каждого сенсора в разные моменты времени и для каждого отдельно составить уравнение прямой. Найдя точку пересечения прямых, можно будет найти угол.


рисунок 3

Сенсоры, расположенные под углом, имеют слепую зону.


рисунок 4

Однако, скрещенные сенсоры все равно натолкнутся на препятствие и смогут детально, с разных углов, обследовать его.

Так, вернемся к нашим сенсорам. Для тестирования последовательного опроса двух сенсоров, нужно будет собрать схему:

программа у меня получилась такой:

#include <util/delay.h> #include <avr/io.h> #include <avr/interrupt.h> #include <uart.h> #define LED PB5 #define LED_PORT PORTB #define RIGHT PD2 #define RIGHT_PORT PORTD #define LEFT PD3 #define LEFT_PORT PORTD static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); volatile uint16_t time; volatile uint8_t sec; ISR(TIMER1_OVF_vect) { sec++; } ISR(TIMER1_CAPT_vect) { uint16_t tmp; time=(uint16_t)ICR1L; tmp=(uint16_t)ICR1H; tmp<<=8; time|=tmp; } ISR(ANALOG_COMP_vect) { TCNT1H=0; TCNT1L=0;// clearing cunter sec=0; uint8_t cmp_value; cmp_value=ACSR & (1<<ACO); if(cmp_value) { LED_PORT &= ~(1<<LED); } else { LED_PORT |= (1<<LED); } } int main(void) { //---- init init_uart(); DDRB |= (1<<LED); // led indicator DDRD |= (1<<RIGHT); // output DDRD |= (1<<LEFT); // init 16-bit timer TIMSK1 =(1<<ICIE1) |(1<<TOIE1); // Timer1: enable interrupt TCCR1B= (1<<ICES1)| (1<<CS12);// prescaler 1/256, overflow period 1 sec on 16MHz Quarz // comparator ACSR = (1<<ACIE)|(1<<ACIC)|(1<<ACBG);// bandgap ON; capture interrupt ON; comparator ON ADCSRB |=(1<<ACME); // enable multiplexer ADMUX = 0; // ADC0 on negative input of the Analog Comparator //---- ready indication blink13(3); stdout = &mystdout; printf("Ok, I'm ready!\n"); sei(); //---- main body for (;;) { ADMUX =0; _delay_ms(500); RIGHT_PORT |= (1<<RIGHT); // ON _delay_ms(10); RIGHT_PORT &= ~(1<<RIGHT); // OFF _delay_ms(300); ADMUX=1; _delay_ms(10); printf("sec: %d timer: %u\n", sec,time); LEFT_PORT |=(1<<LEFT); // ON _delay_ms(10); LEFT_PORT &= ~(1<<LEFT); // OFF _delay_ms(500); printf("sec: %d timer: %u\n", sec,time); }; return 0; }

лог с UART

здесь у меня оба сенсора были подключены параллельно, поэтому цифры часто парные. Хотя, зедержка 0,3 сек дает, конечно, знать о себе. Чтобы перевести значения с сенсоров в сантиметры, их нужно разделить на 3.71875

скачать архив с исходниками к последенму примеру:

скачать

поделиться: