Ультразвуковые дальнометры HC-SR04 черезвычайно популярны в любительской робототехнике из-за своей дешевизны и простоты. Я тоже не остался в стороне, когда баловался с Arduino, теперь же хочу разобрать работу с сенсором на "низком уровне" и напсать пример работы на чистом Си.
Есть один принципальный момент. Часто работу с сенсором HC-SR04 реализуют через внешние прерывания. Но. В ATmega8 их всего два, и если сенсор будет работать на колесном шасси, то внешние прерывания будут заняты колесными энкодерами. Однако, как я говорил в посте про прерывание захвата, оно работает аналогично внешнему, т.е. есть смысл попытаться его задействовать.
Заглянем в datasheet HC-SR04 и посмотрим на протокол работы сенсора:
Здесь видно две линии: управляющую Trig, и Echo работающую на приём.
т.о. измерив длительность Echo сигнала, получим растояние до препятствия.
В качестве шаблона я использовал программу из поста про прерывание по захвату. Получился такой текст:
#include <util/delay.h> #include <uart.h> #include <avr/io.h> #include <avr/interrupt.h> #define LED PB5 #define TRIG PB1 static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); volatile uint16_t impulse; ISR(TIMER1_CAPT_vect) { TCNT1H=0;TCNT1L=0; uint16_t tmp; impulse=(uint16_t)ICR1L; tmp=(uint16_t)ICR1H; impulse |=(tmp << 8); impulse /= 118; } int main(void) { //---- init init_uart(); DDRB |= (1<<LED); // led indicator // init 16-bit timer in capture mode TIMSK =(1<<TICIE1);//enable capture TCCR1B=(1<<CS11); // prescaler 1/8 //--- counter clear TCNT1H=0; TCNT1L=0; impulse=1; // --- enable Trig DDRB |= (1<<TRIG); //---- ready indication blink13(3); stdout = &mystdout; printf("Ok, I'm ready!\n"); sei(); //---- main body for (;;) { _delay_ms(200); if (impulse!=0) { cli(); printf("impulse: %u cm\n", impulse); // clearing counters TCNT1H=0; TCNT1L=0; impulse=0; /// start impulse to TRIG PORTB |= (1<<TRIG); _delay_us(10); PORTB &= ~(1<<TRIG); sei(); } else printf("none values.\n"); }; return 0; }
По сравнению с оригинальной программой, здесь было убрано прерывание по переполнению счетчика, которое мигало светодиодом. И сброшен бит ICES1, т.е. срабатывание прерывания по захвату идет по низкому уровню, а не по смене фронта. Результат работы программы:
Схема подключения:
Скачать архив с исходниками можно здесь: скачать