Meranie vzdialenosti ultrazvukovým snímačom HC-SR04
Zo stránky SensorWiki
Záverečný projekt predmetu MIPS / LS2024 - Jozef Csabi
Zadanie
Pripojenie senzora vzdialenosti HC-SR04 k vývojovej doske Arduino NANO. Našim cieľom je pripojiť senzor a odmerať vzdialenosť od prekážky.
HC-SR04
Je to ultrazvukový senzor pre meranie vzdialenosti. funguje tak, že vysiela krátky ultrazvukový impulz, potom detekuje jeho odrazený signál. Zmeriame, koľko toto trvá a vieme vypočítať vzdialenosť. Senzor spotrebúva 8 mA, jeho minimálna vzdialenosť je 1 cm a maximálna 300 cm. Frekvencia ultrazvuku je 40 kHz. Trigger puls má 10 ms a uhol detekcie je 15°.
Literatúra:
Analýza a opis riešenia
Najprv sme si pridali do nášho programu knižnice uart.h, uart.c, ktoré sme si vytvorili na cvičení, aby sme mohli vypisovať vzdialenosť cez Putty. Inicializovali sme UART, vytvorili volatile premennú, do ktorej sme zapisovali vzdialenosť, ktorú sme následne vydelili 41, aby nám vyšla v cm. Následne sme si inicializovali trigger_pulse, aby vyslal signál a mohli sme začať merať. Potom sme čakali, kým bude Echo pin na vysokej úrovni, zmerali sme dĺžku signálu a vypočítali vzdialenosť v cm. Nakoniec sme dĺžku len vypísali cez Putty-ho, počkali chvíľu a merali sme znova.
Zapojenie
Zapojenie sme realizovali pripojením Trigger pinu na D9, Echo pinu na D10 a následne pripojením Gnd na zem a Vcc na 5V. Potom sme zapojili aj ARDUINO na zem.
Algoritmus a program
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "uart.h"
volatile uint16_t distance = 0; //tu budeme ukladat vzdialenost, ako cele cislo o velkosti 16 bitov
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
void UART_Transmit(unsigned char data) {
while (!(UCSR0A & (1<<UDRE0))); // Caka na prazdny buffer
UDR0 = data;
}
void trigger_pulse() {
PORTB |= (1 << PB1); // Nastavi Trig pin na vysoku uroven
_delay_us(10); // Caka 10 mikrosekund
PORTB &= ~(1 << PB1); // Nastavi Trig pin na nizku uroven
}
uint16_t measure_pulse_width() {
uint16_t pulse_width = 0;
uint16_t timeout = 50000; // Aby sme nesli donekonecna
// Caka na Echo pin, kym bude na vysokej urovni
while (!(PINB & (1 << PB2)) && timeout--) {
_delay_us(1);
}
// Mera dlzku signalu
while ((PINB & (1 << PB2)) && timeout--) {
_delay_us(1);
pulse_width++;
}
// Vypocitame vzdialenost v cm
uint16_t distance = pulse_width / 41;
return distance;
}
int main(void) {
DDRB |= (1 << PB1); // Nastavi Trig pin ako vystup
DDRB &= ~(1 << PB2); // Nastavi Echo pin ako vstup
PORTB |= (1 << PB2); // Ovladanie pull-up rezistoru
hw_init();
uart_init();
stdout= &mystdout;
while (1) {
trigger_pulse(); // Posle signal na senzor
uint16_t distance = measure_pulse_width(); // Merame vzdialenost a vypocitame ju v cm
printf("Vzdialenost: %d cm\n", distance); // Vypiseme vzdialenost cez napr. Putty
_delay_ms(500); // Pockame pred dalsim meranim
}
return 0;
}
/* ************************************************************************* */
/* FileName: uart.h */
/* ************************************************************************* */
#define LED PB5 // internal on-board LED
/* na testovanie su uz zadefinovane */
// bit_is_set(PINB, SW1)
// bit_is_clear(PINB, SW1)
/* na cakanie su preddefinovane slucky */
// loop_until_bit_is_set(PINB, SW1); // cakanie na uvolnenie tlacitka
// loop_until_bit_is_clear(PINB, SW1); // cakanie na stlacenie tlacitka
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#ifndef UART_H_
#define UART_H_
#include <stdio.h>
#define BAUD_PRESCALE (((F_CPU / (BAUDRATE * 16UL))) - 1) // vzor?ek z datasheetu
void hw_init( void );
void uart_init( void );
/* Following definition is compatible with STDIO.H, for more
* information see https://www.appelsiini.net/2011/simple-usart-with-avr-libc/
*/
int uart_putc( char c, FILE *stream );
void uart_puts( const char *s );
char uart_getc( void );
void delay(int delay);
#endif /* UART_H_ */
/* ************************************************************************* */
/* FileName: uart.c */
/* ************************************************************************* */
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
void hw_init( void )
{
DDRB |= (1<<LED); // PORTB.5 kde je LED ma byt OUTPUT
/* sem si mozete dopisat svoje vlastne inicializacne prikazy */
}
void uart_init( void )
{
// for different BAUD rate change the project settings, or uncomment
// following two lines:
// #undef BAUD // avoid compiler warning
// #define BAUD 115200
#include <util/setbaud.h> // requires defined BAUD
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X // defined in setbaud.h
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
}
int uart_putc( char c, FILE *stream )
{
if (c == '\n')
uart_putc('\r',stream);
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
UDR0 = c;
return 0;
}
void uart_puts(const char *s)
{
/* toto je vasa uloha */
}
char uart_getc(void)
{
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
return UDR0;
}
void delay(int delay) // vlastna funkcia pre dlhsie casy
{
for (int i=1; i<=delay; i++)
_delay_ms(1);
}
Zdrojový kód: zdrojaky.zip
Overenie
Výsledok merania
Reálna vzdialenosť a odmeraná sa zhodujú v menších vzdialenostiach, ale čím väčšia vzdialenosť, tým bola aj väčšia odchýlka. Toto spôsobuje číslo, ktorým delíme. V mojom prípade 41, kedy mi vychádzajú rovnako menšie vzdialenosti. Používateľ si musí zvoliť, aké dĺžky chce merať a podľa toho nastaviť dané číslo.
Video: