AVR: подключаем ультразвуковой дальномер HC-SR04 к atmega8

HC-SR04

Характеристики ультразвукового дальномера 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 &lt;util/delay.h&gt;
#include &lt;avr/interrupt.h&gt;
#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 &amp; 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 &amp;= ~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 =  &amp;uart_stream;
 
  sei();
 
  while( 1 ) {
    //измерение
    sm = hc_sr04_meas();
    printf( "sm = %u\r\n", sm );
    //задержка 1 сек
    _delay_ms( 1000 );
  }
  return 0;
}
Запись опубликована в рубрике Микроконтроллеры avr с метками , . Добавьте в закладки постоянную ссылку.

15 комментариев: AVR: подключаем ультразвуковой дальномер HC-SR04 к atmega8

  1. Константин говорит:

    Хочу немного добавить, что вход Trig срабатывает даже от импульса в 300нс, импульс на Echo появляется примерно через 500мкс и его длительность не превышает 4мс, если удалось измерить расстояние. Ну и потребление во время импульса не должно превышать 20мА. Я может быть когда-нибудь напишу про этот девайс более подробно в своем блоге.

  2. Артём Двинин говорит:

    Спасибо за дополнительную инфу :)

  3. Роман говорит:

    Google выдает 96 рублей стоимость. с учетом того что самый плохой/дешевый парктроник стоит — 30$, проще весь бампер обложить такими датчиками. +доллоровый MAXII и светодиодные столбики на каждый датчик.

  4. Артём Двинин говорит:

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

  5. Руслан говорит:

    Есть датчики для парктроников же я покупал за 150р год назад, лежит всё не до него…Так он защищён более-менее.
    У меня просто была задумка проверить как он под водой работает и сделать ходовой эхолот но тут за много цепляется проблем- дифферент, качка и т.д. Гироскоп надо)

  6. Артём Двинин говорит:

    Интересная идея, а не подскажите что у Вас за датчики?

  7. Рома говорит:

    Добрый день Артем!! =) Мне понравилась Ваша статья…

    У Вас, в документе «ext_int.h» ,там где приведены 3 функции по прерываниям.
    Я бы хотел спросить как работает 1-вая и 3-тья функция. Могли бы Вы сделать небольшие комментарии здесь или рассказать как работает компилятор, просто на си не особо силен, изучаю пока =)))
    Хочу понять всю Вашу программу. Заранее благодарен!)

  8. Артём Двинин говорит:

    Добрый день!
    дописал комментарии, если есть еще вопросы — пишите, попробую ответить =)

    ================================================
    //функция настраивает по какому событию будет происходить прерывание 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(); //то по этому указателю вызываем функцию
    }
    }

  9. Лизоркин Виктор Васильевич говорит:

    Работа с датчиком расстояния HC-SR04 в ассемблере

  10. Артём Двинин говорит:

    ???

  11. Станислав говорит:

    День добрый! Я новичок в С, хочу поинтересоваться, зачем вызывать функцию через указатель, вместо того, что бы просто указать имя функции?

  12. Артём Двинин говорит:

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

  13. Сергей говорит:

    Выходит, что в даташите врут. 4мс приблизительно 70см

  14. Артём говорит:

    Думаю, Константин, ошибся. Этим дальномером получалось измерять расстояние более 2м, при этом длительность импульса была более 10 мс.

  15. goga770 говорит:

    Большое спасибо за пример, запустил, все работает, НО!
    При ошибке получения отклика на сонаре микроконтроллер зависает, это скорее всего вызвано строкой

    while( hc_sr04_status != HC_SR04_END )
    ,

    то есть если по каким-то причинам не пришел сигнал окончания измерения (например, слишком большой угол поверхности отражения) программа «зацикливается». Как самый простой вариант решения данной проблемы:
    //while( hc_sr04_status != HC_SR04_END );
    _delay_ms( 50 );

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

Ваш e-mail не будет опубликован.

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>