深色模式
第 10 章:看懂超声波测距代码
本章任务
看懂"HC-SR04 超声波测距"的 Arduino C++ 代码——对应第一册第 10 章的实验,和第二册第 10 章是同一个任务。
接线回顾
| HC-SR04 | Pico | 说明 |
|---|---|---|
| VCC | 3V3 | 3.3V 供电 |
| Trig | GP16 | 触发信号输出 |
| Echo | GP17 | 回波信号输入(需分压) |
| GND | GND | 共地 |
电平注意: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 的舒适区
想一想
想让"距离小于 20cm 时打印警告",应该在
loop()里加什么?(提示:第 4 章的if)💡 查看答案
在测出距离
d之后加一个if:cppvoid loop() { float d = measureDistance(); if (d < 20) { Serial.println("⚠️ 警告:太近了!"); } // ……原来的打印和延时 }pulseIn还有个可选参数timeout(超时时间)。如果传感器面前什么都没有,Echo 一直不变高,pulseIn会一直等下去吗?查一查它默认等多久💡 查看答案
不会一直等。
pulseIn默认最多等 1 秒(1000000 微秒),超时还没等到就返回 0。所以看到读数是 0,往往说明没收到回波——没对准、没接好,或者超量程了。对比第二册第 10 章的 Python 版:为什么 Python 要自己数时间,C++ 却有现成的
pulseIn?💡 查看答案
这是两种生态的风格差异:Arduino 发展了二十多年,常用功能(测脉冲、控舵机……)都有人封装成了现成函数;MicroPython 偏教学,把底层过程暴露出来让人看清楚。看到 Python 版"手动掐表",正是理解
pulseIn内部原理的好机会。
