STM32F103系列单片机HAL库的超声波模块测试程序
原理:
声波遇到障碍物会反射,而声波的速度已知,所以只需要知道发射到接收的时间差,就能轻松计算出测量距离,再结合发射器和接收器的距离,就能算出障碍物的实际距离。
超声波原理图
以HC-SR04硬件为例,端口为VCC、Trig、Echo、GND。
- VCC–接STM32板子+5V;
- GND–接STM32板子GND;
- Trig–为触发控制信号输入,触发测距,给至少10us的高电平信号,模块自动发射8个40KHz的方波,自动检测是否有信号返回;
- Echo–回响信号输出,有信号返回,通过IO口ECHO输出一个高电平,高电平持续时间就是超声波从发射到返回的时间。
那用STM32怎么给端口信号呢?又是怎么获取信号呢?
Trig端口为超声波模块的输入信号,也就是通过STM23一个端口推挽输出一个至少10us的高电平信号即可,利用delay_ms(20)实现;
Echo端口为超声波模块的输出信号,也就是利用STM32端口捕获高电平时间,那么这个端口肯定是可以用做定时器的端口。
通过以上分析,这里采用以下STM32端口
超声波模块硬件连接图
定时器捕获原理:arr为自动重装载值,psc为时钟预分频数
当捕获不满一个时长的原理图
当捕获超过一个时长的原理图
部分程序
Trig程序
void Trig_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure. Pin=GPIO_PIN_0;//PA8
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLDOWN; //下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
void CHL_capture(void)
{
TRIG1=1;
delay_us(20);
TRIG1=0;
}
Echo程序
#include "us015timer.h"
#include "led.h"
// PA1---Echo TIM2 CH2
//TIM2 捕获初始化
TIM_HandleTypeDef TIMx_Handler; //定时器3句柄
//定时器2通道1输入捕获配置
//arr:自动重装值(TIM2是16位的!!)
//psc:时钟预分频数
void TIM2_CHx_Cap_Init(u32 arr,u16 psc)
{
TIM_IC_InitTypeDef TIMx_CHyConfig;
TIMx_Handler.Instance=TIM2; //通用定时器2
TIMx_Handler.Init.Prescaler=psc; //分频系数
TIMx_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器
TIMx_Handler.Init.Period=arr; //自动装载值
TIMx_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子
TIMx_Handler.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;//使能自动重载
HAL_TIM_IC_Init(&TIMx_Handler); //初始化输入捕获时基参数
TIMx_CHyConfig.ICPolarity=TIM_ICPOLARITY_RISING; //上升沿捕获
TIMx_CHyConfig.ICSelection=TIM_ICSELECTION_DIRECTTI;//映射到TI1上
TIMx_CHyConfig.ICPrescaler=TIM_ICPSC_DIV1; //配置输入分频,不分频
TIMx_CHyConfig.ICFilter=0; //配置输入滤波器,不滤波
HAL_TIM_IC_ConfigChannel(&TIMx_Handler,&TIMx_CHyConfig,TIM_CHANNEL_2);//配置TIM3通道3
HAL_TIM_IC_Start_IT(&TIMx_Handler,TIM_CHANNEL_2); //开启TIM2的捕获通道2,并且开启捕获中断
__HAL_TIM_ENABLE_IT(&TIMx_Handler,TIM_IT_UPDATE); //使能更新中断
HAL_NVIC_SetPriority(TIM2_IRQn,2,0); //设置中断优先级,抢占优先级2,子优先级0
HAL_NVIC_EnableIRQ(TIM2_IRQn); //开启ITM2中断通道
}
//定时器2底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_IC_Init()调用
//htim:定时器2句柄
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_TIM2_CLK_ENABLE(); //使能TIM2时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Pin=GPIO_PIN_1; //PA1
GPIO_Initure.Mode=GPIO_MODE_AF_INPUT; //复用推挽输入
GPIO_Initure.Pull=GPIO_PULLDOWN; //下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
HAL_NVIC_SetPriority(TIM2_IRQn,2,0); //设置中断优先级,抢占优先级2,子优先级0
HAL_NVIC_EnableIRQ(TIM2_IRQn); //开启ITM2中断通道
}
//捕获状态
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
//[5:0]:捕获低电平后溢出的次数
u8 TIM2CH2_CAPTURE_STA=0; //输入捕获状态
u16 TIM2CH2_CAPTURE_VAL; //输入捕获值(TIM2是16位)
//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIMx_Handler); //定时器共用处理函数
}
//定时器更新中断(计数溢出)中断处理回调函数, 该函数在HAL_TIM_IRQHandler中会被调用,实现多个计数器满装载的计数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//更新中断(溢出)发生时执行
{
if((TIM2CH2_CAPTURE_STA&0X80)==0) //还未成功捕获上升沿
{
if(TIM2CH2_CAPTURE_STA&0X40) //已经捕获到高电平了
{
if((TIM2CH2_CAPTURE_STA&0X3F)==0X3F) //高电平太长了
{
TIM2CH2_CAPTURE_STA|=0X80; //标记成功捕获了一次
TIM2CH2_CAPTURE_VAL=0XFFFF;
}else TIM2CH2_CAPTURE_STA++;
}
}
}
//定时器输入捕获中断处理回调函数,该函数在HAL_TIM_IRQHandler中会被调用
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕获中断发生时执行
{
if((TIM2CH2_CAPTURE_STA&0X80)==0) //还未成功捕获
{
if(TIM2CH2_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM2CH2_CAPTURE_STA|=0X80; //标记成功捕获到一次高电平脉宽
TIM2CH2_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&TIMx_Handler,TIM_CHANNEL_2);//获取当前的捕获值.
TIM_RESET_CAPTUREPOLARITY(&TIMx_Handler,TIM_CHANNEL_2); //一定要先清除原来的设置!!
TIM_SET_CAPTUREPOLARITY(&TIMx_Handler,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING);//配置TIM2通道2上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM2CH2_CAPTURE_STA=0; //清空
TIM2CH2_CAPTURE_VAL=0;
TIM2CH2_CAPTURE_STA|=0X40; //标记捕获到了上升沿
__HAL_TIM_DISABLE(&TIMx_Handler); //关闭定时器2
__HAL_TIM_SET_COUNTER(&TIMx_Handler,0);
TIM_RESET_CAPTUREPOLARITY(&TIMx_Handler,TIM_CHANNEL_2); //一定要先清除原来的设置!!
TIM_SET_CAPTUREPOLARITY(&TIMx_Handler,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING);//定时器2通道2设置为下降沿捕获
__HAL_TIM_ENABLE(&TIMx_Handler); //使能定时器2
}
}
}
主函数
int main()
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
delay_init(72); //初始化延时函数
uart_init(9600); //初始化串口
LED_Init(); //初始化LED
Trig_Init();
TIM2_CHx_Cap_Init(0xffff,7200-1);
float len=0;
u32 time=0;
while(1)
{ u8 count=0;
delay_ms(10);
CHL_capture(); //PAout(0)
if(TIM2CH2_CAPTURE_STA&0X80) //成功捕获到了一次高电平
{
time=TIM2CH2_CAPTURE_STA&0X3F;
time*=65536; //溢出时间总和
time+=TIM2CH2_CAPTURE_VAL; //得到总的高电平时间
len=time*1.7;
if(len<20)
LED0=0;
else LED0=1;
TIM2CH2_CAPTURE_STA=0; //开启下一次捕获
}
printf("LENGHT:%f CM\r\n",len); //打印平均距离
}
}
程序下载链接(https://download.csdn.net/download/qq_42258981/12141380)