
1. 项目缘起为什么用ATOM Matrix ESP32玩超声波测距最近在整理工作室的物料翻出来几个闲置的HC-SR04超声波模块和一个M5Stack的ATOM Matrix ESP32开发板。看着这个只有24x24像素LED点阵的小方块我就在想能不能用它做个既实用又有趣的小玩意儿比如一个能实时显示距离的超声波测距仪。这个想法听起来简单但实操起来你会发现它完美融合了硬件连接、传感器数据采集、嵌入式编程和微型显示交互等多个环节是一个检验你从“点灯”到“造物”能力的绝佳练手项目。ATOM Matrix ESP32这个小家伙核心是一颗ESP32-PICO-D4芯片集成了Wi-Fi和蓝牙性能对于这种小项目来说绰绰有余。它最大的特色就是正面那块5x5的RGB LED矩阵虽然分辨率不高但用来显示数字、简单图形或者状态指示既直观又酷炫。而HC-SR04则是电子爱好者入门必备的超声波测距模块价格低廉原理直观通过发射和接收超声波来计算距离。这个项目的核心价值在于它不是一个简单的“接线-上传代码-看结果”的演示。你需要思考如何在有限的5x5点阵上清晰地显示可能达到数米的距离值如何让显示效果更稳定、更易读如何优化代码以避免超声波模块常见的误触发和测量超时这些都是在实际产品开发中会遇到的问题。通过这个项目你不仅能学会驱动HC-SR04更能深入理解如何在资源受限的嵌入式环境下进行有效的人机交互设计。2. 核心硬件解析ATOM Matrix ESP32与HC-SR04的默契配合要完成这个项目我们得先吃透手头的两件“兵器”。理解它们的特性和连接方式是后续一切顺利的基础。2.1 ATOM Matrix ESP32麻雀虽小五脏俱全ATOM Matrix是一款极致紧凑的ESP32开发板。它的核心是ESP32-PICO-D4模组双核240MHz处理器520KB SRAM4MB Flash支持Wi-Fi和蓝牙。对于我们的测距项目性能完全过剩。它的引脚全部通过板子底部的一个Grove兼容接口引出这简化了连接但也意味着引脚资源有限。具体来看其Grove接口包含了G32 这是一个GPIO引脚同时也是ADC输入通道4。在本项目中我们将用它连接HC-SR04的Trig引脚。G26 另一个GPIO引脚我们将用它连接HC-SR04的Echo引脚。5V 为HC-SR04模块提供电源。GND 共地。板载的5x5 RGB LED矩阵型号为IS31FL3731驱动通过I2C总线与ESP32通信这不需要占用我们额外的GPIO。板载的按键和RGB LED灯珠非矩阵也为我们提供了额外的交互可能。整个开发板的尺寸比一枚硬币大不了多少非常适合嵌入到小型设备或作为可穿戴交互终端。2.2 HC-SR04超声波模块原理与特性HC-SR04的工作原理是声纳。它包含一个超声波发射器和一个接收器。我们向Trig引脚发送一个至少10微秒的高电平脉冲。模块会自动发射8个40kHz的超声波脉冲。超声波遇到障碍物反射回来被接收器捕获。模块的Echo引脚会输出一个高电平脉冲该脉冲的宽度与超声波往返的时间成正比。距离的计算公式为距离 (高电平时间 × 声速) / 2。在空气中声速受温度影响较大常温下20°C约为343米/秒换算成厘米/微秒大约是0.0343。所以公式常写为距离厘米 ≈ 高电平时间微秒 / 58.0 或距离厘米 ≈ 高电平时间微秒 * 0.0343 / 2。HC-SR04的测量范围官方标称是2cm到400cm但实际使用中超过200cm后精度和稳定性会下降。它的测量角度约为15度这意味着它探测的是一个圆锥形区域而不是一个点。模块工作电压为5V这也是为什么我们必须使用ATOM Matrix的5V引脚为其供电虽然Echo脚输出的是5V TTL电平但ESP32的GPIO通常可容忍5V输入具体看芯片手册很多型号是兼容的因此可以直接连接。为了更保险也可以使用两个电阻进行分压但在这个项目中直接连接是常见且可行的做法。3. 硬件连接与电路搭设连接非常简单但细节决定成败。你需要一根Grove转杜邦线母头的电缆或者自己焊接。连接步骤将转接线的GND黑色连接到HC-SR04的GND引脚。将转接线的5V红色连接到HC-SR04的VCC引脚。将转接线的信号线1通常是黄色或白色连接到HC-SR04的Trig引脚。这根线在ATOM Matrix端对应G32。将转接线的信号线2通常是绿色或蓝色连接到HC-SR04的Echo引脚。这根线在ATOM Matrix端对应G26。注意务必确保电源正负极连接正确反接极易损坏HC-SR04模块。连接时最好断开电源。整个系统的电路图在脑海中非常简单ATOM Matrix作为大脑和显示终端通过两根信号线控制并读取HC-SR04的数据同时为其提供能量。连接好后硬件部分就准备就绪了。4. 软件开发环境搭建与核心库选择软件层面我们选择Arduino IDE进行开发因为它对ESP32和外围设备库的支持非常成熟社区资源丰富。4.1 安装ESP32开发板支持首先你需要在Arduino IDE中安装ESP32开发板支持包。打开Arduino IDE点击“文件” - “首选项”。在“附加开发板管理器网址”中填入https://espressif.github.io/arduino-esp32/package_esp32_index.json如果已有其他URL用逗号分隔。点击“工具” - “开发板” - “开发板管理器”。搜索“esp32”找到由“Espressif Systems”提供的版本点击安装。安装完成后在“工具” - “开发板”列表中选择“ESP32 Arduino”然后找到“M5Stack ATOM Matrix”或类似的选项。如果没有完全匹配的选择“ESP32 PICO-D4”也可以但需要手动配置正确的引脚。4.2 安装必要的库本项目需要两个核心库FastLED或M5Atom库用于驱动ATOM Matrix上的LED点阵。M5Atom库是官方库对板载功能封装更友好。在库管理器中搜索“M5Atom”并安装。用于超声波测距的库我们可以自己写脉冲计时代码但使用现成的库更稳健。例如NewPing或HCSR04库。这里我选择NewPing因为它功能强大内置了错误处理。在库管理器中搜索“NewPing”并安装。4.3 项目代码结构设计在开始写代码前先规划一下程序逻辑初始化 初始化串口用于调试、LED矩阵、并设置Trig和Echo引脚模式。主循环触发一次超声波测距发送Trig脉冲。读取Echo脉冲的高电平持续时间。将时间转换为距离厘米。对距离数据进行简单的滤波处理例如取最近N次测量的中值或平均值以消除偶然误差。将处理后的距离值映射到5x5的LED矩阵上进行显示。添加适当的延迟控制测量频率例如每秒5-10次避免模块过热和信号干扰。5. 核心代码实现与逐行解析下面是一份结合了NewPing库和M5Atom库的示例代码并附有详细注释。#include M5Atom.h // 引入M5Atom库用于控制LED矩阵和板载功能 #include NewPing.h // 引入NewPing超声波库 // 定义超声波模块连接的引脚 #define TRIG_PIN 32 // ATOM Matrix的G32 #define ECHO_PIN 26 // ATOM Matrix的G26 // 定义最大测量距离厘米超过此值将返回0 #define MAX_DISTANCE 200 // 初始化NewPing对象 NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); // 用于滤波的变量 const int numReadings 5; // 滑动窗口大小 float readings[numReadings]; // 存储历史数据的数组 int readIndex 0; // 当前写入索引 float total 0; // 窗口内数据总和 float average 0; // 平均值 void setup() { // 初始化ATOM Matrix包括LED矩阵、串口等 M5.begin(true, false, true); // 参数SerialEnable, I2CEnable, DisplayEnable // 注意第一个true是启用串口对于ATOM Matrix如果不需要LED矩阵可设为false但我们需要显示所以第三个为true。 Serial.begin(115200); // 初始化串口用于调试输出 Serial.println(ATOM Matrix Ultrasonic Ranging Start...); // 初始化滤波数组 for (int i 0; i numReadings; i) { readings[i] 0; } // 初始化LED矩阵显示启动图案例如一个圆圈 M5.dis.drawpix(0, 0x00ff00); // 点亮中心像素为绿色 delay(500); M5.dis.clear(); // 清屏 } void loop() { M5.update(); // 更新M5对象状态如按键扫描本项目虽未用按键但保持习惯 // 1. 获取一次原始距离测量单位厘米NewPing库的ping_cm()函数默认使用声速343m/s计算 unsigned int rawDistance sonar.ping_cm(); // 调试输出原始数据 Serial.print(Raw Distance: ); Serial.print(rawDistance); Serial.println( cm); // 2. 数据有效性检查与滤波 // NewPing在超出范围或检测失败时返回0 if (rawDistance 0 || rawDistance MAX_DISTANCE) { // 无效数据可以将其视为一个很大的值或跳过更新 Serial.println(Invalid reading, skipped.); // 可以选择用上一次的有效平均值填充或者直接跳过本次滤波更新 // 这里我们选择跳过更新滤波数组显示上一次的平均值 } else { // 有效数据更新滑动平均滤波器 total total - readings[readIndex]; // 减去最旧的数据 readings[readIndex] rawDistance; // 存入新数据 total total readings[readIndex]; // 加上新数据 readIndex (readIndex 1) % numReadings; // 移动索引 // 计算当前平均值 average total / numReadings; Serial.print(Filtered Distance: ); Serial.print(average); Serial.println( cm); } // 3. 在LED矩阵上显示距离 displayDistanceOnMatrix(average); // 4. 控制测量频率每秒约5次测量 delay(200); } // 自定义函数在5x5矩阵上显示距离 void displayDistanceOnMatrix(float dist) { M5.dis.clear(); // 每次显示前清屏 // 如果距离无效为0或极大显示错误图案例如一个红色的“X” if (dist 2 || dist MAX_DISTANCE - 10) { // 小于2cm可能是误触发接近最大距离可能不稳定 // 画一个红色的X for (int i 0; i 5; i) { M5.dis.drawpix(i, i, 0xff0000); // 从左上到右下的红线 M5.dis.drawpix(i, 4 - i, 0xff0000); // 从左下到右上的红线 } return; } // 方案一数字模式适合显示0-99cm // 将距离映射到0-24的索引点亮对应数量的LED // 但5x525个灯可以表示0-24。我们可以用条形图或进度条形式。 int ledLevel map((int)dist, 2, 100, 0, 24); // 假设主要显示2-100cm范围 ledLevel constrain(ledLevel, 0, 24); // 限制在0-24之间 // 根据ledLevel点亮相应数量的LED例如从底部开始向上点亮 for (int i 0; i 25; i) { int row i / 5; int col i % 5; // 从下往上点亮第4行是底部。你也可以设计其他图案。 int heightIndex 4 - row; // 底部行对应大的索引值 if (i ledLevel) { // 根据距离设置颜色近处红色中间绿色远处蓝色示例 uint32_t color; if (dist 30) color 0xff0000; // 红色 else if (dist 70) color 0x00ff00; // 绿色 else color 0x0000ff; // 蓝色 M5.dis.drawpix(col, row, color); // 注意M5.dis.drawpix参数是(x, y) } else { M5.dis.drawpix(col, row, 0x000000); // 熄灭 } } // 方案二直接显示两位数字需要更复杂的字体映射代码较长此处略 // 方案三用中心点扩散的圆圈半径表示距离更直观但精度低 }代码关键点解析NewPing sonar(...) 创建了一个NewPing对象它封装了触发、计时和计算距离的逻辑。MAX_DISTANCE设置为200厘米是为了平衡测量范围和响应速度。值越大等待Echo超时的时间越长。滑动平均滤波 这是嵌入式传感器数据处理中最常用、最简单的滤波方法。它能有效平滑掉单次测量的偶然跳动比如因为物体表面不平整或空气扰动。numReadings定义了滤波窗口的大小值越大越平滑但响应越慢这里取5是一个折中。数据有效性检查if (rawDistance 0 ...)这段代码至关重要。HC-SR04在测量超时或没有收到回波时NewPing会返回0。如果不加处理这个0值会进入滤波器拉低平均值导致显示异常。我们的策略是跳过无效数据保持上一次的有效显示。显示映射函数displayDistanceOnMatrix 这是本项目最具创意也最挑战的部分。5x5的像素实在太少。示例代码提供了两种思路条形图模式 将距离映射为点亮LED的数量像手机信号格一样直观但不精确。数字模式注释中 需要预先定义0-9的数字在5x5点阵上的显示模式字模然后解析距离的十位和个位分别显示。这需要额外的代码和存储空间但信息最精确。颜色编码 结合条形图用颜色表示“危险区”红色近、“安全区”绿色中、“远方”蓝色远增加了信息维度。M5.dis.drawpix(col, row, color) 这是M5Atom库控制LED矩阵的核心函数。注意其坐标系统(0,0)是左上角(4,4)是右下角。颜色是24位的RGB值0xRRGGBB。6. 高级优化与功能拓展基础功能实现后我们可以让它变得更智能、更稳定。6.1 优化测量稳定性与精度温度补偿 声速随温度变化。可以添加一个DS18B20之类的温度传感器实时计算当前声速。公式为v 331.4 0.6 * TT为摄氏温度。NewPing库的ping_cm()函数可以传入温度参数。中值滤波替代平均滤波 对于存在偶发尖峰干扰的情况比如突然有小虫飞过中值滤波取中间值比平均滤波更能抵抗“离群值”的干扰。设置测量超时和间隔NewPing库已经处理了超时。确保测量间隔delay(200)不要太短给模块足够的“休息”时间通常建议在60ms以上。6.2 丰富显示与交互模式切换显示模式 利用ATOM Matrix板载的按键单击可以在“条形图模式”、“数字模式”、“关闭显示”之间循环切换。无线数据传输 利用ESP32的Wi-Fi功能将距离数据通过HTTP或MQTT协议发送到服务器、手机App或Home Assistant等智能家居平台实现远程监控。增加声音提示 通过PWM驱动一个小型蜂鸣器当距离小于某个阈值时发出“滴滴”声频率随距离变近而加快实现非视觉告警。低功耗优化 如果用于电池供电可以让ESP32在大部分时间进入深度睡眠Deep Sleep定时唤醒进行测量和显示极大延长续航。6.3 结构封装与电源管理3D打印外壳 为ATOM Matrix和HC-SR04设计一个紧凑的外壳将超声波探头朝前露出LED矩阵朝上。这不仅能保护电路也让项目看起来更完整。电池供电 ATOM Matrix可以通过其底部的引脚连接一块小型的锂电池如500mAh的锂聚合物电池实现完全便携。注意在代码中可能需要添加电池电量检测和低电量提示功能通过ADC读取电池电压。7. 常见问题排查与调试心得在实际制作过程中你可能会遇到以下问题测量值始终为0或非常大且不变检查接线 这是最常见的问题。确认Trig和Echo线是否接反电源是否接好。检查电源 HC-SR04需要5V供电确保ATOM Matrix的5V引脚有输出有时USB供电不足会导致问题。检查代码引脚定义 确认代码中的TRIG_PIN和ECHO_PIN与物理连接一致。检查物体表面 超声波对柔软、多孔或倾斜角度过大的表面反射效果很差尝试用平整的硬纸板作为目标。测量值跳动剧烈引入滤波 如代码所示滑动平均滤波是必须的。可以尝试增大numReadings。检查环境干扰 附近是否有其他超声波源如另一个HC-SR04或强烈的空气流动让模块远离干扰源。供电噪声 尝试在HC-SR04的VCC和GND之间并联一个10uF-100uF的电解电容以稳定电源。LED矩阵显示混乱或不亮确认M5.begin()参数 确保第三个参数为true以启用显示。检查I2C地址 ATOM Matrix的LED驱动芯片地址是固定的通常库函数已处理好。如果使用其他库如FastLED需要正确配置。颜色值格式 确认传递给drawpix的颜色值是24位的RGB0xRRGGBB。程序上传失败选择正确的开发板和端口 在Arduino IDE的“工具”菜单中仔细检查。按住“复位”键 对于某些ESP32板在上传时需要手动进入下载模式。ATOM Matrix通常在上传开始时自动复位如果失败尝试在点击“上传”后立刻按住板上的“复位”按钮如果有的话直到编译完成开始上传时松开。这个项目从硬件连接到软件滤波再到显示优化涵盖了一个完整嵌入式小产品的核心流程。它最吸引我的地方在于用极其有限的显示空间25个像素去表达一个连续变化的物理量这个过程迫使你去思考信息传递的本质。我个人的体会是在资源受限的嵌入式开发中“显示”不一定是“看到数字”而是“感知到状态”。用颜色和简单的图形变化往往比强行显示不清晰的数字更有效。当你看到LED矩阵的红色光柱随着手的前后移动而平滑升降时那种直接的人机交互感比看串口打印的数字要有趣得多。下一步我打算给它加上Wi-Fi把距离数据实时推送到我电脑上的一个仪表盘这样它就能作为一个简单的桌面防近视提醒器或者宠物靠近监测器来用了。