Как подключить ультразвуковой датчик измерения расстояния HC-SR04 к ATmega16 и передать данные через USART/UART на компьютер
Очень часто нам нужно подключить датчик измерения расстояния HC-SR04 к ATmega16, Arduino или другому микроконтроллеру и отображать данные на экран или передать через USART/UART на наш компьютер.
В данной статье мы решим эти проблемы, а именно:
- подключим HC-SR04 к ATmega16;
- подключим радио модуль TB387 к ATmega16 или напрямую, или другой имеющийся радио модуль как HC-11/12 или FS1000A/XD-FST;
- напишем прошивку для ATmega16;
- проверим работоспособность.
Схема подключения модуля TB387 и датчика движения HC-SR04 к ATmega16
Пример программы в Atmel Studio 7
uart.h
#ifndef UART_H_ #define UART_H_ void USARTInit(unsigned int); void USARTTransmitChar(char); void USARTTransmitString(char*); void USARTTransmitStringLn(char*); char USARTReceiveChar(void); #endif /* UART_H_ */
uart.c
#include <avr/io.h> #include "uart.h" void USARTInit(unsigned int ubrr) { // нормальный асинхронный двунаправленный режим работы // UBRR = f / (16 * band) // Установка скорости UBRRH = (unsigned char)(ubrr>>8); UBRRL = (unsigned char)(ubrr); // RXC - завершение приёма // |TXC - завершение передачи // ||UDRE - отсутствие данных для отправки // |||FE - ошибка кадра // ||||DOR - ошибка переполнение буфера // |||||PE - ошибка чётности // ||||||U2X - Двойная скорость // |||||||MPCM - Многопроцессорный режим // |||||||| // 76543210 UCSRA = 0; // RXCIE - прерывание при приёме данных // |TXCIE - прерывание при завершение передачи // ||UDRIE - прерывание отсутствие данных для отправки // |||RXEN - разрешение приёма // ||||TXEN - разрешение передачи // |||||UCSZ2 - UCSZ0:2 размер кадра данных // ||||||RXB8 - 9 бит принятых данных // |||||||TXB8 - 9 бит переданных данных // |||||||| // 76543210 // разрешен приём и передача данных по UART UCSRB = 1<<RXEN | 1<<TXEN; // URSEL - всегда 1 // |UMSEL - режим: 1-синхронный 0-асинхронный // ||UPM1 - UPM0: 1 чётность // |||UPM0 - UPM0: 1 чётность // ||||USBS - стоп биты: 0-1, 1-2 // |||||UCSZ1 - UCSZ0: 2 размер кадра данных // ||||||UCSZ0 - UCSZ0: 2 размер кадра данных // |||||||UCPOL - в синхронном режиме - тактирование // |||||||| // 76543210 // 8-битовая посылка, 2 стоп бита UCSRC = 1<<URSEL | 1<<USBS | 1<<UCSZ0 | 1<<UCSZ1; } // Отправка байта void USARTTransmitChar(char c) { // Устанавливается, когда регистр свободен while(!( UCSRA & (1<<UDRE))); UDR = c; } // Отправка строки void USARTTransmitString(char str[]) { register char i = 0; while(str[i]) { USARTTransmitChar(str[i++]); } } // Отправка строки void USARTTransmitStringLn(char str[]) { USARTTransmitString(str); USARTTransmitChar((char)13); USARTTransmitChar((char)10); } // Получение байта char USARTReceiveChar(void) { // Устанавливается, когда регистр свободен while(!(UCSRA & (1<<RXC))); return UDR; }
hcsr04.h
#ifndef HCSR04_H_ #define HCSR04_H_ void initHCSR04(); void stopHCSR04(); void trigHCSR04(); void waitHCSR04(); uint32_t getDistance(); #endif /* HCSR04_H_ */
hcsr04.c
// HC-SR04 к ATmega16 #define F_CPU 11059200UL // Clock Speed #define TRIG_DDR DDRD #define TRIG_PORT PORTD #define TRIG_PIN PIND3 #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdbool.h> #include "hcsr04.h" uint16_t rising, falling; uint32_t counts; uint32_t dist; bool star = false; // Режим захвата ISR(TIMER1_CAPT_vect) { // ICES1 = 1 // фронт - положительный срез if (TCCR1B & (1<<ICES1)) { // Сохраняем текущее значение счетчика rising = ICR1; // В следующий раз обнаружить спад (отрицательный срез) TCCR1B &= ~(1<<ICES1); // Просто код ошибки, что измерение не произошло dist = -2; } // ICES1 = 0 // спад - отрицательный срез else { // Сохраняем текущее значение счетчика falling = ICR1; // считаем число тактов counts = falling - rising; // определяем растояние в миллиметрах dist = (counts * 100) / 813; // уведомляем функцию waitHCSR04() что можно отправить // результат заказчику т.е. растояние определено star = false; } } // обработчик прерывания по совпадению значения таймера со значением регистра OCR1A // OCR1A = 0xFFFF ISR(TIMER1_COMPA_vect) { // уведомляем функцию waitHCSR04() что можно отправить // результат заказчику т.е. растояние не определено // HC-SR04 не получил обратный сигнал т.е. растояние // слишком большая, сенсор не подключён или сигнал слишком слабый dist = -1; star = false; } // инициализация HCSR04 void initHCSR04() { // инициализация ножки TRIG как выход TRIG_DDR |= 1<<TRIG_PIN; rising = falling = counts = dist = 0; // инициализация таймера 1 TIMER1 // CS12,CS11,CS10: Clock Select. Эти 3 бита задают источник тактового сигнала для счетчика. // 0 1 0 : F_CPU/8 (с выхода делителя) // ICNC1: Установка этого бита в лог. 1 активирует входной подавитель шума // WGM13,WGM12,WGM11,WGM10: // 0 1 0 0 : режим CTC, максимальное значение OCR1A = 0xFFFF TCCR1B |= (1<<ICNC1) | (1<<CS11) | (1<<WGM12); // TICIE1 = 1: разрешено прерывание захвата таймера/счетчика 1 // OCIE1A = 1: разрешено прерывание по совпадению регистра A с состоянием таймера/счетчика1 TIMSK |= (1<<TICIE1) | (1<<OCIE1A); // ICES1 = 1: захват входа ICR1 по нарастающему фронту (положительный срез). TCCR1B |= (1<<ICES1); // максимальное значение счетчика OCR1A = 0xFFFF; // активируем прерывания sei(); } // отключаем режим захвата void stopHCSR04() { TRIG_DDR &= ~(1<<TRIG_PIN); // TIMER1 INIT TCCR1B &= ((1<<ICNC1) | (1<<CS11) | (1<<WGM12)); TIMSK &= ((1<<TICIE1) | (1<<OCIE1A)); TCCR1B &= ((1<<ICES1)); OCR1A = 0; } // Генерируем импульс на 12us void trigHCSR04() { TRIG_PORT ^= (1<<TRIG_PIN); _delay_us(12); TRIG_PORT ^= (1<<TRIG_PIN); } // ждём пока star равно true т.е. завершение измерения void waitHCSR04() { star = true; while(star) { _delay_us(1); } } uint32_t getDistance() { // Инициализируем таймер (HCSR04) initHCSR04(); // Генерируем импульс на 12us trigHCSR04(); // Ждем, пока растояние не определено waitHCSR04(); // Останавливаем таймер stopHCSR04(); // Возвращяем результат return dist; }
main.c
#define F_CPU 11059200UL // Clock Speed #define BAUD 9600 #define MYUBRR F_CPU/16/BAUD-1 #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdio.h> #include "uart.h" #include "hcsr04.h" int main(void) { uint32_t d; char str[20]; USARTInit(MYUBRR); while (1) { d = getDistance(); sprintf(str, "Distance: %dmm", d); USARTTransmitStringLn(str); _delay_ms(1000); } }
Результат
Скачать
Terminal 1.9b — работаем с COM-портом
datasheet ATMEGA16.pdf
Проект в Atmel Studio 7 HC-SR04+UART+ATmega16
The accuracy and repeatability that Mantle 3D offers, combined with cost reductions,
could make high-quality tooling accessible to more companies.
The effectiveness of Mantle 3D in cutting down on lead times from prototype to production could help manufacturers adapt more quickly to market
demands.
The capability to manufacture intricate tooling designs with Mantle’s 3D technology could result in higher-performing products, as the tools themselves are enhanced for their specific applications.