嵌入式大赛初探之-(3)外接超声波距离传感器
因为要用到测距功能,需要熟悉外接测距传感器,并研究其测距精度。
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、超声波传感器HC-SR04
- 二.工作原理
- 三、MRS添加库文件
- 1.新建.c和.h文件
- 2.编写.c函数
- 总结
前言
对于外设,首先需要学会用mounriver studio添加外设库,并编写相关函数在主程序完成测距的功能。
一、超声波传感器HC-SR04
外接的 超声波是振动频率高于20KHZ的机械波。它具有频率高、波长短、绕射现象小、方向性好、能够成为射线而定向传播等特点,应用广泛,适合大学生、工程师、技术人员以及电子爱好者等操作。
新版HC-SR04,性能远超老版HC-SRO4、US-015,在测距精度高于老版HC-SRO4和US-015的情况下,测距范围更远,可达6米,远超一般超声波测距模块。采用CS-100A超声波测距SOC芯片,高性能,工业级,宽电压、低价格,只有普通超声波测距模块一半的价格,而性能远超普通超声波测距模块。性能与US-025相同,均采用CS100A芯片,接口完全兼容。
这里选择拓展接口的PD10和PD11。
超声波HC-SR04模块:
VCC --> VCC
GND --> GND
Trig --> PD10
Echo --> PD11
二.工作原理
Trig (Trigger) 引脚用于触发超声波脉冲。
Echo 回声当接收到反射信号时,引脚产生一个脉冲。脉冲的长度与检测发射信号所需的时间成正比。
当持续时间至少为10 µS(10微秒)的脉冲施加到触发引脚时,一切开始。响应于此,传感器以40 KHz发射八个脉冲的声音脉冲。8脉冲模式从而使接收器能够将发射模式与环境超声噪声区分开。
八个超声波脉冲通过空气传播,远离发射器。同时,回声引脚变为高电平,开始形成回声信号的开始。
如果这些脉冲没有被反射回来(即最大距离内无障碍物时),则回波信号将在38毫秒(38毫秒)后超时并返回低电平。因此38 ms的脉冲表示在传感器范围内没有阻塞。

如果,脉冲被反射回去,则在收到信号后,Echo引脚就会变低。这会产生一个脉冲,其宽度在150 µS至25 mS之间变化,具体取决于接收信号所花费时间。
因此,当无障碍时,获取的回应脉冲为38ms长度,而存在障碍时,获取的回应脉冲长度为150 µS至25 mS之间变化。

总结:距离= 高电平时间*声速(340M/S)/2;
三、MRS添加库文件
1.新建.c和.h文件
打开MRS,创建一个CH32V307VCT6项目,在左侧的CH32V307VCT6栏目新建一个hardware文件夹,右键-新建-文件夹,起名叫HC-SR04,再右键-新建-头文件、源文件。

添加新的头文件需要添加到头文件寻址路径中,点击菜单栏-项目-属性配置按钮,在弹出的页面中,如下图,点击绿色加号添加路径即可。

2.编写.c函数
具体思路是:只需要将一个IO口配置推挽输出作为Trig,一个IO口配置下拉输入作为Echo,因为当Echo收到回响信号会由低电平置高电平,因此默认设置Echo为低电平。距离= 高电平时间*声速(340M/S)/2;
先用SysTick软件延时控制Trig发出高电平,之后等待回响信号,当Echo收到信号,即开启定时器,但是我们这个程序是在定时器中运行的,利用同一个定时器TIM2,在收到信号后要先把定时器清零。之后得到电平持续时间,计算出距离后再次把定时器清零,并且开启定时器,下次定时器中断方能正常触发。
(1)编写定时器函数
代码如下:
#include "debug.h" // Device header
//初始化定时器,采用基本定时器6,
void Timer_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //启用TIM3时钟TIM_InternalClockConfig(TIM6); //设置TIM3使用内部时钟TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体,配置定时器TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置1分频(不分频)TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数模式为向上计数TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; //设置最大计数值,达到最大值触发更新事件,因为从0开始计数,所以计数10次是10-1,每10微秒触发一次TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //设置时钟预分频,72-1就是每 时钟频率(72Mhz)/72=1000000 个时钟周期计数器加1,每1微秒+1TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器(高级定时器才有,所以设置0)TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStructure); //初始化TIM6定时器TIM_ClearFlag(TIM6, TIM_FLAG_Update); //清除更新中断标志位TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); //开启更新中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级分组NVIC_InitTypeDef NVIC_InitStructure; //定义结构体,配置中断优先级NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //指定中断通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //设置抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //设置响应优先级NVIC_Init(&NVIC_InitStructure); // https://blog.zeruns.techTIM_Cmd(TIM6, ENABLE); //开启定时器
}/*
void TIM3_IRQHandler(void) //更新中断函数
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //获取TIM3定时器的更新中断标志位{TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除更新中断标志位}
}*/
#ifndef __TIMER_H
#define __TIMER_Hvoid Timer_Init(void);#endif
(2)编写HC-SR04初始化与测距函数
#include "debug.h"
#include "stdio.h"
#include "ch32v30x.h"#define Echo GPIO_Pin_10 //HC-SR04模块的Echo脚接GPIOD10
#define Trig GPIO_Pin_11 //HC-SR04模块的Trig脚接GPIOD11uint64_t time=0; //声明变量,用来计时
uint64_t time_end=0; //声明变量,存储回波信号时间void HC_SR04_Init(void)
{ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE); //启用GPIOB的外设时钟GPIO_InitTypeDef GPIO_InitStructure; //定义结构体GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置GPIO口为推挽输出GPIO_InitStructure.GPIO_Pin = Trig; //设置GPIO口5GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置GPIO口速度50MhzGPIO_Init(GPIOD,&GPIO_InitStructure); //初始化GPIOBGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置GPIO口为下拉输入模式GPIO_InitStructure.GPIO_Pin = Echo; //设置GPIO口6GPIO_Init(GPIOD,&GPIO_InitStructure); //初始化GPIOBGPIO_WriteBit(GPIOD,GPIO_Pin_10,0); //输出低电平,让回应信号先保持低电平状态Delay_Us(15); //延时15微秒
}int16_t sonar_mm(void) //测距并返回单位为毫米的距离结果
{uint32_t Distance,Distance_mm = 0;GPIO_WriteBit(GPIOB,Trig,1); //输出高电平Delay_Us(15); //延时15微秒GPIO_WriteBit(GPIOB,Trig,0); //输出低电平while(GPIO_ReadInputDataBit(GPIOB,Echo)==0); //等待低电平结束time=0; //计时清零while(GPIO_ReadInputDataBit(GPIOB,Echo)==1); //等待高电平结束time_end=time; //记录结束时的时间if(time_end/100<38) //判断是否小于38毫秒,大于38毫秒的就是超时,直接调到下面返回0{Distance=(time_end*346)/2; //计算距离,25°C空气中的音速为346m/sDistance_mm=Distance/100; //因为上面的time_end的单位是10微秒,所以要得出单位为毫米的距离结果,还得除以100}return Distance_mm; //返回测距结果
}float sonar(void) //测距并返回单位为米的距离结果
{uint32_t Distance,Distance_mm = 0;float Distance_m=0;GPIO_WriteBit(GPIOB,Trig,1); //输出高电平Delay_Us(15);GPIO_WriteBit(GPIOB,Trig,0); //输出低电平while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);time=0;while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);time_end=time;if(time_end/100<38){Distance=(time_end*346)/2;Distance_mm=Distance/100;Distance_m=Distance_mm/1000;}return Distance_m;
}void TIM3_IRQHandler(void) //更新中断函数,用来计时,每10微秒变量time加1
{if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //获取TIM3定时器的更新中断标志位{time++;TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除更新中断标志位}
}
#ifndef __HCSR04_H
#define __HCSR04_Hvoid HC_SR04_Init(void);
int16_t sonar_mm(void);
float sonar(void);#endif
(3)编写主程序
这里要实现的是使用毫米为单位,并用串口打印测得距离。
#include "debug.h"
#include "timer_6.h"
#include "HC-SR04.h"
/* Global typedef *//* Global define *//* Global Variable *//********************************************************************** @fn main** @brief Main program.** @return none*/
int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);SystemCoreClockUpdate();Delay_Init();USART_Printf_Init(115200); Timer_Init();HC_SR04_Init();//printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );//printf("This is printf example\r\n");while(1){float distance = sonar_mm();printf("distance:%f\r\n",distance);}
}
总结
目前由于项目要用到更为复杂的测距方案,因此本文在借鉴其他大佬的HC-SR04的库,只给出了最基础的应用实例。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
