2.10 SR04 超声波测距传感器
2.10.1 模块来源
采购链接: HC-SR04 超声波测距模块 宽电压 3-5.5V 工业级 传感器 资料下载链接: https://pan.baidu.com/s/1sSah9PvLBrmbA7So-6YcSw 资料提取码:qq35
2.10.2 规格参数
工作电压: 5-5.5V
工作电流: 5.3MA
感应角度: 小于 15 度
探测距离: 2CM-600CM
探测精度: 0.1CM+1%
输出方式: GPIO
管脚数量: 4 Pin
2.10.3 移植过程
我们的目标是在梁山派 GD32F470 上能够判断前方障碍物距离的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
2.10.3.1 查看资料
只需要在 Trig 管脚(触发信号)输入一个 10US 以上的高电平,系统便可发出 8 个 40KHZ 的超声波脉冲,然后检测回波信号。当检测到回波信号后,通过 Echo 管脚输出。根据 Echo 管脚输出高电平的持续时间可以计算距离值。即距离值为:(高电平时间*340m/s)/2。
当测量距离超过 HC-SR04 的测量范围时,仍会通过 Echo 管脚输出高电平的信号,高电平的宽度约为 66ms。如图 6 所示:
测量周期:当接收到 HC-SR04 通过 Echo 管脚输出的高电平脉冲后,便可进行下一次测量,所以测量周期取决于测量距离,当距离被测物体很近时,Echo 返回的脉冲宽度较窄,测量周期 就很短;当距离被测物体比较远时,Echo 返回的脉冲宽度较宽,测量周期也就相应的变长。最坏情况下,被测物体超出超声波模块的测量范围,此时 返回的脉冲宽度最长,约为 66ms,所以最坏情况下的测量周期稍大于 66ms 即可(取 70ms 足够)。
2.10.3.2 引脚选择
实测模块的电源必须是 5V!
2.10.3.3 移植至工程
移植步骤中的导入.c 和.h 文件与上一节相同,只是将.c 和.h 文件更改为 bsp_ultrasonic.c 与 bsp_ultrasonic.h。见 2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件 bsp_ultrasonic.c 中,编写如下代码。
/********************************************************************************
* 文 件 名: bsp_ultrasonic.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2023年04月17日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "bsp_ultrasonic.h"
#include "systick.h"
unsigned char msHcCount = 0;//ms计数
float distance = 0;
/******************************************************************
* 函 数 名 称:bsp_ultrasonic
* 函 数 说 明:超声波初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:TRIG引脚负责发送超声波脉冲串
******************************************************************/
void Ultrasonic_Init(void)
{
// 定义定时器结构体
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TRIG);
rcu_periph_clock_enable(RCU_ECHO);
//设置TRIG引脚模式为推挽输出
gpio_mode_set(PORT_TRIG, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_TRIG);
//设置引脚为推挽模式,翻转速度50MHz
gpio_output_options_set(PORT_TRIG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_TRIG);
//设置引脚输出低电平
gpio_bit_write(PORT_TRIG, GPIO_TRIG, RESET);
//设置echo引脚模式为浮空输入
gpio_mode_set(PORT_ECHO, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_ECHO);
//设置引脚输出低电平
gpio_bit_write(PORT_ECHO, GPIO_ECHO, RESET);
/* 开启时钟 */
rcu_periph_clock_enable(RCU_TIMER5);
/* 将定时器时钟的频率4倍频为200MHz */
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
// 复位定时器
timer_deinit(TIMER5);
timer_initpara.period = 1000-1;//定时1ms
timer_initpara.prescaler = 200-1;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; // 分频因子
timer_initpara.alignedmode = TIMER_COUNTER_EDGE; // 边缘对齐
timer_initpara.counterdirection = TIMER_COUNTER_UP; // 向上计数
/* 在输入捕获的时候使用 数字滤波器使用的采样频率之间的分频比例 */
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; // 分频因子
/* 只有高级定时器才有 配置为 x,就重复 x+1 次进入中断 */
timer_initpara.repetitioncounter = 0; // 重复计数器 0-255
timer_init(TIMER5,&timer_initpara); // 初始化定时器
/* 配置中断优先级 */
nvic_irq_enable(TIMER5_DAC_IRQn,1,1); // 设置中断优先级为 1,1 断
/* 使能中断 */
timer_interrupt_enable(TIMER5,TIMER_INT_UP); // 使能更新事件中断
/* 使能定时器 */
timer_enable(TIMER5);
}
/******************************************************************
* 函 数 名 称:TIMER5_DAC_IRQHandler
* 函 数 说 明:定时器5的中断服务函数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:1ms中断一次
******************************************************************/
void TIMER5_DAC_IRQHandler(void)
{
static int i = 0;
if( timer_interrupt_flag_get(TIMER5, TIMER_INT_UP) != RESET )
{
msHcCount++;
timer_interrupt_flag_clear(TIMER5,TIMER_INT_UP);
}
}
/******************************************************************
* 函 数 名 称:OpenTimer
* 函 数 说 明:打开定时器
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
static void OpenTimer(void) //
{
/*清除计数器*/
timer_counter_value_config(TIMER5,0);
msHcCount = 0;
timer_enable(TIMER5);//使能定时器
}
/******************************************************************
* 函 数 名 称:CloseTimer
* 函 数 说 明:关闭定时器
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
static void CloseTimer(void)
{
/*关闭计数器使能*/
timer_disable(TIMER5);
}
/******************************************************************
* 函 数 名 称:GetEchoTimer
* 函 数 说 明:获取定时器时间
* 函 数 形 参:无
* 函 数 返 回:返回获取到的时间
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned int GetEchoTimer(void)
{
unsigned int time = 0;
/*//当回响信号很长是,计数值溢出后重复计数,overCount用中断来保存溢出次数*/
time = msHcCount*1000;//overCount每++一次,代表overCount毫秒,time微妙
time += timer_counter_read(TIMER5);//获取计TIM5数寄存器中的计数值,一边计算回响信号时间
timer_counter_value_config(TIMER5,0);//将TIM2计数寄存器的计数值清零
delay_1ms(10);
return time;
}
/******************************************************************
* 函 数 名 称:Hcsr04GetLength
* 函 数 说 明:获取测量距离
* 函 数 形 参:无
* 函 数 返 回:测量距离
* 作 者:LC
* 备 注:无
******************************************************************/
float Hcsr04GetLength(void)
{
/*测5次数据计算一次平均值*/
float length = 0;
float t = 0;
float sum = 0;
unsigned int i = 0;
while(i != 5){
gpio_bit_write(PORT_TRIG, GPIO_TRIG, SET);//trig拉高信号,发出高电平
delay_1us(20);//持续时间超过10us
gpio_bit_write(PORT_TRIG, GPIO_TRIG, RESET);//trig拉低信号,发出低电平
/*Echo发出信号 等待回响信号*/
/*输入方波后,模块会自动发射8个40KHz的声波,与此同时回波引脚(echo)端的电平会由0变为1;
(此时应该启动定时器计时);当超声波返回被模块接收到时,回波引 脚端的电平会由1变为0;
(此时应该停止定时器计数),定时器记下的这个时间即为
超声波由发射到返回的总时长;*/
while(gpio_input_bit_get(PORT_ECHO, GPIO_ECHO) == 0);//echo等待回响
/*开启定时器*/
OpenTimer();
i = i+1; //每收到一次回响信号+1,收到5次就计算均值
while(gpio_input_bit_get(PORT_ECHO, GPIO_ECHO) == 1);
/*关闭定时器*/
CloseTimer();
/*获取Echo高电平时间时间*/
t = GetEchoTimer();
length = (float)t/58;//单位时cm
sum += length;
}
length = sum/5;//五次平均值
distance = length;
return length;
}
/******************************************************************
* 函 数 名 称:Get_distance
* 函 数 说 明:返回测量后的距离;必须先采集有超声波数据
* 函 数 形 参:无
* 函 数 返 回:上一次测量过的距离
* 作 者:LC
* 备 注:无
******************************************************************/
float Get_distance(void)
{
return distance;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
在文件 bsp_ultrasonic.h 中,编写如下代码。
#ifndef _BSP_ULTRASONIC_H_
#define _BSP_ULTRASONIC_H_
#include "gd32f4xx.h"
#define RCU_TRIG RCU_GPIOC
#define PORT_TRIG GPIOC
#define GPIO_TRIG GPIO_PIN_10
#define RCU_ECHO RCU_GPIOC
#define PORT_ECHO GPIOC
#define GPIO_ECHO GPIO_PIN_11
void Ultrasonic_Init(void);//超声波初始化
float Hcsr04GetLength(void );//获取超声波测距的距离
float Get_distance(void);//获取上一次测距的距离
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2.4.4 移植验证
在自己工程中的 main 主函数中,编写如下。
/********************************************************************************
* 文 件 名: main.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2023年04月06日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "bsp_ultrasonic.h"
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
systick_config(); //滴答定时器初始化 1ms
usart_gpio_config(115200U);
Ultrasonic_Init();
printf("start\r\n");
while(1)
{
printf("distance = %.2f\r\n",Hcsr04GetLength() );
delay_1ms(1000);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
移植现象:距离 20CM 处摆放障碍物,输出换算后的实际距离。
移植成功示例,见文件 2.4.4-1 。
文件 2.4.4-1 移植成功示例