Logo
“用Arduino制作简易超声波测距仪”的封面

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

Avatar

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

完成!

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

成果


隐私政策

Copyright © Skyone 2025