HC-SR04 ultrasonic distance measurement module usage method and routine (STM32)

Realize ultrasonic distance measurement function based on STM32 and HC-SR04 module

Recently, I am learning STM32 to do a simple application practice, and I will write an article by the way.

The single-chip microcomputer used in this article is STM32F103C8T6, the ultrasonic ranging module is HC-SR04, and the 0.96-inch OLED screen module is used to display the ranging results.

Show results

There is a problem with the display results when it is less than 10cm in the image below, the code has been fixed and updated

Result after fix:

Video demo: https://www.bilibili.com/video/BV1Sg411Z7ex/

Realize ultrasonic distance measurement function based on STM32 and HC-SR04 module

HC-SR04 Hardware Overview

The core of the HC-SR04 ultrasonic distance sensor is two ultrasonic sensors . One acts as a transmitter, converting electrical signals into 40 KHz ultrasonic pulses. The receiver listens for the transmitted pulse. If it receives them, it produces an output pulse whose width can be used to determine how far the pulse traveled. It's that simple!

The sensor's small size makes it easy to use in any robotics project and provides excellent non-contact range detection between 2 cm and 400 cm (approximately 1 inch to 13 feet) with 3mm accuracy.

Operating VoltageOperating Voltage DC 5V
Operating Current 15mA
Operating FrequencyOperating Frequency 40K Hz
Max Range maximum range 4m
Min Range minimum range 2 cm
Ranging Accuracy 3 mm
Measuring AngleMeasuring Angle 15 degrees
Trigger Input Signal trigger input signal 10µS TTL pulse
Dimension 45 x 20 x 15mm

HC-SR04 Ultrasonic Sensor Pin

Let's take a look at its pinout.

VCC is the power supply of HC-SR04 ultrasonic distance sensor, we connected the 5V power supply.

The Trig (Trigger) pin is used to trigger the ultrasonic pulse, GPIOB5 is used in the following routine, so connect the GPIOB5 of STM32.

The Echo pin produces a pulse when a reflected signal is received. The length of the pulse is proportional to the time required to detect the transmitted signal. GPIOB6 is used in the following routine, so connect to GPIOB6 of STM32.

GND should be connected to the ground of the STM32.

How does HC-SR0 work?

It all starts when a pulse with a duration of at least 10 µS (10 microseconds) is applied to the trigger pin. In response, the sensor emits a sound pulse of eight pulses at 40 KHz. This 8-pulse pattern makes the "ultrasonic signature" of the device unique, allowing the receiver to distinguish the transmitted pattern from ambient ultrasonic noise.

Eight ultrasonic pulses travel through the air, away from the transmitter. At the same time, the echo pin goes high, and the beginning of the echo signal begins to form.

If these pulses are not reflected back, the echo signal will time out and return low after 38 milliseconds (38 milliseconds). A pulse of 38 ms therefore indicates no blockage within the range of the sensor.

If these pulses are reflected back, the Echo pin will go low when the signal is received. This produces a pulse whose width varies between 150 µS and 25 mS, depending on how long it takes to receive the signal.

The timing diagram of HC-SR04 is as follows:

The width of the received pulse is then used to calculate the distance to the reflecting object. This can be solved with the simple distance-velocity-time equation we learned in junior high.

distance = speed x time

wiring

Connect HC-SR04 and 0.96 inch OLED screen to STM32.

HC-SR04 STM32
VCC 5V
Trig GPIO PB5
Echo GPIO PB6
Gnd Gnd
OLED STM32
VCC 3.3V
GND GND
SCL GPIO PB12
SDA GPIO PB13

Effect of temperature on distance measurement

While the HC-SR04 is fairly accurate for most of our projects, such as intruder detection or proximity alarms; there may be times when you want to design a device to be used outdoors or in unusually hot or cold environments. In this case, you might want to take into account the fact that the speed of sound in air varies with temperature, air pressure and humidity.

Due to the speed at which sound factors into the HC-SR04's distance calculations, it may affect our readings. If the temperature (°C) and humidity are known, consider the following formula:

Sound velocity m/s = 331.4 + (0.606 * temperature) + (0.0124 * humidity)

purchase address

The purchase addresses of the modules used in this article are as follows:

STM32F103C8T6 development board: https://s.click.taobao.com/8SoQMVu
ST-LINK V2 emulator: https://s.click.taobao.com/FEuPMVu
HC-SR04 module: https://s.click. taobao.com/Ing88Vu
0.96-inch OLED module: https://s.click.taobao.com/o4fPMVu
breadboard: https://s.click.taobao.com/dBjPMVu
breadboard jumper: https://s .click.taobao.com/7eG88Vu

program

I used the ST standard library to write the program. The main program is released in the article. Please click the link below to download the complete project file.

Complete project file download: https://url.zeruns.tech/HCSR04

Extraction code: d9xr

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "HCSR04.h"

uint64_t numlen(uint64_t num)//计算数字的长度
{
    uint64_t len = 1;        // 初始长度为1
    for(; num > 9; ++len)    // 判断num是否大于9,否则长度+1
        num /= 10;	         // 使用除法进行运算,直到num小于1
    return len;              // 返回长度的值
}

int main(void)
{	
	OLED_Init();		//初始化OLED屏
	Timer_Init();		//初始化定时器
	HC_SR04_Init();		//初始化超声波测距模块
	
	OLED_ShowString(1, 1, "Distance:");		//OLED屏输出字符串
	
	while (1)
	{
		int Distance_mm=sonar_mm();			//获取距离测量结果,单位毫米(mm)		
		int Distance_m=Distance_mm/1000;	//转换为米(m)为单位,将整数部分放入Distance_m
		int Distance_m_p=Distance_mm%1000;	//转换为米(m)为单位,将小数部分放入Distance_m_p
		OLED_Clear_Part(2,1,16);			//将OLDE屏第2行清屏
		OLED_ShowNum(2, 1,Distance_m,numlen(Distance_m));	//显示测量结果的整数部分
		OLED_ShowChar(2, 1+numlen(Distance_m), '.');		//显示小数点
		if(Distance_m_p<100){								//判断是否小于100毫米
			OLED_ShowChar(2, 1+numlen(Distance_m)+1,'0');								//因为单位是米,所以小于10cm时要加0
			OLED_ShowNum(2, 1+numlen(Distance_m)+2,Distance_m_p,numlen(Distance_m_p));	//显示测量结果的小数部分
			OLED_ShowChar(2, 1+numlen(Distance_m)+2+numlen(Distance_m_p), 'm');			//显示单位
		}else																			// https://blog.zeruns.tech
		{
			OLED_ShowNum(2, 1+numlen(Distance_m)+1,Distance_m_p,numlen(Distance_m_p));	//显示测量结果的小数部分
			OLED_ShowChar(2, 1+numlen(Distance_m)+1+numlen(Distance_m_p), 'm');			//显示单位
		}
		OLED_Clear_Part(3,1,16);			//将OLDE屏第3行清屏
		OLED_ShowNum(3, 1,Distance_mm,numlen(Distance_mm));		//显示单位为毫米的距离结果
		OLED_ShowString(3, 1 + numlen(Distance_mm), "mm");
		Delay_ms(300);						//延时300毫秒
		
	}
}

Timer.c

#include "stm32f10x.h"                  // Device header
//blog.zeruns.tech
void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);		//启用TIM3时钟

	TIM_InternalClockConfig(TIM3);								//设置TIM3使用内部时钟
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;			//定义结构体,配置定时器
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;	//设置1分频(不分频)
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//设置计数模式为向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;			//设置最大计数值,达到最大值触发更新事件,因为从0开始计数,所以计数10次是10-1,每10微秒触发一次
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;			//设置时钟预分频,72-1就是每 时钟频率(72Mhz)/72=1000000 个时钟周期计数器加1,每1微秒+1
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;		//重复计数器(高级定时器才有,所以设置0)
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);			//初始化TIM3定时器
	
	TIM_ClearFlag(TIM3, TIM_FLAG_Update);			//清除更新中断标志位
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);		//开启更新中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//设置中断优先级分组
	
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体,配置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;				//指定中断通道
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//中断使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//设置抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//设置响应优先级
	NVIC_Init(&NVIC_InitStructure);								// https://blog.zeruns.tech
	
	TIM_Cmd(TIM3, ENABLE);							//开启定时器
}

/*
void TIM3_IRQHandler(void)			//更新中断函数
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)		//获取TIM3定时器的更新中断标志位
	{
		
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);			//清除更新中断标志位
	}
}*/

Timer.h

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

HCSR04.c

#include "stm32f10x.h"
#include "Delay.h"

/*
我的博客:blog.zeruns.tech
具体使用说明请到我博客看
*/


#define Echo GPIO_Pin_6		//HC-SR04模块的Echo脚接GPIOB6
#define Trig GPIO_Pin_5		//HC-SR04模块的Trig脚接GPIOB5

uint64_t time=0;			//声明变量,用来计时
uint64_t time_end=0;		//声明变量,存储回波信号时间

void HC_SR04_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	//启用GPIOB的外设时钟	
	GPIO_InitTypeDef GPIO_InitStructure;					//定义结构体
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//设置GPIO口为推挽输出
	GPIO_InitStructure.GPIO_Pin = Trig;						//设置GPIO口5
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//设置GPIO口速度50Mhz
	GPIO_Init(GPIOB,&GPIO_InitStructure);					//初始化GPIOB
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;			//设置GPIO口为下拉输入模式
	GPIO_InitStructure.GPIO_Pin = Echo;						//设置GPIO口6
	GPIO_Init(GPIOB,&GPIO_InitStructure);					//初始化GPIOB
	GPIO_WriteBit(GPIOB,GPIO_Pin_5,0);						//输出低电平
	Delay_us(15);											//延时15微秒
}

int16_t sonar_mm(void)									//测距并返回单位为毫米的距离结果
{
	uint32_t Distance,Distance_mm = 0;
	GPIO_WriteBit(GPIOB,Trig,1);						//输出高电平
	Delay_us(15);										//延时15微秒
	GPIO_WriteBit(GPIOB,Trig,0);						//输出低电平
	while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);		//等待低电平结束
	time=0;												//计时清零
	while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);		//等待高电平结束
	time_end=time;										//记录结束时的时间
	if(time_end/100<38)									//判断是否小于38毫秒,大于38毫秒的就是超时,直接调到下面返回0
	{
		Distance=(time_end*346)/2;						//计算距离,25°C空气中的音速为346m/s
		Distance_mm=Distance/100;						//因为上面的time_end的单位是10微秒,所以要得出单位为毫米的距离结果,还得除以100
	}
	return Distance_mm;									//返回测距结果
}

float sonar(void)										//测距并返回单位为米的距离结果
{
	uint32_t Distance,Distance_mm = 0;
	float Distance_m=0;
	GPIO_WriteBit(GPIOB,Trig,1);					//输出高电平
	Delay_us(15);
	GPIO_WriteBit(GPIOB,Trig,0);					//输出低电平
	while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);
	time=0;
	while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);
	time_end=time;
	if(time_end/100<38)
	{
		Distance=(time_end*346)/2;
		Distance_mm=Distance/100;
		Distance_m=Distance_mm/1000;
	}
	return Distance_m;
}

void TIM3_IRQHandler(void)			//更新中断函数,用来计时,每10微秒变量time加1
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)		//获取TIM3定时器的更新中断标志位
	{
		time++;
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);			//清除更新中断标志位
	}
}

HCSR04.h

#ifndef __HCSR04_H
#define __HCSR04_H

void HC_SR04_Init(void);
int16_t sonar_mm(void);
float sonar(void);

#endif

recommended reading

Guess you like

Origin blog.csdn.net/u012513463/article/details/126045385