完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1.所需硬件
正点原子战舰V3开发板 X1 HC-SR04超声波模块 X1 杜邦线 若干 2.HC-SR04超声波模块介绍 上图为HC-SR04超声波模块实物图,从图中可以看到,该模块一共有四个引脚,分别是VCC、GND、Trig、Echo,关于该模块这里不做过多的详细介绍,感兴趣的同学可以自行百度了解,下面将简单介绍该模块的原理及使用方法。根据时序图可知,首先给TRIG引脚至少10us的高电平信号触发测距,模块自动发送8个40KHz的方波,自动检测是否有信号返回,若有信号返回,通过Echo引脚输出一个高电平,高电平的持续时间就是超声波从发射到返回的时间, 时序图如下 该模块使用较简单,难点在于程序的编写。 3.硬件连接 [tr]Vcc3.3/5V[/tr]
1、配置好使用到的GPIO以及定时器; 2、给模块TRIG端口发送大于10us的高电平信号,当收、收到ECHO回响信号是,打开定时器开始定时; 3、当回响信号消失,关闭定时器; 4、通过定时器定时时间来确定距离。 5.程序代码 HCSR04.c源文件 #include "hcsr04.h" #include "sys.h" #include "delay.h" #define HCSR04_PORT GPIOB #define HCSR04_CLK RCC_APB2Periph_GPIOB #define HCSR04_TRIG GPIO_Pin_5 #define HCSR04_ECHO GPIO_Pin_6 #define TRIG_Send PBout(5) #define ECHO_Reci PBin(6) void Delay_Ms(uint16_t time); void Delay_Us(uint16_t time); void hcsr04_NVIC(); u16 msHcCount = 0; //ms计数 void Hcsr04Init() { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //生成用于定时器设置的结构体 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE); //IO初始化 GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG; //发送电平引脚 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_Init(HCSR04_PORT, &GPIO_InitStructure); GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG); GPIO_InitStructure.GPIO_Pin = HCSR04_ECHO; //返回电平引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(HCSR04_PORT, &GPIO_InitStructure); GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO); //定时器初始化 使用基本定时器TIM6 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //使能对应RCC时钟 //配置定时器基础结构体 TIM_DeInit(TIM2); TIM_TimeBaseStructure.TIM_Period = (1000-1); //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到1000为1ms TIM_TimeBaseStructure.TIM_Prescaler =(72-1); //设置用来作为TIMx时钟频率除数的预分频值 1M的计数频率 1US计数 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ClearFlag(TIM6, TIM_FLAG_Update); //清除更新中断,免得一打开中断立即产生中断 TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); //打开定时器更新中断 hcsr04_NVIC(); TIM_Cmd(TIM6,DISABLE); } //tips:static函数的作用域仅限于定义它的源文件内,所以不需要在头文件里声明 static void OpenTimerForHc() //打开定时器 { TIM_SetCounter(TIM6,0); //清除计数 msHcCount = 0; TIM_Cmd(TIM6, ENABLE); //使能TIMx外设 } static void CloseTimerForHc() //关闭定时器 { TIM_Cmd(TIM6, DISABLE); //使能TIMx外设 } //NVIC配置 void hcsr04_NVIC() { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //选择串口1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应式中断优先级设置为1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); } //定时器6中断服务程序 void TIM6_IRQHandler(void) //TIM3中断 { if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否 { TIM_ClearITPendingBit(TIM6, TIM_IT_Update ); //清除TIMx更新中断标志 msHcCount++; } } //获取定时器时间 u32 GetEchoTimer(void) { u32 t = 0; t = msHcCount*1000; //得到MS t += TIM_GetCounter(TIM6); //得到US TIM6->CNT = 0; //将TIM2计数寄存器的计数值清零 Delay_Ms(50); return t; } //一次获取超声波测距数据 两次测距之间需要相隔一段时间,隔断回响信号 //为了消除余震的影响,取五次数据的平均值进行加权滤波。 float Hcsr04GetLength(void ) { u32 t = 0; int i = 0; float lengthTemp = 0; float sum = 0; while(i!=5) { TRIG_Send = 1; //发送口高电平输出 Delay_Us(20); TRIG_Send = 0; while(ECHO_Reci == 0); //等待接收口高电平输出 OpenTimerForHc(); //打开定时器 i = i + 1; while(ECHO_Reci == 1); CloseTimerForHc(); //关闭定时器 t = GetEchoTimer(); //获取时间,分辨率为1US lengthTemp = ((float)t/58.0);//cm sum = lengthTemp + sum ; } lengthTemp = sum/5.0; return lengthTemp; } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ** 函数名称: Delay_Ms_Ms ** 功能描述: 延时1MS (可通过仿真来判断他的准确度) ** 参数描述:time (ms) 注意time<65535 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ void Delay_Ms(uint16_t time) //延时函数 { uint16_t i,j; for(i=0;i for(j=0;j<10260;j++); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ** 函数名称: Delay_Ms_Us ** 功能描述: 延时1us (可通过仿真来判断他的准确度) ** 参数描述:time (us) 注意time<65535 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ void Delay_Us(uint16_t time) //延时函数 { uint16_t i,j; for(i=0;i for(j=0;j<9;j++); } main.c源文件 #include "hcsr04.h" #include "sys.h" #include "delay.h" #define HCSR04_PORT GPIOB #define HCSR04_CLK RCC_APB2Periph_GPIOB #define HCSR04_TRIG GPIO_Pin_5 #define HCSR04_ECHO GPIO_Pin_6 #define TRIG_Send PBout(5) #define ECHO_Reci PBin(6) void Delay_Ms(uint16_t time); void Delay_Us(uint16_t time); void hcsr04_NVIC(); u16 msHcCount = 0; //ms计数 void Hcsr04Init() { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //生成用于定时器设置的结构体 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE); //IO初始化 GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG; //发送电平引脚 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_Init(HCSR04_PORT, &GPIO_InitStructure); GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG); GPIO_InitStructure.GPIO_Pin = HCSR04_ECHO; //返回电平引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(HCSR04_PORT, &GPIO_InitStructure); GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO); //定时器初始化 使用基本定时器TIM6 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //使能对应RCC时钟 //配置定时器基础结构体 TIM_DeInit(TIM2); TIM_TimeBaseStructure.TIM_Period = (1000-1); //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到1000为1ms TIM_TimeBaseStructure.TIM_Prescaler =(72-1); //设置用来作为TIMx时钟频率除数的预分频值 1M的计数频率 1US计数 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ClearFlag(TIM6, TIM_FLAG_Update); //清除更新中断,免得一打开中断立即产生中断 TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); //打开定时器更新中断 hcsr04_NVIC(); TIM_Cmd(TIM6,DISABLE); } //tips:static函数的作用域仅限于定义它的源文件内,所以不需要在头文件里声明 static void OpenTimerForHc() //打开定时器 { TIM_SetCounter(TIM6,0); //清除计数 msHcCount = 0; TIM_Cmd(TIM6, ENABLE); //使能TIMx外设 } static void CloseTimerForHc() //关闭定时器 { TIM_Cmd(TIM6, DISABLE); //使能TIMx外设 } //NVIC配置 void hcsr04_NVIC() { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //选择串口1中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应式中断优先级设置为1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); } //定时器6中断服务程序 void TIM6_IRQHandler(void) //TIM3中断 { if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否 { TIM_ClearITPendingBit(TIM6, TIM_IT_Update ); //清除TIMx更新中断标志 msHcCount++; } } //获取定时器时间 u32 GetEchoTimer(void) { u32 t = 0; t = msHcCount*1000; //得到MS t += TIM_GetCounter(TIM6); //得到US TIM6->CNT = 0; //将TIM2计数寄存器的计数值清零 Delay_Ms(50); return t; } //一次获取超声波测距数据 两次测距之间需要相隔一段时间,隔断回响信号 //为了消除余震的影响,取五次数据的平均值进行加权滤波。 float Hcsr04GetLength(void ) { u32 t = 0; int i = 0; float lengthTemp = 0; float sum = 0; while(i!=5) { TRIG_Send = 1; //发送口高电平输出 Delay_Us(20); TRIG_Send = 0; while(ECHO_Reci == 0); //等待接收口高电平输出 OpenTimerForHc(); //打开定时器 i = i + 1; while(ECHO_Reci == 1); CloseTimerForHc(); //关闭定时器 t = GetEchoTimer(); //获取时间,分辨率为1US lengthTemp = ((float)t/58.0);//cm sum = lengthTemp + sum ; } lengthTemp = sum/5.0; return lengthTemp; } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ** 函数名称: Delay_Ms_Ms ** 功能描述: 延时1MS (可通过仿真来判断他的准确度) ** 参数描述:time (ms) 注意time<65535 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ void Delay_Ms(uint16_t time) //延时函数 { uint16_t i,j; for(i=0;i for(j=0;j<10260;j++); } /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ** 函数名称: Delay_Ms_Us ** 功能描述: 延时1us (可通过仿真来判断他的准确度) ** 参数描述:time (us) 注意time<65535 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ void Delay_Us(uint16_t time) //延时函数 { uint16_t i,j; for(i=0;i for(j=0;j<9;j++); } 5.总结 通过本次的项目,我们对STM32的定时器的应用有一定了解,在学习STM32单片机的过程中自己可以边学边做项目,这样会提高自己的动手能力,也会巩固理论知识,本篇博客简单介绍了利用超声波模块测距,如需进一步了解可自行求助度娘,希望对大家的学习有所帮助! |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1867浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
650浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
518浏览 3评论
536浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
506浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 08:21 , Processed in 0.768195 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号