STM32f103驱动超声波测距模块
关键词:输入捕获 定时器 中断
使用的超声波测距模块型号为US-015,该模块可实现2cm~4cm的非接触测距功能,供电电压为5v,工作电流为2.2mA,支持GPIO通信模式。
模块引脚:
VCC引脚 :接直流5V电源
Trig引脚: 接外部电路的Trig端,向此管脚输入一个10us以上的高电平,触发模块测距
Echo引脚 :接外部电路的Echo端,测距结束时,此管脚会输出一个高电平,电平宽度为超声波往返时间之和
GND引脚: 接外部电路的地
测距原理:
(1)给模块Trig引脚至少10us的高电平信号触发测距
(2)模块自动发送8个40kHz的方波,自动检测是否有信号返回
(3)有信号返回时,通过Echo引脚输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
:测试距离=(高电平时间*声速)/2 :
硬件连接:
超声波测距模块 | STM32mini |
---|---|
VCC | VCC5(VOUT2) |
Trig | PA8 |
Echo | PA0 |
GND | GND(VOUT2) |
驱动程序:
(1)点亮LED0时PA8发出高电平,这里给Trig引脚20ms的高电平,触发模块测距
LED0=1;
delay_ms(20);
LED0=0;
(2)用输入捕获模式来测量脉冲宽度,参考正点原子的输入捕获实验,配置定时器2的通道1进行输入捕获,即void TIM2_Cap_Init(u16 arr,u16 psc)。配置定时器2输入捕获和定时器中断详情参考正点原子输入捕获实验timer.c。
捕获原理:
通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度。同时,如果脉宽比较长,那么定时器就会溢出,需要对溢出做处理。
假设要捕获如图所示波形的脉宽:
1.先设置定时器为向上计数模式
2.设置定时器的采样通道channelx为上升下降沿捕获,所以在t1时刻,上升沿就会捕获到当前CNT的值,随即将CNT清零
3.在t2时刻下降沿会捕获CNT的值,记为CCRx2
4.根据定时器的频率,以及期间溢出的次数,即可算出|t1-t2|的时间,从而得到高电平脉宽。
输入捕获原理转自csdn文章:
[stm32]stm32F4输入捕获原理
关于自动重装载值arr和预分频系数psc的设置:
溢出时间Tout=((arr+1)*(psc+1))/Tclk
Tclk为TIM2输入时钟频率
根据stm32内部时钟树得知:当APB1的时钟分频数为1的时候,TIM2~7 的时钟为APB1的时钟
而如果 APB1 的时钟分频数不为 1,那么TIM2~7 的时钟频率将为 APB1 时钟的两倍,因此,TIM2的时钟为 72MHz
这里设置arr=0xFFFF,psc=7199
即将72MHz时钟7200分频后变为10KHz,用这10KHz的时钟作为定时器的基准时钟,然后计数0xFFFF个数后,产生一次定时器中断。
(3)主函数通过 TIM2CH1_CAPTURE_STA 的第 7 位,来判断有没有成功捕获到一次高电平,
如果成功捕获,则将高电平时间通过串口输出到电脑。
TIM2CH1_CAPTURE_STA 各位描述
bit7 | bit6 | bit5~0 |
---|---|---|
捕获完成标志 | 捕获到高电平标志 | 捕获高电平后定时器溢出的次数 |
将结果通过串口调试助手打印出来:
以下是main.c程序(库函数版本):
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
#include "usart.h"
extern u8 TIM2CH1_CAPTURE_STA; //输入捕获状态(变量当成寄存器使用)
extern u16 TIM2CH1_CAPTURE_VAL; //输入捕获值
int main(void)
{
float distance;
u32 temp=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
delay_init(); //延时函数初始化
uart_init(9600); //9600
LED_Init(); //初始化与LED连接的硬件接口
TIM2_Cap_Init(0XFFFF,7200-1); //以10khz的频率计数
while(1)
{
LED0=1;
delay_ms(20);
LED0=0;
if(TIM2CH1_CAPTURE_STA&0X80)//成功捕获到了一次高电平
{
temp=TIM2CH1_CAPTURE_STA&0X3F;//得到捕获高电平后定时器溢出次数
temp*=65536; //溢出时间总和
temp+=TIM2CH1_CAPTURE_VAL; //得到总的高电平时间
distance=(temp*340)/2; //得到距离,单位:m
printf("DISTANCE:%f cm\r\n",distance); //打印距离
TIM2CH1_CAPTURE_STA=0; //开启下一次捕获
}
}
}
附上一张实物图: