跳到主要内容

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

· 阅读需 12 分钟
Skyone
科技爱好者

最近学着玩了一下Arduino,今天下午抽时间试着拿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() 函数

咳咳,还是这么解释吧:

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 引脚。

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

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

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() ,这个函数等待一个端口变为高电平并开始计时,再变为低电平时停止计时,并返回时间间隔(单位为微秒)

最后计算距离

代码如下:

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 四个引脚分别串联一个合适阻值的电阻,具体阻值要看数码管的工作电压。

如下表:

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

代码

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

#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 // 用于控制每次测量的间隔

初始化引脚

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

封装每个数字为函数

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

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);
}
}

全部代码

#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引脚四位数码管引脚超声波测距仪引脚
A2GND
A3ECHO
A4TRIG
A5VCC
35
44
53
62
71
87
910
1011
118
129
1312

完成!

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

成果