Ультразвуковой датчик HC-SR04 – дальномер на микроконтроллере

Подключение модуля HC-SR04 к микроконтроллеруПросматривая в сети модули для робототехники, я наткнулся на ультразвуковой измеритель расстояния HC-SR04, после чего решил испытать его в действии и приобрел данный модуль в Китае за невысокую цену. На модуле установлены два пъезоизлучателя, один из которых является излучателем, а другой приемником звуковых волн. Принцип действия основан на измерении времени между излучением и приемом отраженных от объекта звуковых волн, при этом зная скорость звука в воздухе можно вычислить расстояние до объекта: S=(Vзв х t)/2, где Vзв – скорость звука в воздухе, которая составляет в среднем 330-340 м/с, t – промежуток времени между излучением и приемом отраженного звукового сигнала.

Модуль можно заказать здесь. По заявленным характеристикам модуль измеряет расстояния от 2 см до 4 м, частота ультразвука составляет 40 кГц. На следующей картинке представлена диаграмма работы модуля:
Диаграмма работы модуля HC-SR04
Для начала цикла измерения необходимо подать на вывод Trig положительный импульс длительностью 10 мкс, после чего модуль подает на излучатель 8 пачек импульсов с частотой 40 кГц, и переключается в режим приема эха, отраженного от объекта. На выводе Echo появляется положительный импульс, длительность которого прямо пропорциональна расстоянию до объекта. Расстояние рассчитывается по следующей формуле: S(см)=Tимп(мкс)/58, где Tимп – длительность импульса на выводе Echo в микросекундах, S – расстояние до объекта в сантиметрах. Рекомендуемая пауза между циклами измерений составляет 60 мс, пауза нужна для исчезновения эха от предыдущего измерения.

Ниже представлена схема дальномера на микроконтроллере PIC16F628A с применением ультразвукового (УЗ) модуля:
Схема подключение модуля HC-SR04 к микроконтроллеру
Для отображения результатов измерения я использовал цифровой индикатор на микросхеме MAX7219, в микроконтроллере включены прерывания по изменению уровня на входах RB4-RB7, вывод Echo модуля A1 подключен к линии RB4, линии RB5-RB7 настроены на выход для исключения ложного срабатывания, они используются для управления индикатором HG1. Напомню что, в микроконтроллере PIC16F628A, прерывания по изменению уровня на входах RB4-RB7 включаются для всех четырех линий, возможность индивидуальной настройки каждой линии отсутствует.

Теперь рассмотрим код программы микроконтроллера:

Микроконтроллер работает от внутреннего тактового генератора частотой 4 МГц. В начале основной программы выполняется настройка линий ввода\вывода, далее настраивается 16-ти разрядный таймер TMR1, с помощью него будет производиться измерение длительности импульса на выходе УЗ модуля. Коэффициент предделителя таймера устанавливается равным 1:1, выбирается внутренний источник тактового сигнала Fosc/4, при таких настройках таймер переполнится через 65536 мкс, инкремент происходит каждую микросекунду. Далее разрешаются прерывания периферийных модулей, прерывание по переполнению таймера TMR1. Вызывается подпрограмма инициализации (init_lcd) драйвера MAX7219 цифрового индикатора, после чего вызывается подпрограмма signal_not, для вывода символов тире “- – -” на цифровой индикатор. Следом идет вызов подпрограммы запуска цикла измерения start_pul, в подпрограмме выполняется сброс флага готовности измерения flag,1, на линии trig (RB3) устанавливается высокий логический уровень на 10 мкс, тем самым УЗ модуль начинает процесс измерения. После подачи команды, сбрасываем флаг и разрешаем прерывания по изменению уровня на входах RB4-RB7, после выхода из подпрограммы start_pul, разрешаем глобальные прерывания и переходим к опросу флага готовности flag,1 и флага получения длительности импульса flag,0.

Спустя некоторое время УЗ модуль устанавливает высокий логический уровень на выводе Echo, происходит прерывание по изменению уровня на линии RB4 и переход в обработчик прерываний. В подпрограмме обработки прерываний проверяется состояние линии echo (RB4), и если оно равно 1, выполняется запуск таймера TMR1, тем самым начинается процесс измерения длительности импульса. После запуска таймера выполняется сброс флага прерываний по изменению уровня на входах RB4-RB7 и выход из обработчика прерываний.

Через определенный промежуток времени (пропорциональный расстояние до объекта) на линии RB4 устанавливается низкий логический уровень, происходит очередное прерывание по изменению уровня RB4. В обработчике прерываний снова проверяется состояние линии echo (RB4), на этот раз оно равно нулю и происходит переход на метку stop_tmr1. Выполняется остановка таймера TMR1, значение регистров таймера (в микросекундах) копируется в регистры хранения длительности импульса (varHH, varLL), запрещаются прерывания по изменению уровня на RB4-RB7, устанавливается флаг получения длительности импульса flag,0. Таким образом, заканчивается цикл измерения расстояния УЗ модулем.

Далее настраивается счетчик времени для организации паузы после цикла измерения расстояния, в регистр счетчика времени shet записывается число 4, обнуляются регистры таймера TMR1, сбрасывается флаг прерывания по переполнению таймера, выполняется запуск таймера и выход из обработчика прерывания. По переполнению таймера происходит вход в обработчик прерываний и переход на метку prov_tmr1, где проверяется состояние бита разрешения прерываний по изменению уровня на RB4-RB7, и если он равен нулю выполняется декремент регистра shet. Если содержимое регистра shet не равно нулю происходит сброс флага прерываний по переполнению таймера TMR1и выход из обработчика прерываний. Когда значение регистра shet станет равным нулю, будет выполнена остановка таймера TMR1, обнуление его регистров, установка флага готовности измерения flag,1, сброс флага прерывания и выход из обработчика прерываний. Таким образом, продолжительность паузы составит (65536мкс) х 4=262,144 мс, паузу можно изменить, записав другое значение в регистр shet.

В основной программе при получении подтверждения об окончании процесса измерения (опрос флага flag,0) вызывается подпрограмма (vivod) расчета и вывода расстояния до объекта на цифровой индикатор. В подпрограмме vivod сбрасывается флаг flag,0 и вызывается подпрограмма деления (del) длительности импульса на число 58, после возврата в регистрах rezHH, rezLL, находится значение расстояния до объекта в сантиметрах. Если значение больше 400 см, на цифровой индикатор выводятся символы тире “- – -”, я применил данное ограничения опираясь на характеристики УЗ модуля.

При значениях расстояния менее 400 см, вызывается подпрограмма (bin2bcd) преобразования двоичного числа в двоично-десятичное, далее в подпрограмме send_rast десятичное значение расстояния выводится на цифровой индикатор. После вывода, происходит возврат из подпрограммы vivod и дальнейший опрос флагов flag,0 и flag,1. Если флаг готовности (flag,1) равен 1, происходит вызов подпрограммы start_pul, тем самым запускается новый цикл измерения расстояния.

В процессе измерения длительности импульса на линии echo (RB4), может возникнуть переполнение таймера TMR1, например, из-за большого расстояния до объекта или его отсутствии. Для этого случая в обработчике прерывания при переходе на метку prov_tmr1, проверяется состояние бита разрешения прерываний по изменению уровня на RB4-RB7, если значение бита равно 1, то длительность импульса превысила 65,536 мс. При этом в регистры таймера записывается число 39936 (соответствует расстоянию в 688 см) и выполняется переход на метку s_t1. Во время проверки значения расстояния в основной программе, из-за ограничения в 400 см, на индикаторе будут отображаться символы тире “- – -”.

Модуль довольно точно измеряет расстояния, по крайней мере, на коротких дистанциях, в характеристиках указано, что модуль измеряет расстояния до 4-х метров, но на самом деле больше, я получал показания вплоть до 5-ти метров.
Подключение модуля HC-SR04, макетная плата
На следующем видеоролике показан процесс измерения расстояния с применением УЗ модуля HC-SR04:

Прошивка МК и исходник

У этой записи 26 комментариев

  1. А от стекла отражается?

  2. Отлично)). Скажите пожалуйста, а какова получилась скорость работы? Если резко дернуть вперед, значение сразу изменится? Или, если бежать стометровку на него…?

    1. в коде приведенном в статье, измерения проводятся каждые 0,26 сек + время на измерение расстояния (максимум 0,065 сек), таким образом в секунду производится 3 измерения, что достаточно быстро, но можно сделать и быстрее

  3. А каким образом можно это сделать?

    1. уменьшить значение числа в регистре shet, в статье про это сказано.

  4. Да просто я на c++ пишу… не оч понимаю

  5. Здраствуйте. Извините, а в чем смысл команды: movf PORTB,W ;чтение регистра PORTB для устранения несоответствия

    1. Это нужно для последующего сброса флага прерывания (RBIF) по изменению уровня на линиях RB4-RB7, если этого не сделать флаг прерывания не получится сбросить.

  6. Великолепная работа! А если в воде? Откорректировать вычисления по скорости распространения… и загерметизировать датчик.

    1. Сомневаюсь что это возможно, мне кажется звук будет отражаться от герметизационного материала, да и мощность излучения нужно увеличивать, так как сопротивление среды (вода) больше и сигнал будет быстро затухать.

        1. Отлично) а визуализация имеется, в виде косяка рыб?

  7. Я купил на Али вот такой эхолот:
    https://ru.aliexpress.com/item/Russian-Menu-Language-LUCKY-Wireless-Sonar-Sensor-River-Lake-Sea-Bed-Live-Update-Contour-131ft-40M/1786095806.html?spm=2114.03020208.3.64.ByYCnH&ws_ab_test=searchweb0_0,searchweb201602_2_10093_10091_10090_10088_10089,searchweb201603_1&btsid=82d0ea03-9ae9-4b5b-8804-3514669d173d

    Он быстро перестал работать т. к. при забрасывании, от удара об воду, пропал контакт в плохой пайке. Мне пришлось вскрыть датчик. Там излучатель (пьезоэлемент) тупо залит эпоксидной смолой. То есть излучатель лежит на дне “кораблика” и налита “лужица” эпоксидки. Может быть в данном случае весь корпус “кораблика” является излучателем-приемником. Если дадите E-mail – пришлю фото внутренностей. И еще…. Думаю, что как раз в воде сигнал будет распространяться лучше. Мой эхолот в воздухе не показывает “глубину” вообще.
    Подумайте! Может это Ваша золотая жила? 🙂

  8. подключил по схеме на пустое пространство скачет 25-30 а начинает нормально работать с 20 см и меньше может что в программе кто с таким сталкивался

    1. Попробуйте другой датчик подключить, возможно ваш экземпляр выдает некорректные данные.

  9. А возможно сделать прерывания по int? Пытался переделать- не получилось

  10. А не подскажите, где надо внести изменения? Можете не писать сам код, интересует только что именно надо изменить. Периодически менял option_reg,intedg но все равно выводит —

  11. Всё работает. Спасибо огромное! Вы меня очень выручили. Я понял, где ошибся

  12. очень полезная разработка . Хотел установить данное устройство как уровнемер в летнем душе, по заполнению до определенного значения чтобы реле отключало насос подачи воды, ну и для разных емкостей нужно делать калибровку нуля .Может ли автор внести эти изменения в прошивку?

    1. Здравствуйте, то есть вам надо добавить кнопку для калибровки нижнего и верхнего уровня воды, и выход на реле для насоса?

  13. Поддерживаю доработку сия очень полезного девайса. В частности пусть это будет прописано в ячейке памяти, чтоб можно было менять при прошивке, расстояние при котором на одном свободном порту МК появлялась логическая единица. Т.е. при уменьшении расстояния до заданной величины осуществлялось управление нагрузкой.

  14. Ультразвуковой дальномер
    Исходные данные к работе
    • Напряжение питания – 9В.
    • Модуль измерения расстояния HC-SR04.
    • Результаты измерения отображать на семисегментных индикаторах
    • Диапазон измеряемых расстояний – от 2 до 400 см
    • Точность отображения – округление результата измерения до целого, в см
    • Предусмотреть кнопку сброса.
    • При проектировании принципиальной схемы предусмотреть разъем для программирования микроконтроллера.
    • Режим измерения – непрерывный.

    4 Содержание пояснительной записки
    Введение
    Выбор и обоснование структурной схемы
    Разработка принципиальной схемы
    Алгоритм программы
    Код программы
    Экспериментальные результаты
    Заключение
    кто сможет помочь?

Имя (обязательно)Email (обязательно)Веб-сайт

Добавить комментарий