【STM32F1基础例程13】HC-SR04超声波传感器测距实验
实验简介
这个实验呢算是这几个实验中稍微稍微“复杂”一点的(当然,对于看到这篇文章的大家来说肯定是超级无敌简单了),关于HC-SR04传感器呢,其实网上有很多很多的资料,但是还是给大家叨叨一些吧稍微。
HC-SR04是一款广泛使用的超声波测距传感器模块,它能够提供2cm至400cm的非接触式距离测量功能,测量精度可达到3mm 1。该模块包括一个超声波发射器和一个接收器,它们通过超声波信号实现距离测量。当发射器发出超声波信号后,信号会被目标物体反射回来,并由接收器接收。根据超声波从发射到接收的时间差,可以计算出物体与传感器之间的距离 2。
HC-SR04模块的工作原理基于发送和接收超声波脉冲。模块通过IO口TRIG触发测距,给至少10us的高电平信号后,自动发送8个40kHz的方波并检测是否有信号返回。若有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间即为超声波从发射到返回的时间。根据公式:测试距离 = (高电平时间 × 声速(340m/s)) / 2,可以计算出距离 1。
模块的电气参数包括工作电压5V、工作电流15mA、工作频率40Hz 5。在使用时,需要注意模块不宜带电连接,测距时被测物体的面积不少于0.5平方米且平面尽量要求平整,以确保测量结果的准确性 2。
HC-SR04的应用领域包括机器人避障、物体测距、液位检测、公共安防和停车场检测等 13。它的接口包括TRIG触发脉冲输入和ECHO脉冲宽度输出,且支持5V和3.3V功率接口,易于微控制器或Arduino控制 8。
在实际应用中,可以通过编写程序来控制Trig引脚发送触发信号,并读取Echo引脚的回波时间,从而实现距离测量。例如,在使用Arduino Uno板进行测距时,可以通过定义Trig和Echo引脚,发送一个高电平信号触发测距,并通过pulseIn函数读取Echo引脚的高电平时间,再根据公式计算出距离 8。
此外,HC-SR04虽然性能稳定且易于使用,但也存在一些局限性,比如声波速度受温度影响、对反射面积和材料有要求、可能受到其他超声波传感器的干扰以及存在2cm的最小测量距离限制 8。尽管如此,HC-SR04因其性价比较高、使用方便,仍然是许多项目中首选的超声波传感器模块。
主要代码
main.c
#include "delay.h"
#include "sys.h"
#include "oled.h"
uint32_t Distance_Calculate(uint32_t count)//传入时间单位10us
{
uint32_t Distance = 0;
Distance = (uint32_t)(((float)count *17)/100);//距离单位cm,声速340M/S,时间*速度/2=距离
return Distance;
}
//1us等待
void Delay_us(uint32_t nus)
{
uint32_t tickStart, tickCur, tickCnt;
uint32_t tickMax = SysTick->LOAD;
uint32_t udelay_value = (SysTick->LOAD/1000)*nus;
tickStart = SysTick->VAL;
while(1)
{
tickCur = SysTick->VAL;
tickCnt = (tickStart < tickCur) ? (tickMax+tickStart-tickCur) : (tickStart-tickCur);
if (tickCnt > udelay_value)
break;
}
}
uint32_t Distance;//距离
uint32_t HalTime1,HalTime2;//时间临时变量
extern volatile uint32_t TimeCounter;//时间计数,单位10us
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void RCC_Configuration(void)
{
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
void TIM2_Config_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* ---------------------------------------------------------------
72M主频,72分频就是1us,计数到10就是10us中断一次
--------------------------------------------------------------- */
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 9;//计数到10,产生中断一次
TIM_TimeBaseStructure.TIM_Prescaler = 71;//72分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM IT enable */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
//PA0配置成输出,PA1配置成输入
void GPIO_Config_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PA0端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
}
//主函数,采用外部8M晶振,72M系统主频,可以在void SetSysClock(void)函数中选择主频率设置
int main(void)
{
delay_init(); //延时函数初始化,通过Systick中断实现1ms延时功能
GPIO_Config_Init();//PA0配置成输出,PA1配置成下拉输入
RCC_Configuration();//定时器2时钟使能
TIM2_Config_Init();//定时器2配置,10us中断一次进入TIM2_IRQHandler
NVIC_Configuration();//中断使能
OLED_Init(); //初始化OLED
OLED_Clear(); //清屏
while(1)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_0);//预先拉低Trig引脚
delay_ms(5);
GPIO_SetBits(GPIOA, GPIO_Pin_0);//拉高Trig引脚
delay_ms(20);
GPIO_ResetBits(GPIOA, GPIO_Pin_0);//拉低Trig引脚
Delay_us(20);//等待20us
while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 0);//如果是低电平,一直等
HalTime1= TimeCounter;
while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 1);//如果是高电平,一直等
if(TimeCounter>HalTime1)
{
HalTime2 = TimeCounter-HalTime1;
if(HalTime2<0x300)
{
Distance = Distance_Calculate(HalTime2);//计算距离
}
}
OLED_Clear();
OLED_ShowCHinese(18,0,0);//光
OLED_ShowCHinese(36,0,1);//子
OLED_ShowCHinese(54,0,2);//物
OLED_ShowCHinese(72,0,3);//联
OLED_ShowCHinese(90,0,4);//网
OLED_ShowString(24,3,"SR04 TEST");
OLED_ShowString(0,6,"Dis: ");
OLED_ShowNum(30,6,Distance,3,16);//显示距离值,单位cm
OLED_ShowString(60,6,"cm");
delay_ms(1000);
}
}
这段主程序的代码用于初始化并使用HC-SR04超声波传感器模块来测量距离。
-
头文件包含:
"delay.h":可能包含延时相关的函数声明。"sys.h":可能包含系统初始化和配置相关的函数。"oled.h":包含OLED显示屏接口的函数。
-
距离计算函数:
Distance_Calculate:根据传入的时间(单位为10us),计算并返回距离(单位为厘米)。
-
微秒级延时函数:
Delay_us:实现微秒级延时功能,使用SysTick定时器来实现。
-
全局变量:
Distance:存储计算出的距离。HalTime1,HalTime2:存储时间的临时变量。TimeCounter(外部定义):存储时间计数,单位为10us。
-
中断和时钟配置函数:
NVIC_Configuration:配置NVIC(嵌套向量中断控制器),使能TIM2中断。RCC_Configuration:使能TIM2定时器的时钟。TIM2_Config_Init:初始化TIM2定时器,设置为每10us产生一次中断。
-
GPIO配置函数:
GPIO_Config_Init:配置GPIO端口,将PA0设置为输出,PA1设置为输入。
-
主函数
main:- 进行延时、GPIO、定时器和中断的初始化。
- 进入一个无限循环,周期性地触发HC-SR04传感器进行测量:
- 将PA0置为低电平,然后置为高电平20ms,再拉低,触发HC-SR04发送超声波。
- 等待PA1变为高电平,使用
TimeCounter记录开始时间HalTime1。 - 再次等待PA1变为低电平,计算两次的时间差
HalTime2。 - 如果
HalTime2小于0x300(即距离不是很近),调用Distance_Calculate计算距离。
- 清除OLED屏幕,并显示固定文本和测量的距离值。
- 每次测量后延时1秒再次测量。
代码中使用了一些外设和中断,以及对GPIO的操作来控制HC-SR04模块发送和接收超声波。通过定时器中断来精确测量超声波的往返时间,并据此计算距离。OLED显示屏用于实时显示测量结果。这个程序就是一个典型的嵌入式系统应用,涉及到硬件控制和用户界面的基本操作。
我收集到的比较完整的代码大家也可以直接下载去试试!!!
更多推荐

所有评论(0)