Характеристики ультразвукового дальномера HC-SR04
- Измеряемый диапазон: 2 см — 500 см
- Точность: 0,3 см
- Угол обзора: < 15 °
- Напряжение питания 5V
Принцип работы ультразвукового дальномера HC-SR04
В составе дальномера два пьезоэлемента, один работает как излучатель сигнала, другой как приемник. Излучатель генерирует сигнал, который отразившись от препятствия попадает на приёмник. Измерив время за которое сигнал проходит до объекта и обратно можно оценить расстояние.
Модуль датчика расстояния HC-SR04 имеет 4 вывода:
- VCC: питание 5 вольт
- Trig: вход триггера, запускающего измерения
- Echo: выход, на котором генерируется импульс, длительность которого пропорциональна расстоянию
- GND: земля
В документации на модуль датчика расстояния HC-SR04 указано, что для запуска измерений на вход Trig надо подать импульс длительностью 10-15 микросекунд. После чего на выходе Echo появится импульс длительностью 150мкс — 25мс. Длительность этого импульса пропорциональна расстоянию до объекта, от которого отразился ультразвуковой сигнал. Для того что бы из длительности сигнала в микросекундах получить расстояние в сантиметрах используется формула:
D = T/58
где:
T — длительности сигнала в микросекундах
D — расстояние в сантиметрах
Если же отраженный сигнал не дошёл до приёмника, то на выходе Echo будет импульс длительностью 38 попугаев миллисекунд,
Пример использования ультразвукового дальномера HC-SR04 с микроконтроллером AVR atmega
Описание программы для avr atmega: программа запускает измерения, генерируя импульс 10 мкс. на выходе PD3, соединённого с входом Trig. Выход Echo подключён к PD2, который используется как внешнее прерывание. По переднему фронту на PD2 сбрасываем в ноль таймер счетчик timer1. По заднему фронту на PD2 запоминается значение таймера счетчика timer1. Далее, полученная длина импульса переводится в сантиметры и выводится в uart. Через 1 секунду цикл измерений повторяется. Так как timer1 настроен так, что длительность тика равна 8.68 мкс ( 1/(7372800/64) ), то используется пересчитанный коэффициент для перевода в сантиметры 58/8.68 = 6.68, округляем до 7;
Далее приведён исходный текст только основных функций для avr atmega, целиком исходники проекта avr-gcc (WinAvr) можно скачать тут.
#include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include "uart.h" #include "ext_int.h" #include "timer1.h" //порт для генерирования сигнала TRIG #define HC_SR04_TRIG_PORT PORTD #define HC_SR04_TRIG_DDR DDRD #define HC_SR04_TRIG_BIT _BV(3) //порт для измерения длительности импульса #define HC_SR04_ETHO_PIN PIND #define HC_SR04_ECHO_BIT _BV(2) //состояние измерения #define HC_SR04_START 0 //запуск #define HC_SR04_MEAS 1 //в процессе #define HC_SR04_END 2 //окончено volatile unsigned char hc_sr04_status; //измеренная длительность импульса volatile unsigned short hc_sr04_cnt; //функция обработчик внешнего прерывания INT0 void hc_sr04_int_handler( void ) { //проверяем уровень сигнала PD2( ECHO ) if( HC_SR04_ETHO_PIN & HC_SR04_ECHO_BIT ) { //передний фронт - сбрасываем в 0 таймер timer1_clr(); hc_sr04_status = HC_SR04_MEAS; } else { //задний фронт - запоминаем значение таймера hc_sr04_cnt = timer1_cnt(); hc_sr04_status = HC_SR04_END; } } void hc_sr04_init( void ) { //устанавливаем функцию для обработки внешнего прерывания INT0 int0_set_handler( hc_sr04_int_handler ); //разрешаем внешнее прерывание INT0 int0_enable(); //настраиваем внешнее прерывание INT0 на срабатывание любому изменению int0_set_source( INT0_ANY_CHANGE ); //настраиваем timer1д timer1_init(); //настраиваем PD3(TRIG) на выход HC_SR04_TRIG_PORT |= ~HC_SR04_TRIG_BIT; HC_SR04_TRIG_DDR |= HC_SR04_TRIG_BIT; } //измерение дальности, возвращает значение в см unsigned short hc_sr04_meas( void ) { //состояние - начало измерений hc_sr04_status = HC_SR04_START; //генерируем импульс 10 мкс на входе trig HC_SR04_TRIG_PORT |= HC_SR04_TRIG_BIT; _delay_us( 10 ); HC_SR04_TRIG_PORT &= ~HC_SR04_TRIG_BIT; //ждем окончания измерения while( hc_sr04_status != HC_SR04_END ); // 58/8.68 = 6.68 ~ 7 //переводим в сантиметры return hc_sr04_cnt/7; } FILE uart_stream = FDEV_SETUP_STREAM( uart_putc, NULL, _FDEV_SETUP_WRITE ); int main( ) { unsigned short sm; //настройка uart uart_init(); //инициализация датчика hc_sr04_init(); stdout = &uart_stream; sei(); while( 1 ) { //измерение sm = hc_sr04_meas(); printf( "sm = %u\r\n", sm ); //задержка 1 сек _delay_ms( 1000 ); } return 0; } |
Хочу немного добавить, что вход Trig срабатывает даже от импульса в 300нс, импульс на Echo появляется примерно через 500мкс и его длительность не превышает 4мс, если удалось измерить расстояние. Ну и потребление во время импульса не должно превышать 20мА. Я может быть когда-нибудь напишу про этот девайс более подробно в своем блоге.
Спасибо за дополнительную инфу :)
Google выдает 96 рублей стоимость. с учетом того что самый плохой/дешевый парктроник стоит — 30$, проще весь бампер обложить такими датчиками. +доллоровый MAXII и светодиодные столбики на каждый датчик.
На ebay можно и за 2$ купить с бесплатной доставкой.
А сделать парктроник — мысль интересная, но мне кажется, что на наших дорогах датчики быстро забьются грязью и не будут работать.
Есть датчики для парктроников же я покупал за 150р год назад, лежит всё не до него…Так он защищён более-менее.
У меня просто была задумка проверить как он под водой работает и сделать ходовой эхолот но тут за много цепляется проблем- дифферент, качка и т.д. Гироскоп надо)
Интересная идея, а не подскажите что у Вас за датчики?
Добрый день Артем!! =) Мне понравилась Ваша статья…
У Вас, в документе «ext_int.h» ,там где приведены 3 функции по прерываниям.
Я бы хотел спросить как работает 1-вая и 3-тья функция. Могли бы Вы сделать небольшие комментарии здесь или рассказать как работает компилятор, просто на си не особо силен, изучаю пока =)))
Хочу понять всю Вашу программу. Заранее благодарен!)
Добрый день!
дописал комментарии, если есть еще вопросы — пишите, попробую ответить =)
================================================
//функция настраивает по какому событию будет происходить прерывание int0
//в качестве параметра передаться маска из бит ISC00 ISC01, которая определяет событие
void int0_set_source( unsigned char source )
{
MCUCR &= ~(1<<ISC01)|(1<<ISC00); //сбрасываем биты ISC00 ISC01
MCUCR |= source; //вместо сброшенных выставляем биты, которые переданы через параметр source
}
================================================
//функция устанавливает указатель на функцию, которую надо вызывать при срабатывании прерывания int0
//в качестве параметра передаётся адрес этой функции
void int0_set_handler( void( *handler)( void ) )
{
int0_handler = handler; // int0_handler — это переменная указатель на функцию, этот указатель приравниваем адресу функции, который передан как параметр handler
}
================================================
//обработчик внешнего прерывания INT0
//в эту функцию передаётся управление когда срабатывает int0
//если установлен указатель на функцию, которую надо вызвать по срабатыванию int0, то
//происходит вызов функции по указателю
ISR( INT0_vect )
{
if( int0_handler != NULL ) { //если указатель на функцию не равен нулю
int0_handler(); //то по этому указателю вызываем функцию
}
}
Работа с датчиком расстояния HC-SR04 в ассемблере
???
День добрый! Я новичок в С, хочу поинтересоваться, зачем вызывать функцию через указатель, вместо того, что бы просто указать имя функции?
Вызов через указатель был сделан для того что бы повысить модульность исходного кода. В таком виде код, который работает с прерываниями, можно использовать в других проектах без изменений.
А так, конечно, можно вызывать функцию и напрямую, программа будет работать быстрее и памяти будет меньше занимать.
Выходит, что в даташите врут. 4мс приблизительно 70см
Думаю, Константин, ошибся. Этим дальномером получалось измерять расстояние более 2м, при этом длительность импульса была более 10 мс.
Большое спасибо за пример, запустил, все работает, НО!
При ошибке получения отклика на сонаре микроконтроллер зависает, это скорее всего вызвано строкой
,while( hc_sr04_status != HC_SR04_END )
то есть если по каким-то причинам не пришел сигнал окончания измерения (например, слишком большой угол поверхности отражения) программа «зацикливается». Как самый простой вариант решения данной проблемы:
//while( hc_sr04_status != HC_SR04_END );
_delay_ms( 50 );