超声波测距

Tutorial: 卓越工程师 Category: 嵌入式 Published: 2026-10-23 11:05:29 Views: 1 Likes: 0 Comments: 0

289.7.超声波测距

#define Echo 13                    // 将 ESP32-CAM 的 GPIO13 命名为 Echo,读取模块的回波脉冲。
#define Trig 15                    // 将 GPIO15 命名为 Trig,向模块发送测量触发脉冲。

long gettime()                    // 定义课堂上的测量函数,返回回波高电平持续时间;不是返回距离。
{                                 // 开始 gettime 函数。
    digitalWrite(Trig,HIGH);      // 将 Trig 拉高,开始一次触发脉冲。
    delayMicroseconds(10);        // 保持高电平 10 微秒。
    digitalWrite(Trig,LOW);       // 将 Trig 拉低,结束触发脉冲。
    return pulseIn(Echo,HIGH);    // 等待并测量 Echo 的高电平宽度,以微秒为单位返回。
}                                 // gettime 函数结束。

void setup() {                    // 定义 Arduino 上电或复位后执行一次的初始化函数。
    pinMode(Echo,INPUT);          // 将连接 Echo 的 GPIO13 配成输入,以接收模块输出。
    pinMode(Trig,OUTPUT);         // 将连接 Trig 的 GPIO15 配成输出,以发送触发脉冲。
    Serial.begin(115200);         // 以 115200 bit/s 初始化串口,供串口监视器查看结果。
}                                 // 初始化结束。

void loop() {                     // 定义 Arduino 反复执行的主循环。
    long dis=gettime()/58;        // 将返回的微秒数按课堂近似系数换成整数厘米。
    Serial.println(dis);          // 每测一次就向串口打印一次整数距离并换行。
}                                 // 本轮结束;程序马上开始下一轮测量。

一、采用超声波测距模块进行测距

本节在 AI Thinker ESP32-CAM 上使用视频展示的 HC-SR04 外形模块测距。上方代码逐字保留视频最终草图的业务语句与命名,只删除原注释、增加逐行解释;没有替课堂补写延时、超时、电平转换代码或任何库内部实现。原笔记中的“ESP3CAN”“defy”“log”“Tree le”“E 口”等属于识别错误,分别应理解为 ESP32-CAM、#define、long、Trig、Echo。尤其要把课堂接法与常见 HC-SR04 的额定电压分开,后文详细说明。

1.1 超声波测距模块原理

  • 模块正面的两个圆形金属网罩是两个超声波换能器,一般一个发出约 40 kHz 的声波,另一个接收反射回来的声波;它们不是开发板上可直接读取的两个“网格引脚”。模块背面的电路负责激励发射、识别回波,再通过 Echo 数字输出引脚把计时信息交给 ESP32-CAM。不同照片可能左右镜像,不能单凭“左边一定发射”判断接线,应以板上 VCC/Trig/Echo/GND 丝印为准。
  • 一次测量的时序是:ESP32-CAM 在 Trig 线上送出约 10 μs 高电平 → 模块发出一串 8 个、40 kHz 的超声波周期 → 声波碰到物体反射 → 模块在 Echo 线上输出与往返声程有关的高电平脉冲 → ESP32-CAM 测该脉冲的宽度。40 kHz 是声波振动频率,不是每秒应发起 4 万次测量。ElecFreaks HC-SR04 资料给出了触发、8 周期声波和 Echo 脉宽关系。
  • Echo 高电平持续时间记作 t,它代表声波去程加回程对应的时间。距离物体的单程距离为 d = v × t / 2,v 是空气中的声速,除以 2 是因为声音走了两倍目标距离。它不是“读取接收网罩自身的高电平”,也不是只算去程时间。声速与温度等条件有关,所以算出的距离是估计值,不是绝对精确值。
  • pulseIn(Echo,HIGH) 用于等待 Echo 上的一个完整高电平脉冲并返回微秒数,PPT 把返回单位写成 ms(毫秒)是错的;如果在默认约 1 秒超时内没有取得完整脉冲,它返回 0。本节代码没有区分“0 表示没测到”与“真的距离接近 0”,因此看到串口 0 时应先检查接线、供电、物体和超时,而不是认定物体贴着探头。Arduino 官方 pulseIn() 说明。

1.2 定义超声波引脚

  • 常见四线 HC-SR04 实际有 4 个外接引脚:VCC(模块供电正极)、GND(电源负极与信号参考地)、Trig(模块的触发输入)、Echo(模块的回波输出)。原笔记的“两个引脚”只能理解为两根信号线,不能遗漏电源和地。方向要站在模块角度看:ESP32 的输出接 Trig,ESP32 的输入接 Echo。
  • 视频草图明确写 #define Echo 13、#define Trig 15,因此实际应是 模块 Echo → ESP32-CAM GPIO13、模块 Trig → ESP32-CAM GPIO15。宏名 Echo/Trig 在编译前分别替换成引脚数字;数字 13/15 是 GPIO 编号,不是排针的第 13/15 个孔位。原笔记“发送脚 15、接收脚 13”是对的,但 1.6 节末尾写成“Trig 接 13、Echo 接 15”与视频代码相反,必须更正。
  • 视频打开的 ESP32-CAM 引脚图能看到 GPIO13、GPIO15 的位置,旁边还标了 HS2_DATA3、HS2_CMD 等复用功能:如果以后使用 microSD 卡的相应总线接法,这些引脚可能与 SD 功能冲突。GPIO15 也是 ESP32 的启动配置脚之一,外接电路若在复位时强行改变其电平,可能改变启动日志行为;复用/启动限制应按实物板型与原理图再次核对,不能把图上的编号当作永远无条件可用的“普通排针”。Espressif GPIO/启动脚说明。

1.3 定义超声波测距函数

1.3.1 高电平信号
  • 视频定义的是 long gettime(),long 为整数类型,不是原笔记的 log,也不是专门保存许多小数位的类型;gettime() 返回的是时间,不是“已经算好的距离”。Arduino 的 pulseIn() 本身返回无符号整数微秒数,视频函数再把它作为 long 返回;本课测距时间远小于一般 32 位 long 可表示的范围。真正的距离换算发生在 loop() 中的 /58。
  • digitalWrite(Trig,HIGH) 使 Trig 变高,delayMicroseconds(10) 使它保持约 10 μs,再 digitalWrite(Trig,LOW) 将其拉低。视频用 10,没有做额外的预置低电平步骤;精校稿因此只解释这三条实际代码,不自行补写另一版触发流程。所谓“至少 10 微秒”是Trig 触发输入的要求,绝不是让 Echo 高电平维持 10 μs;Echo 的宽度由模块检测回波后输出。
1.3.2 高电平信号延迟
  • delayMicroseconds(10) 单位为微秒,10 μs = 0.01 ms。它是发起测量的触发脉冲宽度,不是“等声波飞行 10 μs”。模块之后自动发射 8 周期、40 kHz 的超声波;一周期是 1/40 000 s = 25 μs,8 周期发射本身约 200 μs,因此也不能把“8 次声波”误认为 Trig 上连续输出的 8 个电脉冲。
  • pulseIn(Echo,HIGH) 中的 HIGH 表示测高电平脉宽。函数先等待符合条件的脉冲,计时直到它回到低电平;没有返回有效完整脉冲时给 0。它是同步等待调用,本例 loop() 在等待期间不会执行后面的 Serial.println()。视频代码没有给 pulseIn() 自定义更短的 timeout,默认等待可能显著拖慢异常情况下的打印。Arduino 官方说明。
  • 教材所说“函数已经封装完成”仅指它把触发和计时包装成 gettime();后面还必须配置引脚、换算单位并打印。不要把返回值当成摄像头画面中的物体识别结果:这类传感器只能估计它前方反射面的距离,不能辨认物体是什么。

1.4 初始化定义

  • pinMode(Echo,INPUT) 让 GPIO13 接收模块的回波电平;pinMode(Trig,OUTPUT) 让 GPIO15 输出触发电平。这与信号流一一对应:ESP32 → Trig → 模块声波 → 物体 → 模块 Echo → ESP32。INPUT、OUTPUT 是英文常量,不能写成原笔记识别出的 Tree le 一类词。
  • Serial.begin(115200) 把串口速率设为 115200 bit/s;串口监视器需选相同速率,才能正常看见后续打印。复位后可能先出现芯片的启动日志,不等于测距代码输出;本节业务输出是 Serial.println(dis) 打印的一行行数字。
  • loop() 中 long dis=gettime()/58; 用整数变量保存“厘米”的近似数值。因为 gettime() 和 58 都是整数,整数除法直接舍去小数部分:例如回波宽度为 580 μs 时显示 10,若为 609 μs 仍显示 10,不会显示 10.5。原笔记称“为保存很多小数位选 long”与实际代码正好相反。

1.5 超声波模块测距原理

  • 用课堂 PPT 的约 343 m/s 计算:343 m/s = 34 300 cm/s = 0.0343 cm/μs。若测得 t 微秒,单程距离 d = t × 0.0343 / 2 cm = t / 58.31 cm,所以常用便捷式 d(cm) ≈ t(μs) / 58。若取 340 m/s,得到约 t / 58.82;两种结果不同是因为声速取值和近似程度不同。视频代码固定除以整数 58,是估算系数,不是某个模块直接输出“厘米”或“单位时间变成厘米”。ElecFreaks 资料也列出 μs/58 的经验换算。
  • 举例:物体约 10 cm 时,声波往返约 20 cm;按 343 m/s,回波宽度约 20 / 0.0343 ≈ 583 μs,代码算 583/58 后打印整数 10。反射面材质、大小、角度、温度、供电和附近其他超声波源都会影响测得值,串口在 10、11 等相邻整数间跳动并不奇怪。
  • 此段视频在约 6 分 40 秒口述“有效测量范围两米左右”,这是本次实验环境中的保守说法;常见 HC-SR04 规格列出的标称范围约 2~400 cm,不意味着在任意材质、角度和供电下都可稳定测到 4 m。原笔记只写“两米有效范围”若理解为器件绝对最大量程就不准确。
  • 视频草图没有在两次测量之间写等待语句:Serial.println(dis) 结束后下一轮 loop() 随即再触发。ElecFreaks 资料建议两次触发间隔超过约 60 ms,以减少前一次声波与后一次测量相互干扰;因此原代码演示中持续打印不等于长期稳定、可靠的测距实现。这一点只作为局限说明,不擅自改写视频代码。另外没有有效回波时 pulseIn() 返回 0,原代码也直接打印 0 cm,没有报错标志或过滤。

1.6 测试代码上传

  • **烧录顺序:**沿用前几节 USB 转串口连接和合适的板级供电,把 ESP32-CAM 的 GPIO0/IO0 临时接 GND,复位后在 Arduino IDE 选择 AI Thinker ESP32-CAM、正确的 COM 口上传;等 IDE 报告写入和校验完成,再移除 GPIO0–GND 下载模式跳线,复位进入正常程序。只拔“下载模式跳线”,不要把维持板子供电、共地和串口通信的所有导线一并拔掉。烧录过程还没有接好测距模块时,串口显示的数字无意义。GPIO0 只有在复位采样为低时才进入下载模式。Espressif 启动模式说明。
  • **视频实物连接与风险:**视频口述把模块 VCC 接板上 3.3V、GND 接 GND,再按程序把 Echo 接 GPIO13、Trig 接 GPIO15,复位后串口出现约 10 cm 的数字。这说明那次实物演示产生了输出,不能推出所有 HC-SR04 在 3.3 V 下合规或准确。常见四针 HC-SR04 的制造商规格是 DC 5 V,其 Echo 在 5 V 供电时可能输出约 5 V;而 ESP32 的 GPIO 高电平输入规格以 3.3 V 电源域为基准,不能把 5 V Echo 直接接 GPIO13。给模块按自身规格供 5 V 时,GND 必须与 ESP32-CAM 共地,并在 Echo 与 GPIO13 之间加合适的单向电平转换或分压;同时确认该模块的 Trig 输入能识别 ESP32 的 3.3 V 高电平,不能只凭一次成功推断所有不同版本都兼容。改线前先断电,别把 VCC 误插到 GPIO。
  • **给初学者看懂分压(硬件说明,不是课堂实物原接线):**若所购模块确实以 5 V 输出 Echo,可把 Echo ─ 10 kΩ ─ ● ─ GPIO13,并从中间节点 ● ─ 15 kΩ ─ GND。两个电阻在 Echo 高电平时分担电压;理想 5 V 输入在节点得到 5 × 15/(10+15) ≈ 3.0 V,低于 ESP32 的 3.3 V 电源轨、又高于其约 0.75×3.3=2.475 V 的高电平门槛。GPIO13 取中点,不是接在第一个电阻的 Echo 侧;模块地和开发板地必须相连,否则这 3.0 V 没有共同参考。这只是针对“5 V Echo → 3.3 V 输入”的示意,实作前仍要查手中模块的 Echo 输出、供电与阻值公差,或选成品电平转换模块。Adafruit HC-SR04 接线说明、Espressif 电气特性。
  • 打开 Arduino IDE 串口监视器,选 115200 baud,观察逐行输出;视频显示大约 10、11 cm 上下变化。Serial.println(dis) 只输出整数,串口窗口本身不测距,也不会自动把整数标注成“cm”。若一直为 0,检查 Echo/Trig 是否按 Echo→13、Trig→15 接、VCC/GND 是否正确、是否仍留着 GPIO0 下载跳线以及是否真的有可反射的目标;若显示乱码,先核对 115200 波特率。看到数字并不等于已验证量程和精度,还应拿尺子在多个距离对比。

核对依据

  • 本地 videos/289.7.超声波测距.mp4 中的 PPT、GPIO 引脚图、Arduino IDE 最终草图和实物/串口演示,结合 transcripts/289.7.超声波测距.txt、原始 notes/md/289.7.超声波测距.md;尤其以视频草图确定 Echo=13、Trig=15、long gettime() 和 long dis=gettime()/58,没有拿后续综合项目代码替代。
  • ElecFreaks HC-SR04 产品资料:核对四针定义、5 V、2~400 cm、10 μs 触发、8 个 40 kHz 周期、μs/58 与建议测量间隔;Arduino pulseIn() 官方说明:核对微秒单位与超时返回 0。
  • Espressif ESP32 电气规格、GPIO 复用说明、启动模式说明与Adafruit HC-SR04/3.3 V 主控接线说明:核对 Echo 电平安全、IO15 附加功能和 GPIO0 烧录模式。视频中实际模块的具体厂商版本未能仅凭正面画面确定,复现时应优先核对实物丝印或随附规格书。