一、模块来源
采购链接:
HC-SR04 超声波测距模块 宽电压3-5.5V 工业级 传感器
资料下载链接:
https://pan.baidu.com/s/1sSah9PvLBrmbA7So-6YcSw
资料提取码:qq35
二、规格参数
工作电压:3-5.5V
工作电流:5.3MA
感应角度:小于15度
探测距离:2CM-600CM
探测精度:0.1CM+1%
输出方式: GPIO
管脚数量:4 Pin
以上信息见厂家资料文件
三、移植过程
我们的目标是将例程移植至MSPM0G3507开发板上【能够判断前方障碍物距离的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
1、查看资料
只需要在 Trig 管脚(触发信号)输入一个 10US 以上的高电平,系统便可发出 8 个 40KHZ 的超声波脉冲,然后检测回波信号。当检测到回波信号后,通过 Echo 管脚输出。根据 Echo 管脚输出高电平的持续时间可以计算距离值。即距离值为:(高电平时间*340m/s)/2。
当测量距离超过 HC-SR04 的测量范围时,仍会通过 Echo管脚输出高电平的信号,高电平的宽度约为 66ms。如图所示:
测量周期:当接收到 HC-SR04 通过 Echo 管脚输出的高电平脉冲后,便可进行下一次测量,所以测量周期取决于测量距离,当距离被测物体很近时,Echo 返回的脉冲宽度较窄,测量周期 就很短;当距离被测物体比较远时,Echo 返回的脉冲宽度较宽,测量周期也就相应的变长。最坏情况下,被测物体超出超声波模块的测量范围,此时 返回的脉冲宽度最长,约为 66ms,所以最坏情况下的测量周期稍大于 66ms 即可(取 70ms 足够)。
2、引脚选择
VCC | 3V3 |
Trig | PA2 |
Echo | PA3 |
GND | GND |
3、代码编写
新建两个文件 bsp_sr04.c
和 bsp_sr04.h
,并且将头文件路径添加到编译器中。
在文件 bsp_sr04.c
和 bsp_sr04.h
中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef BSP_CODE_BSP_SR04_H_
#define BSP_CODE_BSP_SR04_H_
#include "gd32vw55x.h"
#include "systick.h"
#ifndef u8
#define u8 uint8_t
#endif
#ifndef u16
#define u16 uint16_t
#endif
#ifndef u32
#define u32 uint32_t
#endif
#ifndef delay_ms
#define delay_ms(x) delay_1ms(x)
#endif
#ifndef delay_us
#define delay_us(x) delay_1us(x)
#endif
#define SR04_Trig_GPIO_RCU RCU_GPIOA
#define SR04_Echo_GPIO_RCU RCU_GPIOA
#define SR04_Trig_GPIO_PORT GPIOA
#define SR04_Echo_GPIO_PORT GPIOA
#define SR04_Trig_GPIO_PIN GPIO_PIN_2
#define SR04_Echo_GPIO_PIN GPIO_PIN_3
/* 外部中断 */
#define SR04_Echo_EXTI_LINE EXTI_3
#define SR04_Echo_EXTI_IRQn EXTI3_IRQn
#define SR04_Echo_EXTI_PORT_SOURCE EXTI_SOURCE_GPIOA
#define SR04_Echo_EXTI_PIN_SOURCE EXTI_SOURCE_PIN3
#define SR04_Echo_EXTI_IRQHandler EXTI3_IRQHandler
/* 定时器 */
#define SR04_Timer_RCU RCU_TIMER5
#define SR04_Timer TIMER5
#define SR04_Timer_IRQn TIMER5_IRQn
#define SR04_Timer_IRQHandler TIMER5_IRQHandler
#define SR04_Module_CLK_ENABLE() \
rcu_periph_clock_enable(SR04_Trig_GPIO_RCU); \
rcu_periph_clock_enable(SR04_Echo_GPIO_RCU); \
rcu_periph_clock_enable(SR04_Timer_RCU);
#define SR04_TRIG(x) gpio_bit_write(SR04_Trig_GPIO_PORT, SR04_Trig_GPIO_PIN, x)
#define SR04_ECHO() gpio_input_bit_get(SR04_Echo_GPIO_PORT, SR04_Echo_GPIO_PIN)
void SR04_Init(void);//超声波初始化
float SR04_GetLength(void );//获取超声波测距的距离
#endif /* BSP_CODE_BSP_SR04_H_ */
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
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include "bsp_sr04.h"
volatile uint32_t msHcCount = 0; // ms计数
float Distance_DAT = 0;
uint8_t SR04_Flag = 0; // SR04测距标志位
/******************************************************************
* 函 数 名 称:SR04_Init
* 函 数 说 明:初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:
******************************************************************/
void SR04_Init(void)
{
SR04_Module_CLK_ENABLE(); // 使能时钟
// trig引脚配置
gpio_mode_set(SR04_Trig_GPIO_PORT,
GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE,
SR04_Trig_GPIO_PIN);
gpio_output_options_set(SR04_Trig_GPIO_PORT,
GPIO_OTYPE_PP,
GPIO_OSPEED_MAX,
SR04_Trig_GPIO_PIN);
SR04_TRIG(0); // trig拉低信号,默认状态
// echo引脚配置
gpio_mode_set(SR04_Echo_GPIO_PORT,
GPIO_MODE_INPUT,
GPIO_PUPD_NONE,
SR04_Echo_GPIO_PIN);
// 外部中断配置
eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL2_PRIO2);
eclic_irq_enable(SR04_Echo_EXTI_IRQn, 1, 1);
syscfg_exti_line_config(SR04_Echo_EXTI_PORT_SOURCE, SR04_Echo_EXTI_PIN_SOURCE);
exti_init(SR04_Echo_EXTI_LINE, EXTI_INTERRUPT, EXTI_TRIG_BOTH);
exti_interrupt_enable(SR04_Echo_EXTI_LINE);
exti_interrupt_flag_clear(SR04_Echo_EXTI_LINE);
// 定时器配置
timer_parameter_struct timer_initpara; // 定义定时器结构体
/* CK_TIMERx = 2 x CK_APB1 = 2x80M = 160MHZ */
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL2);// 配置定时器时钟
timer_deinit(SR04_Timer); // 复位定时器
/* 配置定时器参数 */
timer_initpara.prescaler = 160 -1; // 时钟预分频值 0-65535 psc_clk = CK_TIMER / pre
timer_initpara.alignedmode = TIMER_COUNTER_EDGE; // 边缘对齐
timer_initpara.counterdirection = TIMER_COUNTER_UP; // 向上计数
timer_initpara.period = 1000 - 1; // 周期
/* 在输入捕获的时候使用 数字滤波器使用的采样频率之间的分频比例 */
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; // 分频因子
/* 只有高级定时器才有 配置为x,就重复x+1次进入中断 */
timer_initpara.repetitioncounter = 0; // 重复计数器 0-255
timer_init(SR04_Timer, &timer_initpara); // 初始化定时器
eclic_irq_enable(SR04_Timer_IRQn,2,2); // 设置中断优先级为 2,2断
/* 使能中断 */
timer_interrupt_enable(SR04_Timer, TIMER_INT_UP); // 使能更新事件中断
msHcCount = 0;
Distance_DAT = 0.0f; // 清零距离
}
/******************************************************************
* 函 数 名 称:Open_Timer
* 函 数 说 明:打开定时器
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:
******************************************************************/
void Open_Timer(void)
{
msHcCount = 0;
timer_counter_value_config(SR04_Timer, 0); // 重载定时器计数
timer_enable(SR04_Timer); /* 使能定时器 */
}
/******************************************************************
* 函 数 名 称:Get_TIMER_Count
* 函 数 说 明:获取定时器定时时间
* 函 数 形 参:无
* 函 数 返 回:数据
* 作 者:LCKFB
* 备 注:
******************************************************************/
uint32_t Get_TIMER_Count(void)
{
uint32_t time = (msHcCount * 1000) + timer_counter_read(SR04_Timer); // 得到us
timer_counter_value_config(SR04_Timer, 0); // 重载定时器计数
delay_1ms(10);
return time ;
}
/******************************************************************
* 函 数 名 称:Close_Timer
* 函 数 说 明:关闭定时器
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:
******************************************************************/
void Close_Timer(void)
{
timer_disable(SR04_Timer);; // 关闭定时器
}
/******************************************************************
* 函 数 名 称:SR04_GetLength
* 函 数 说 明:获取测量距离
* 函 数 形 参:无
* 函 数 返 回:测量距离
* 作 者:LCKFB
* 备 注:无
******************************************************************/
float SR04_GetLength(void)
{
/*测5次数据计算一次平均值*/
float length = 0;
float t = 0;
float sum = 0;
int i = 0;
int j = 0;
float distances[5] = {0}; // 用于存储测量结果
while(i != 5)
{
SR04_TRIG(1);//trig拉高信号,发出高电平
delay_1us(20);//持续时间超过10us
SR04_TRIG(0);//trig拉低信号,发出低电平
/*Echo发出信号 等待回响信号*/
/*输入方波后,模块会自动发射8个40KHz的声波,与此同时回波引脚(echo)端的电平会由0变为1;
(此时应该启动定时器计时);当超声波返回被模块接收到时,回波引 脚端的电平会由1变为0;
(此时应该停止定时器计数),定时器记下的这个时间即为
超声波由发射到返回的总时长;*/
SR04_Flag = 0; // 清除标志位
while(SR04_Flag == 1);
/*获取Echo高电平时间时间*/
t = Get_TIMER_Count();
distances[i++] = (float)t/58;//单位时cm
}
// 排序以便去除最高值和最低值
for (i = 0,j = 0; i < 5 - 1; i++)
{
for (j = i + 1; j < 5; j++)
{
if (distances[i] > distances[j])
{
float temp = distances[i];
distances[i] = distances[j];
distances[j] = temp;
}
}
}
// 计算去掉最高值和最低值后的平均值
for (i = 1; i < 5 - 1; i++)
{
sum += distances[i];
}
Distance_DAT = sum / 3; // 返回中间值的平均值
return Distance_DAT;
}
// 外部中断服务函数
void SR04_Echo_EXTI_IRQHandler(void)
{
if(exti_interrupt_flag_get(SR04_Echo_EXTI_LINE) == SET)
{
if(gpio_input_bit_get(SR04_Echo_GPIO_PORT,SR04_Echo_GPIO_PIN) == SET)
{
SR04_Flag = 0;
Open_Timer(); //打开定时器
}
else // RESET
{
Close_Timer(); // 关闭定时器
SR04_Flag = 1;
}
exti_interrupt_flag_clear(SR04_Echo_EXTI_LINE);
}
}
void SR04_Timer_IRQHandler(void)
{
if(timer_interrupt_flag_get(SR04_Timer, TIMER_INT_UP) == SET)
{
msHcCount++; // 每次中断计数加1
timer_interrupt_flag_clear(SR04_Timer, TIMER_INT_UP); // 清除中断标志
}
}
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
四、移植验证
在 src\main.c
中输入代码如下:
#include "gd32vw55x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "gd32vw553h_eval.h"
#include "bsp_sr04.h"
/*!
\brief toggle the led every 500ms
\param[in] none
\param[out] none
\retval none
*/
void led_spark(void)
{
static __IO uint32_t timingdelaylocal = 0U;
if(timingdelaylocal) {
if(timingdelaylocal < 500U) {
gd_eval_led_on(LED1);
} else {
gd_eval_led_off(LED1);
}
timingdelaylocal--;
} else {
timingdelaylocal = 1000U;
}
}
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
#ifdef __FIRMWARE_VERSION_DEFINE
uint32_t fw_ver = 0;
#endif /* __FIRMWARE_VERSION_DEFINE */
/* configure systick */
systick_config();
eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL3_PRIO1);
/* initilize the LEDs, USART and key */
gd_eval_led_init(LED1);
gd_eval_com_init(EVAL_COM0);
gd_eval_key_init(KEY_TAMPER_WAKEUP, KEY_MODE_GPIO);
#ifdef __FIRMWARE_VERSION_DEFINE
fw_ver = gd32vw55x_firmware_version_get();
printf("\r\n= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\r\n\n");
printf("\r\n=== Welcome to use the LC-GD32VW553-HMQ6 development board ====\r\n\n");
printf("\r\n======================= www.lckfb.com =========================\r\n\n");
printf("\r\n======================= wiki.lckfb.com ========================\r\n\n");
printf("\r\n= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\r\n");
/* print firmware version */
printf("\r\nGD32VW55X series firmware version: V%d.%d.%d", (uint8_t)(fw_ver >> 24), (uint8_t)(fw_ver >> 16), (uint8_t)(fw_ver >> 8));
#endif /* __FIRMWARE_VERSION_DEFINE */
/* print out the clock frequency of system, AHB, APB1 and APB2 */
printf("\r\nCK_SYS is %d\r\n", rcu_clock_freq_get(CK_SYS));
printf("\r\nCK_AHB is %d\r\n", rcu_clock_freq_get(CK_AHB));
printf("\r\nCK_APB1 is %d\r\n", rcu_clock_freq_get(CK_APB1));
printf("\r\nCK_APB2 is %d\r\n", rcu_clock_freq_get(CK_APB2));
SR04_Init();
printf("\r\nSR04 ultrasonic ranging sensor initialized.\r\n");
while(1)
{
printf("Distance: %.2f cm\r\n", SR04_GetLength());
delay_1ms(500); // 延时500ms
}
}
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
上电效果:距离障碍物20CM
【代码下载】
- 跳转到
下载中心
去下载模块移植代码:【点击跳转🚀】