Skip to content

第 10 章:看懂超声波测距代码

本章任务

看懂"HC-SR04 超声波测距"的 Arduino C++ 代码——对应第一册第 10 章的实验,和第二册第 10 章是同一个任务。

接线回顾

HC-SR04Pico说明
VCC3V33.3V 供电
TrigGP16触发信号输出
EchoGP17回波信号输入(需分压
GNDGND共地

电平注意:Echo 输出 5V 电平,Pico 只耐受 3.3V。分压电路:Echo → 1kΩ → GP17,GP17 → 2kΩ → GND。

Mind+ 生成的典型代码

cpp
const int TRIG_PIN = 16;   // 触发脚接 GP16
const int ECHO_PIN = 17;   // 回波脚接 GP17

void setup() {
  Serial.begin(115200);          // 打开串口,准备打印距离
  pinMode(TRIG_PIN, OUTPUT);     // 触发脚是"输出":Pico 发信号给传感器
  pinMode(ECHO_PIN, INPUT);      // 回波脚是"输入":Pico 听传感器的回答
}

float measureDistance() {        // 自定义函数:测一次距离,返回厘米数
  // 第一步:发出 10 微秒的触发脉冲,告诉传感器"开始测"
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);         // 高电平保持 10 微秒
  digitalWrite(TRIG_PIN, LOW);

  // 第二步:测量 Echo 脚高电平持续了多久(单位:微秒)
  long duration = pulseIn(ECHO_PIN, HIGH);

  // 第三步:距离 = 时间 × 声速 ÷ 2(声音走了来回,所以除以 2)
  float distance = duration * 0.0343 / 2;
  return distance;               // 把结果交出去
}

void loop() {
  float d = measureDistance();   // 调用函数,测一次
  Serial.print("距离:");
  Serial.print(d);
  Serial.println(" cm");         // 打印"距离:xx.xx cm"
  delay(1000);                   // 每秒测一次
}

代码讲解

这段代码比前面几章长,但拆开看就是三步:发触发信号 → 听回波 → 算距离

  • pulseIn(ECHO_PIN, HIGH):等 Echo 脚变高电平,并测量高电平持续的微秒数。Python 版要用两个 while 循环加 ticks_us 才能干完的事,C++ 里这一个函数就包了
  • delayMicroseconds(10):微秒级延时,对应 Python 的 time.sleep_us(10)。1 毫秒 = 1000 微秒
  • 换算公式和第二册完全一致:距离(cm) = 高电平时间(μs) × 0.0343 ÷ 2(0.0343 是声速 343 米/秒换算来的)
  • measureDistance() 是自定义函数:loop() 里写一句 float d = measureDistance(); 就能拿到距离,复杂的细节都藏在函数里——这就是第 6 章讲的函数的实际用处

运行效果

串口监视器每秒打印一次距离,手在传感器前移动,数值跟着变化。

常见坑

  • 读数始终是 0:检查代码里 Trig / Echo 的 GP 编号有没有写反;检查分压电阻接没接对
  • 读数跳变大:对准平整的墙面测,斜面、海绵、布料都会吸收或乱反射声波
  • 串口乱码:串口监视器波特率要设为 115200,和 Serial.begin(115200) 一致
  • duration 用的是 long 类型(能装更大的整数),别写成 int——微秒数可能超过 int 的舒适区

想一想

  1. 想让"距离小于 20cm 时打印警告",应该在 loop() 里加什么?(提示:第 4 章的 if

    💡 查看答案

    在测出距离 d 之后加一个 if

    cpp
    void loop() {
      float d = measureDistance();
      if (d < 20) {
        Serial.println("⚠️ 警告:太近了!");
      }
      // ……原来的打印和延时
    }
  2. pulseIn 还有个可选参数 timeout(超时时间)。如果传感器面前什么都没有,Echo 一直不变高,pulseIn 会一直等下去吗?查一查它默认等多久

    💡 查看答案

    不会一直等。pulseIn 默认最多等 1 秒(1000000 微秒),超时还没等到就返回 0。所以看到读数是 0,往往说明没收到回波——没对准、没接好,或者超量程了。

  3. 对比第二册第 10 章的 Python 版:为什么 Python 要自己数时间,C++ 却有现成的 pulseIn

    💡 查看答案

    这是两种生态的风格差异:Arduino 发展了二十多年,常用功能(测脉冲、控舵机……)都有人封装成了现成函数;MicroPython 偏教学,把底层过程暴露出来让人看清楚。看到 Python 版"手动掐表",正是理解 pulseIn 内部原理的好机会。

不积跬步,无以至千里;万里之行,始于当下。