用Arduino制作一个简易超声波测距仪

用Arduino制作一个简易超声波测距仪

二月 22, 2021

目标

用Arduino UNO开发板做一个简单的超声波测距仪

成果

材料准备

材料 数量
Arduino Uno或其他类似开发板及其配套数据线 1个
杜邦线 若干
超声波测距模块(HC-SR04) 1个
四位数码管 1个
电阻 若干

括号里的是我自己使用的型号;当然,你还需要一台装有Arduino IDE的电脑。

Arduino基础

了解过Arduino的请跳过~~

Arduino怎么用?

如你所见,Arduino上有很多插孔,这个叫 I/O ,我们要做的就是通过 C++ 程序控制I/O的读取和输出。

这个C++程序怎么写?

什么?你不会C++?快去这里学习吧。。。

Arduino程序必须包含两个函数: setup()loop()

这两个函数简单来说就是先执行 setup() 函数初始化,在无限循环 loop() 函数

咳咳,还是这么解释吧:

1
2
3
4
5
6
7
8
9
10
11
12
void setup();
void loop();

int main() {
setup();

for(;;) {
loop();
}

return 0;
}

超声波测距模块

分析工作原理

由于各个型号的模块针脚可能不同,请查看相关文档,这里我根据我使用的HC-SR04介绍。

HC-SR04

采用IO触发测距,给至少10us的高电平信号。模块自动发送8个40khz的方波,自动检测是否有信号返回。有信号返回,通过IO输出一高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340m/s))/2

文档

一个完整的测距过程

  1. GND 接Arduino的 GNDVCC 接Arduino的 5V

下面开始测距:

  1. Trig 一个至少10微秒的脉冲
  2. 监听输出端口并开始计时
  3. 当输出端口出现高电平时计时结束
  4. 根据声速计算距离

代码

首先,为了接线方便,超声波测距模块连Arduino的 A2 ~ A5 引脚。

1
2
3
4
#define GND A2
#define ECHO A3
#define TRIG A4
#define VCC A5

setup() 函数里我们初始化引脚

1
2
3
4
5
6
7
8
9
10
void setup() {
// …………
pinMode(GND, OUTPUT); // 输出 0V 电压
pinMode(VCC, OUTPUT); // 输出 5V 电压
pinMode(TRIG, OUTPUT); // 输出 控制信号
pinMOde(ECHO, INPUT); // 输入端
// …………
digitalWrite(VCC, HIGH); // VCC 5V 高电平
digitalWrite(GND, LOW); // GND 低电平
}

还记得上面的步骤吗?

loop() 里我们先将 Trig 设为高电平( digitalWrite(TRIG, HIGH); ),50微秒后变回低电平,也就是形成一个50微秒的脉冲

再调用Arduino库函数 pulseln() ,这个函数等待一个端口变为高电平并开始计时,再变为低电平时停止计时,并返回时间间隔(单位为微秒)

最后计算距离

代码如下:

1
2
3
4
5
6
7
8
void loop() {
digitalWrite(TRIG, HIGH); // 先将 `Trig` 设为高电平
delayMicroseconds(50); // 等待 50 微秒
digitalWrite(TRIG, LOW); // 先将 `Trig` 设为低电平
double time = double(pulseIn(ECHO, HIGH)) / 1000000; // 保存以秒为单位的时间间隔

show(time * 340 / 2); // 将计算结果传递给 `show()` 函数,这个函数的实现在后面
}

四位数码管

分析工作原理

我用的是共阴数码管,原理图如下:

数码管原理图

可以看到,当12低电平时,其他引脚控制第一个数字,当9为低电平时,其他引脚控制第一个数字,以此类推。

注意!要在 12 , 9 , 8 , 6 四个引脚分别串联一个合适阻值的电阻,具体阻值要看数码管的工作电压。

如下表:

数字 高电平的引脚
0 ABCDEF
1 BC
2 ABDEG
3 ABCDG
4 BCFG
5 ACDFG
6 ACDEFG
7 ABC
8 ABCDEFG
9 ABCDFG

代码

为了用字母而不是数字表示引脚,可以在程序的开头定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define l1 13 // Arduino 的 13 号引脚 连数码管的 12 号引脚
#define l2 12 // Arduino 的 12 号引脚 连数码管的 9 号引脚
#define l3 11 // Arduino 的 11 号引脚 连数码管的 8 号引脚
#define l4 2 // Arduino 的 2 号引脚 连数码管的 6 号引脚
#define la 10 // Arduino 的 10 号引脚 连数码管的 11 号引脚
#define lb 8 // Arduino 的 8 号引脚 连数码管的 7 号引脚
#define lc 4 // Arduino 的 4 号引脚 连数码管的 4 号引脚
#define ld 6 // Arduino 的 6 号引脚 连数码管的 2 号引脚
#define le 7 // Arduino 的 7 号引脚 连数码管的 1 号引脚
#define lf 9 // Arduino 的 9 号引脚 连数码管的 10 号引脚
#define lg 3 // Arduino 的 3 号引脚 连数码管的 5 号引脚
#define ldp 5 // Arduino 的 5 号引脚 连数码管的 3 号引脚

#define DELAY 5 // 用于控制每次测量的间隔

初始化引脚

1
2
3
4
5
6
void setup() {
for (int i = 2; i < 14; i++) {
pinMode(i, OUTPUT);
}
// …………
}

封装每个数字为函数

1
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
void flush() {
digitalWrite(la, LOW);
digitalWrite(lb, LOW);
digitalWrite(lc, LOW);
digitalWrite(ld, LOW);
digitalWrite(le, LOW);
digitalWrite(lf, LOW);
digitalWrite(lg, LOW);
digitalWrite(ldp, LOW);
}

void show_num(int num) {
switch (num) {
case 0:
_show_0();
break;
case 1:
_show_1();
break;
case 2:
_show_2();
break;
case 3:
_show_3();
break;
case 4:
_show_4();
break;
case 5:
_show_5();
break;
case 6:
_show_6();
break;
case 7:
_show_7();
break;
case 8:
_show_8();
break;
case 9:
_show_9();
break;
default:
break;
}
}

void _show_0() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(le, HIGH);
digitalWrite(lf, HIGH);
}

void _show_1() {
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
}

void _show_2() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(le, HIGH);
}

void _show_3() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(lc, HIGH);
}

void _show_4() {
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
}

void _show_5() {
digitalWrite(la, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
}

void _show_6() {
digitalWrite(la, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(le, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(lg, HIGH);
}

void _show_7() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
}

void _show_8() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(le, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
}

void _show_9() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
}

注意!

我们要显示的是XX.XX米,其中第二个小数点要正确显示,我们写一个函数,接受一个小于10000的正整数,如344,显示为03.44(米)。所以前面调用 show() 的时候传入的参数应该乘100

1
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
void show(int num) {
// 一次测量结果显示 300 / DELAY 秒。
for (int i = 0; i < 300 / DELAY; i++) {
int tmp = num;
int j;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(l4, LOW);
delay(DELAY);
digitalWrite(l4, HIGH);
tmp -= j;
tmp /= 10;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(l3, LOW);
delay(DELAY);
digitalWrite(l3, HIGH);
tmp -= j;
tmp /= 10;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(ldp, HIGH);
digitalWrite(l2, LOW);
delay(DELAY);
digitalWrite(l2, HIGH);
tmp -= j;
tmp /= 10;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(l1, LOW);
delay(DELAY);
digitalWrite(l1, HIGH);
}
}

全部代码

1
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
#define l1 13
#define l2 12
#define l3 11
#define l4 2
#define la 10
#define lb 8
#define lc 4
#define ld 6
#define le 7
#define lf 9
#define lg 3
#define ldp 5

#define GND A2
#define ECHO A3
#define TRIG A4
#define VCC A5

#define DELAY 5

void setup() {
for (int i = 2; i < 14; i++) {
pinMode(i, OUTPUT);
}

pinMode(GND, OUTPUT);
pinMode(VCC, OUTPUT);
pinMode(TRIG, OUTPUT);
pinMOde(ECHO, INPUT);

digitalWrite(VCC, HIGH);
digitalWrite(GND, LOW);
}

void loop() {
digitalWrite(TRIG, LOW);
delayMicroseconds(5);
digitalWrite(TRIG, HIGH);
delayMicroseconds(50);
digitalWrite(TRIG, LOW);

double time = double(pulseIn(ECHO, HIGH)) / 10000;

show(int(time * 340 / 2));
}

void show(int num) {
for (int i = 0; i < 300 / DELAY; i++) {
int tmp = num;
int j;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(l4, LOW);
delay(DELAY);
digitalWrite(l4, HIGH);
tmp -= j;
tmp /= 10;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(l3, LOW);
delay(DELAY);
digitalWrite(l3, HIGH);
tmp -= j;
tmp /= 10;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(ldp, HIGH);
digitalWrite(l2, LOW);
delay(DELAY);
digitalWrite(l2, HIGH);
tmp -= j;
tmp /= 10;

flush();
j = tmp % 10;
show_num(j);
digitalWrite(l1, LOW);
delay(DELAY);
digitalWrite(l1, HIGH);
}
}

void flush() {
digitalWrite(la, LOW);
digitalWrite(lb, LOW);
digitalWrite(lc, LOW);
digitalWrite(ld, LOW);
digitalWrite(le, LOW);
digitalWrite(lf, LOW);
digitalWrite(lg, LOW);
digitalWrite(ldp, LOW);
}

void show_num(int num) {
switch (num)
{
case 0:
_show_0();
break;
case 1:
_show_1();
break;
case 2:
_show_2();
break;
case 3:
_show_3();
break;
case 4:
_show_4();
break;
case 5:
_show_5();
break;
case 6:
_show_6();
break;
case 7:
_show_7();
break;
case 8:
_show_8();
break;
case 9:
_show_9();
break;
default:
break;
}
}

void _show_1() {
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
}
void _show_2() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(le, HIGH);
}
void _show_3() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(lc, HIGH);
}
void _show_4() {
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
}
void _show_5() {
digitalWrite(la, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
}
void _show_6() {
digitalWrite(la, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(le, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(lg, HIGH);
}
void _show_7() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
}
void _show_8() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(le, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
}
void _show_9() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(lf, HIGH);
digitalWrite(lg, HIGH);
}
void _show_0() {
digitalWrite(la, HIGH);
digitalWrite(lb, HIGH);
digitalWrite(lc, HIGH);
digitalWrite(ld, HIGH);
digitalWrite(le, HIGH);
digitalWrite(lf, HIGH);
}

接线

前面其实都已经讲过了,这里再复述一遍:

Arduino引脚 四位数码管引脚 超声波测距仪引脚
A2 GND
A3 ECHO
A4 TRIG
A5 VCC
3 5
4 4
5 3
6 2
7 1
8 7
9 10
10 11
11 8
12 9
13 12

完成!

我已经成功了,你也快去试试吧~~

完成!