超声波测距模块介绍
实物图
超声波传感器模块上面通常有两个超声波元器件,一个用于发射,一个用于接收。
引脚定义
电路板上有四个引脚:VCC、GND、Trig(控制端)、Echo(接收端)。
1.单片机在控制口发一个 10US 以上的高电平,
2.就可以在接收口等待传感器模块高电平输出.
3.一有输出单片机就可以开定时器计时,
4.当此口变为低电平时就可以读定时器的值,此时就为此次测距的时间,
方可算出距离.如此不断的周期测,就可以达到你移动测量的值了。
即
Trig(控制端):对应的GPIO引脚设置为输出模式
Echo(接收端):对应的GPIO引脚设置为输入模式
模块工作原理
(1)采用 IO 触发测距,给至少 10us 的高电平信号;
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 输出一高电平,高电平持续的时间就是此次测距的时间
(4)超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;
超声波时序图
注意:手册介绍说建议测量周期为60ms以上。防止回响信号没有测量完,就再一次发送触发信号。
模块实现
运用功能
1.位带操作,控制引脚输出高电平
2.定时器输入捕获:输入引脚设置为定时器模式,捕获引脚的高电平,
输入捕获功能参考文章:
定时器输入捕获
配置流程
1. 打开定时器和相应IO口的时钟。
2. 初始化IO口,模式为输入:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
3. 初始化定时器ARR,PSC
TIM_TimeBaseInit();
4. 初始化输入捕获通道
TIM_ICInit();
5. 配置相应的中断
6. NVIC_Init();
TIM_ITConfig();
7. 使能定时器:TIM_Cmd();
8. 编写中断服务函数:TIMx_IRQHandler();
代码示例
#include "stm32f10x.h"
#include <stdio.h>
#include "sys.h"
#include "delay.h"
#include "Bluetooth.h"
float Distance1;
u16 TIM2CH2_CAPTURE_STA,TIM2CH2_CAPTURE_VAL;
void Time12_CH2_Init()
{
GPIO_InitTypeDef GPIOInitDef;
TIM_TimeBaseInitTypeDef TIMBaseInitDef;
NVIC_InitTypeDef NVICInitDef;
TIM_ICInitTypeDef TIMICInitDef;
//-----------------------------------------------------开时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //PA1--TIM2_CH2
//-----------------------------------------------------
GPIOInitDef.GPIO_Pin = GPIO_Pin_1; //设置引脚PA1
GPIOInitDef.GPIO_Mode = GPIO_Mode_IPD; //设置下拉输入
GPIOInitDef.GPIO_Speed = GPIO_Speed_50MHz; //设置传输速率为50MHZ
GPIO_Init(GPIOA, &GPIOInitDef); //调用GPIO初始化函数,进行初始化
//----------------------------------------------------- 配置定时器
TIMBaseInitDef.TIM_ClockDivision=TIM_CKD_DIV1;
TIMBaseInitDef.TIM_CounterMode=TIM_CounterMode_Up;//配置向上计数
TIMBaseInitDef.TIM_Period=1000-1; //计数周期100ms
TIMBaseInitDef.TIM_Prescaler=7200-1; //10khz CNT_t=100us 0.1ms
TIM_TimeBaseInit(TIM2,&TIMBaseInitDef);
//-----------------------------------------------------
TIMICInitDef.TIM_Channel=TIM_Channel_2;
TIMICInitDef.TIM_ICFilter=0X00; //
TIMICInitDef.TIM_ICPolarity=TIM_ICPolarity_Rising; //上升沿
TIMICInitDef.TIM_ICPrescaler=TIM_ICPSC_DIV1; //不分频
TIMICInitDef.TIM_ICSelection=TIM_ICSelection_DirectTI; //影子寄存器cc2映射到捕获通道TI2
TIM_ICInit(TIM2,&TIMICInitDef);
//----------------------------------------------------- 设置中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE);
NVICInitDef.NVIC_IRQChannel=TIM2_IRQn; //设置更新中断
NVICInitDef.NVIC_IRQChannelCmd=ENABLE;
NVICInitDef.NVIC_IRQChannelPreemptionPriority=3;
NVICInitDef.NVIC_IRQChannelSubPriority=3;
NVIC_Init(&NVICInitDef);
TIM_Cmd(TIM2,ENABLE); //使能定时器
}
void TIM2_IRQHandler(void)
{
if((TIM2CH2_CAPTURE_STA&0X80)==0)//还未成功捕获
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//溢出
{
if(TIM2CH2_CAPTURE_STA&0X40)//已经捕获到高电平了
{
if((TIM2CH2_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM2CH2_CAPTURE_STA|=0X80;//标记成功捕获了一次
TIM2CH2_CAPTURE_VAL=0XFFFF;
}
else
TIM2CH2_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//发生捕获事件
{
if(TIM2CH2_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM2CH2_CAPTURE_STA|=0X80; //标记成功捕获到一次高电平脉宽
TIM2CH2_CAPTURE_VAL=TIM_GetCapture3(TIM3); //获取当前的捕获值.
TIM_OC2PolarityConfig(TIM3, TIM_ICPolarity_Rising); //设置为上升沿捕获
}
else //还未开始,第一次捕获上升沿
{
TIM2CH2_CAPTURE_STA=0; //清空
TIM2CH2_CAPTURE_VAL=0;
TIM2CH2_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_SetCounter(TIM2, 0); //清空计数器
TIM_OC3PolarityConfig(TIM2, TIM_ICPolarity_Falling);//设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update|TIM_IT_CC3); //清除中断标志位
}
void Read_TIM3Distane(void)
{
PBout(0)=1; //输出10us以上的高电平
delay_us(15);
PBout(0)=0;
if(TIM2CH2_CAPTURE_STA&0X80)//成功捕获到了一次高电平
{
Distance1=TIM2CH2_CAPTURE_STA&0X3F;
Distance1*=65536; //溢出时间总和
Distance1+=TIM2CH2_CAPTURE_VAL; //得到总的高电平时间
Distance1=Distance1*170/1000; //340除以2=170,计数周期为100MS,单位为340M/S,再将单位M换算为CM所以除以1000
printf("aaa%f \r\n",Distance1);
TIM2CH2_CAPTURE_STA=0; //开启下一次捕获
}
}