Как подключить ультразвуковой датчик измерения расстояния 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

