HC-SR04 超声波测距模块
方法二:
在向Trig控制端发送触发信号后,通过定时器的输入捕获引脚抓取到Echo引脚上升沿,开启定时器计时直到Echo变为低电平,关闭定时器记录下计时时间,通过公式计算具体的距离。
程序:
定时器初始化:
tim.c
#include "tim.h"
#include "delay.h"
#include "Printf.h"
/*2020.11.16*/
//通用定时器 5 初始化
void TIM5_Int_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM5_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能 TIM5 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 时钟
//初始化 GPIOA.0
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入 //回波接收ECHO端口
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.0
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉
//初始化 TIM5 参数
TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式
//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //初始化 TIMx
//初始化 TIM5 输入捕获通道 1
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1 映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure); //初始化 TIM5 输入捕获通道 1
//初始化 NVIC 中断优先级分组
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级 2 级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级 0 级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化 NVIC
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断捕获中断
//TIM_SetCounter(TIM5,0); //设置计数器初值
TIM_Cmd(TIM5,ENABLE ); //使能定时器 5
}
u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
//定时器 5 中断服务程序
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40) //已经捕获到高电平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕获 1 发生捕获事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
tim.h
#include "sys.h"
//通用定时器 5 初始化
void TIM5_Int_Init(u16 arr,u16 psc);
超声波引脚配置
hc-sr04.c
#include "hc-sr04.h"
#include "tim.h"
#include "delay.h"
#include "Printf.h"
/*2020.11.16
* HC-SR04超声波测距模块
* 基本工作原理:* 给TRIG引脚至少10us的高电平信号触发测距
* 模块自动发送8个40KHz的方波,自动检测是否有信号返回
* 有信号返回,通过Echo引脚输出一个高电平,高电平的持续时间就是超声波从发射到返回的时间
* 测量距离 = (高电平的持续时间 * 声速(340m/s))/ 2
*/
#define HC_SR04_TRIG_CLK RCC_APB2Periph_GPIOA //脉冲触发TRIG端口
#define HC_SR04_TRIG_PORT GPIOA
#define HC_SR04_TRIG_PIN GPIO_Pin_4
//HC_SR04超声波初始化
void HC_SR04_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(HC_SR04_TRIG_CLK, ENABLE); //使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = HC_SR04_TRIG_PIN; // 脉冲触发端口(Trig)配置PA4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(HC_SR04_TRIG_PORT, &GPIO_InitStructure); //根据设定参数初始化端口
}
//发送20us的脉冲触发信号
void HC_SR04_start(void)
{
GPIO_SetBits(HC_SR04_TRIG_PORT,HC_SR04_TRIG_PIN); //TRIG置高
delay_us(20);
GPIO_ResetBits(HC_SR04_TRIG_PORT,HC_SR04_TRIG_PIN); //TRIG置低
delay_ms(10);
}
hc-sr04.h
#include "sys.h"
//HC_SR04超声波初始化
void HC_SR04_Init(void);
//发送20us的脉冲触发信号
void HC_SR04_start(void);
主函数;
main.c
#include "sys.h"
#include "delay.h"
#include "hc-sr04.h"
#include "usart.h"
#include "Printf.h"
#include "tim.h"
extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态
extern u16 TIM5CH1_CAPTURE_VAL; //输入捕获值
int main(void)
{
float Distance=0;
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //系统时钟设置PLL作为系统时钟
delay_init(); //初始化延时函数
uart_init(9600);
HC_SR04_Init();
TIM5_Int_Init(65535,71);
printf("开始测量距离\r\n");
/*在发送触发信号后,通过定时器的输入捕获引脚抓取Echo引脚上升沿,
开启定时器计时直到Echo变为低电平,关闭定时器记录下计时时间*/
while(1)
{
HC_SR04_start(); //发送20us的脉冲触发信号
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次高电平
{
Distance=TIM5CH1_CAPTURE_STA&0X3F;
Distance*=65536; //溢出时间总和
Distance += TIM5CH1_CAPTURE_VAL; //得到总的高电平时间 ECHO输出的高电平的时间就是超声波从发射到返回的时间
Distance = Distance *170*0.0001;
printf("测的距离 = %0.4f cm \r\n",Distance);
TIM5CH1_CAPTURE_STA=0; //开启下一次捕获
}
delay_ms(500);
}
}