1. 项目概述与核心思路几年前我在调试一个机器人小车时经常需要手动测量它与障碍物之间的精确距离以便校准传感器。每次都要弯腰、拉卷尺既麻烦又容易产生误差。当时我就想如果能有一个像手表一样戴在手上、抬手就能测距的工具那该多方便。这个想法一直搁置着直到最近整理零件时翻出了几片闲置的Arduino Nano和HC-SR04超声波模块那个“可穿戴测距仪”的念头又冒了出来。这个项目的核心就是打造一个“距离测量手表”。它本质上是一个高度集成化的超声波测距系统通过将Arduino微控制器、超声波传感器和微型显示屏全部塞进一个手表大小的空间里实现随时随地的非接触式距离测量。听起来可能有点极客但实际做下来你会发现它涉及到的嵌入式系统集成、电源管理和结构设计思路对于任何想深入硬件开发的朋友来说都是一次绝佳的练手机会。无论你是想为你的机器人项目添加一个便携调试工具还是单纯享受将想法变成实物的乐趣这个项目都能让你收获颇丰。整个系统的运作逻辑非常清晰手表上的超声波传感器周期性地发射一束人耳听不到的超声波脉冲这束声波在空气中传播遇到障碍物后反射回来被传感器接收。Arduino负责精确记录从发射到接收的时间差。我们知道声音在常温20°C空气中的速度大约是343米/秒。那么距离就等于声速乘以时间差再除以2因为声波走了一个来回。最后计算出的距离值会实时显示在那块小小的OLED屏幕上。整个过程在几十毫秒内完成让你感觉就像拥有了“电子眼”。2. 核心组件选型与原理深析为什么是这几样零件这背后每一件都是经过权衡和考量的结果绝不是随便抓几个模块拼在一起就行。2.1 大脑的选择Arduino Nano vs. Pro Mini项目原文提到了Arduino Nano或Pro Mini。这两者都是ATmega328P核心的微型控制器但细节决定成败。我强烈推荐使用Arduino Nano。原因有三第一Nano自带USB转串口芯片通常是CH340或FT232你只需要一根Micro-USB线就能完成编程和供电调试起来极其方便。而Pro Mini需要额外的USB转TTL串口模块才能烧录程序对新手不够友好。第二Nano的引脚是标准的2.54毫米间距排针可以直接插在迷你面包板上连接稳固。Pro Mini的引脚是单排的焊接和固定稍麻烦。第三在功耗相差无几的情况下Nano的易用性完胜。对于可穿戴设备易调试比那一点点尺寸差异更重要。注意购买Nano时注意区分是5V/16MHz版本还是3.3V/8MHz版本。一定要选择5V版本因为我们的传感器和显示屏都是5V逻辑电平。2.2 感知世界的“眼睛”HC-SR04超声波传感器HC-SR04几乎是电子爱好者入门测距的首选成本极低通常不到10元性能可靠。它的工作原理是你给Trig引脚一个至少10微秒的高电平脉冲它内部就会发射一组8个40kHz的超声波。当回声被接收到时Echo引脚会输出一个高电平脉冲这个脉冲的宽度与超声波飞行时间成正比。这里有一个关键细节常被忽略HC-SR04的测量周期。模块本身需要约60ms的“冷却时间”才能进行下一次测量这是为了防止上一次发射的回波干扰下一次的接收。这意味着即使用代码疯狂触发它的最高测量频率也被限制在约16Hz左右。在设计代码时两次测量的间隔至少应设为60ms否则读数会不稳定甚至出错。2.3 信息的窗口0.96英寸I2C OLED屏为什么用OLED而不是LCD对于可穿戴设备OLED有压倒性优势自发光、超高对比度、极薄、可视角度广、功耗低显示黑色像素时不耗电。我们选用128x64分辨率的I2C接口版本。I2C总线只需要两根数据线SDA, SCL比并口屏节省了大量引脚非常适合引脚紧张的微型项目。I2C通信有一个需要注意的地方地址。市面上常见的0.96寸OLED屏I2C地址通常是0x3C但也有部分型号是0x3D。如果你的屏幕初始化失败、一片空白首先就应该检查并修改代码中的设备地址。2.4 动力之源9V电池与升压考量原文使用了9V电池通常是6F22叠层电池。这是一个简单直接的选择因为Arduino Nano有一个“VIN”引脚可以接受7-12V的输入内部线性稳压器会将其降到5V给主板和模块供电。但这里存在一个效率陷阱。线性稳压器LDO的原理是“多退少补”把多余的电压以热量的形式耗散掉。当电池电压为9V系统工作在5V时有将近一半的功率被白白浪费成了热量这不仅缩短续航在密闭的手表壳内还可能引起温升。更优的方案是使用一块3.7V的锂聚合物电池配合一个DC-DC升压模块将电压稳定升压至5V。升压电路的效率通常可达85%以上能显著延长使用时间。不过这需要额外的电路和充电管理增加了复杂度。对于初次制作从9V电池开始更稳妥但了解这个优化方向很有必要。2.5 结构之基迷你面包板与连接170点的迷你面包板是整个电路的“临时骨架”。它允许我们无需焊接就能快速搭建和测试电路这是原型开发阶段不可或缺的。但要注意面包板内部的金属簧片用久了可能会接触不良导致时好时坏的诡异故障。在最终固定前务必确保每个插脚都接触牢固。跳线建议使用公-公杜邦线柔软易于整理。3. 电路搭建与硬件连接实操理论清楚了现在开始动手。请严格按照以下步骤和接线图操作这是保证一次成功的基础。3.1 分步连接指南首先将所有元件插在迷你面包板上。建议按功能分区摆放左边放Arduino Nano右边放OLED屏前方伸出超声波传感器电源放在侧面。这样布线清晰便于排查。1. 连接OLED显示屏 (I2C接口)OLED GND-Arduino GND(任意一个GND引脚)OLED VCC-Arduino 5V(注意是5V不是3.3V)OLED SDA-Arduino A4(在Nano上A4就是SDA功能引脚)OLED SCL-Arduino A5(同理A5是SCL功能引脚)2. 连接HC-SR04超声波传感器HC-SR04 VCC-Arduino 5VHC-SR04 GND-Arduino GNDHC-SR04 Trig-Arduino Digital 12HC-SR04 Echo-Arduino Digital 11这里为什么用D11和D12没有特殊原因只是两个普通的数字引脚。你可以根据喜好更换但务必记住并在后续代码中同步修改。3. 连接9V电池电池扣正极(红色线)-Arduino VIN引脚电池扣负极(黑色线)-Arduino GND引脚重要安全提示连接电池前再三确认正负极接反了会瞬间烧毁你的Arduino Nano。可以先不接传感器和屏幕只连Arduino和电池如果板载电源指示灯通常标着“ON”亮了说明供电正常。3.2 电路原理与信号流解读现在我们来梳理一下整个电路的“信息流”和“电流流”这能帮你真正理解它在干什么而不是机械地照搬连线。电流路径供电9V电池的电能从VIN进入Arduino Nano经过板载的AMS1117-5.0线性稳压器稳定输出5V。这个5V一路供给Arduino自身的芯片另一路通过5V引脚“分配”给OLED屏和HC-SR04传感器。所有设备的GND最终汇集到一起接回电池负极形成一个完整的回路。信号路径控制与数据触发阶段Arduino的D12引脚输出一个短暂的10微秒高电平脉冲送到HC-SR04的Trig脚。这个脉冲就像扣动扳机告诉传感器“发射”测距阶段HC-SR04内部发射超声波同时将Echo引脚拉高。超声波在空气中飞行、反射、返回。当接收头检测到回波时HC-SR04将Echo引脚拉低。这样Echo引脚高电平的持续时间就是超声波往返的时间。计时阶段Arduino在触发拉高Trig的同时启动一个高精度计时器pulseIn函数。它持续监测D11Echo引脚等待其从低变高再变低并精确记录这个高电平脉冲的宽度单位是微秒。计算与显示阶段Arduino将测得的时间微秒代入公式距离 (时间 * 0.0343) / 20.0343是声速343米/秒换算成厘米/微秒的近似值。计算结果通过I2C总线A4/A5引脚发送给OLED屏驱动屏幕更新显示。整个过程中OLED屏作为一个被动的显示设备只接收来自Arduino的指令和数据不参与控制逻辑。4. 软件编程与代码逐行解析硬件是躯体软件是灵魂。下面这份代码不仅能让设备跑起来还包含了一些提升稳定性和用户体验的细节处理。4.1 库文件安装与准备在编写代码前你需要为Arduino IDE安装两个库Adafruit SSD1306这是驱动OLED屏的核心库。Adafruit GFX这是图形库SSD1306库依赖于它来绘制图形和文字。安装方法打开Arduino IDE点击“工具” - “管理库…”在搜索框中分别搜索这两个库名由Adafruit发布的版本点击安装即可。4.2 完整代码与深度注释// 引入必要的库 #include Wire.h // I2C通信库Arduino内置 #include Adafruit_GFX.h // 图形库 #include Adafruit_SSD1306.h // OLED驱动库 // 定义OLED屏幕的尺寸和I2C地址 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_ADDR 0x3C // 如果屏幕不亮尝试改为0x3D // 初始化OLED对象 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, Wire, -1); // 定义超声波传感器引脚 const int trigPin 12; const int echoPin 11; // 定义声速厘米/微秒20摄氏度下的近似值 const float soundSpeed 0.0343; // 变量声明 long duration; // 存储高电平脉冲时间微秒 float distance; // 存储计算出的距离厘米 float smoothedDistance 0; // 用于平滑滤波的距离值 const float smoothingFactor 0.2; // 平滑系数越小越平滑但响应越慢 void setup() { // 初始化串口用于调试可选 Serial.begin(9600); // 初始化超声波传感器引脚 pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); digitalWrite(trigPin, LOW); // 初始确保Trig为低电平 // 初始化OLED显示屏 if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { Serial.println(F(SSD1306 allocation failed)); for(;;); // 如果初始化失败程序停在这里 } delay(100); // 给屏幕一点启动时间 display.clearDisplay(); // 清屏 display.setTextSize(2); // 设置字体大小 display.setTextColor(SSD1306_WHITE); // 设置字体颜色白色 display.setCursor(0, 0); // 设置光标起始位置 display.println(Range:); // 显示静态标题 display.display(); // 将缓存内容刷到屏幕上 } void loop() { // 1. 触发超声波测距 digitalWrite(trigPin, LOW); delayMicroseconds(2); // 短暂低电平确保稳定 digitalWrite(trigPin, HIGH); delayMicroseconds(10); // 维持10微秒高电平触发脉冲 digitalWrite(trigPin, LOW); // 2. 读取回声高电平持续时间 duration pulseIn(echoPin, HIGH, 30000); // 超时设为30000微秒约5米 // 3. 计算距离单位厘米 // 公式距离 (时间 * 声速) / 2 distance duration * soundSpeed / 2.0; // 4. 简单滤波处理消除突变值 if (distance 0 distance 400) { // 有效范围设为0-400厘米 smoothedDistance (smoothingFactor * distance) ((1 - smoothingFactor) * smoothedDistance); } else { // 如果读数超出范围保留上一次的有效平滑值 // distance smoothedDistance; // 或者显示“ERR” } // 5. 在OLED屏幕上显示结果 display.clearDisplay(); // 清除上一帧画面 display.setTextSize(2); display.setCursor(0, 0); display.println(Range:); // 显示标题 display.setTextSize(3); // 放大数字字体 display.setCursor(10, 25); // 调整数字显示位置 // 判断显示内容 if (smoothedDistance 400 || smoothedDistance 0) { display.println(ERR); // 显示错误 } else { display.print(smoothedDistance, 1); // 显示距离保留1位小数 display.println( cm); // 显示单位 } display.display(); // 更新屏幕显示 // 6. 可选通过串口输出数据用于调试 Serial.print(Raw Duration: ); Serial.print(duration); Serial.print( us, Distance: ); Serial.print(smoothedDistance); Serial.println( cm); // 7. 等待至少60ms满足HC-SR04的测量周期要求 delay(100); // 这里设为100ms提供更稳定的读数间隔 }4.3 关键代码逻辑剖析pulseIn函数与超时设置pulseIn(echoPin, HIGH, 30000)是关键。它等待echoPin变为高电平并开始计时直到其变回低电平。第三个参数30000是超时时间微秒。如果超过30毫秒仍未收到回波意味着障碍物太远或没有反射函数会返回0。这个超时值对应约(30000 * 0.0343)/2 ≈ 514厘米但我们通常将有效距离限定在更小的范围如400厘米以保证精度。一阶滞后滤波算法smoothedDistance (smoothingFactor * distance) ((1 - smoothingFactor) * smoothedDistance);这行代码实现了一个简单的软件低通滤波器。它的作用是让显示的距离值变化更平滑避免因传感器微小波动或环境干扰导致的数字剧烈跳动。smoothingFactor取值在0到1之间值越小平滑效果越强但对新变化的响应也越慢。0.2是一个不错的起点。错误处理与显示优化代码中添加了对距离有效性的判断if (distance 0 distance 400)。当传感器没有收到有效回波如对着天空或距离过远时duration可能为0或极大计算出的distance是无意义的。此时我们选择不更新平滑值或者显示“ERR”这比显示一个荒谬的数字如“65535 cm”要专业得多。屏幕刷新策略每次循环都执行display.clearDisplay()和display.display()。虽然清屏重绘是最简单的方式但在更复杂的界面下可能会造成闪烁。对于这种只更新数字的应用可以采用局部更新只重写数字区域来优化但当前代码的简洁性更适合初学者理解。5. 系统集成、装配与结构优化电路测试成功后我们就要考虑如何把它变成一块真正的“手表”。这步是从原型到产品的关键跳跃。5.1 从面包板到可穿戴设备首先你需要一块旧手表作为“外壳”。拆掉表芯和表带只保留空表壳。我们的目标是利用这个现成的、佩戴舒适的结构。装配步骤固定电池使用强力双面胶或纳米胶将9V电池平整地粘贴在手表壳的背面原来贴手腕的那一面。这是整个设备最大最重的部分需要粘牢。固定电路将迷你面包板连同上面插好的所有元件用双面胶粘贴在电池的正面即朝向表盘的一面。注意布局让超声波传感器的“眼睛”和OLED屏幕尽可能朝向表盘开口的方向。处理导线用扎带或胶布将连接电池和面包板的电源线妥善捆扎避免松散拉扯导致脱落。开孔与对准这是最需要耐心的一步。你需要仔细在手表玻璃或塑料表盖上规划开孔位置。对于超声波传感器它的发射和接收头是那两个圆形的金属网。你需要为这两个“眼睛”开出对应的圆孔或一个足够大的方孔。孔洞必须精准对准否则声波会被表壳遮挡。可以使用小电钻配合合适尺寸的钻头或者用烧热的针/刀头慢慢烫出孔洞。务必小心操作避免表盖碎裂。对于OLED屏幕你需要开一个矩形窗口让屏幕完全露出。可以用美工刀和尺子慢慢切割。理想情况下窗口大小应略小于屏幕显示区域这样表盖可以起到固定和装饰边框的作用。最终封装将所有部件对准孔位后可以用少量热熔胶在面包板边缘和表壳内部进行辅助固定防止移位。最后考虑用一块透明的亚克力板或甚至原来的手表玻璃如果开孔成功盖回去用胶水封边起到防尘防碰的作用。5.2 结构设计中的经验与教训重心与佩戴感9V电池加上电路重量不容小觑。粘贴时尽量让重心靠近手腕中心避免一头过重导致手表在手腕上旋转。如果感觉太重可以考虑换用更小的锂聚合物电池但需配套充电和升压模块。传感器朝向确保超声波传感器的发射面与表盖平行且前方没有任何胶水或杂物遮挡。即使是透明的塑料如果厚度不均也可能对声波造成轻微折射影响精度。按钮预留当前版本没有开关接上电池就开始工作。一个改进方案是在侧面钻一个小孔安装一个微型拨动开关串联在电池正极线上方便随时断电节省电量。防水与坚固这只是一个原型不防水也不抗摔。如果希望日常使用需要考虑用环氧树脂胶对电路进行灌封但这会使得后续维修几乎不可能。需要在可维修性和耐用性之间权衡。6. 校准、测试与高级功能拓展设备装好了怎么知道它测得准不准能不能让它更聪明6.1 校准与精度验证超声波测距在空气中受温度和湿度影响。代码中使用的0.0343是20°C下的声速。温度每升高1°C声速增加约0.6米/秒。对于要求不高的近距离测量1-2米内这个误差可以接受。如果需要更高精度可以简易校准法在已知距离例如50.0厘米、100.0厘米处放置一个平整的障碍物读取手表显示值。如果存在固定偏差如总是偏大2厘米可以在代码的计算公式中加入一个修正偏移量distance (duration * soundSpeed / 2.0) - offset;。加入温度补偿添加一个DS18B20之类的数字温度传感器实时读取环境温度动态计算声速。公式为V 331.4 0.6 * T其中T为摄氏温度。这将大幅提升在不同环境下的测量精度。6.2 功能优化与扩展思路基础功能实现后你可以尝试以下升级让这块手表变得更强大测量模式切换通过增加一个按钮实现单位切换厘米/英寸、测量模式切换单次测量/连续测量。数据记录与回看增加一个微型SD卡模块让手表可以按时间戳记录测量数据后期可以导入电脑分析。阈值报警设定一个安全距离如20厘米当测量值低于该阈值时让手表通过蜂鸣器振动马达发出警报。这可以变成一个盲人避障辅助设备的雏形。蓝牙传输加入HC-05蓝牙模块将实时距离数据发送到手机APP上显示或记录实现无线监控。低功耗优化这是可穿戴设备的终极课题。将Arduino的休眠模式利用起来让大部分时间芯片处于深度睡眠只有按下按钮或定时唤醒时才进行一次测量和显示可以轻松将续航从几小时提升到数天甚至数周。7. 常见问题排查与实战心得做项目不可能一帆风顺下面是我在制作和调试过程中遇到的一些典型问题及解决方法希望能帮你少走弯路。7.1 问题速查表问题现象可能原因排查步骤与解决方案上电后屏幕不亮1. 电源未接通或接反。2. OLED屏I2C地址不对。3. 屏幕本身损坏。1. 检查电池电压用万用表测量Arduino 5V引脚是否有输出。2. 将代码中OLED_ADDR从0x3C改为0x3D重新上传。3. 尝试用单独的5V电源和GND直接给屏幕供电看是否亮起。屏幕亮但无内容显示1. 代码未成功上传。2. I2C线接触不良。3. 库文件未正确安装或版本冲突。1. 检查Arduino IDE中端口和板型选择是否正确重新上传。2. 重新插拔SDA、SCL线或换用其他引脚测试。3. 在管理库中更新或重新安装Adafruit SSD1306和GFX库。距离显示为0或固定值1. 超声波传感器接线错误。2. Trig或Echo引脚定义与代码不符。3. 传感器前方有遮挡或距离障碍物太近/太远。1. 对照接线图确认VCC、GND、Trig、Echo四根线是否正确。2. 检查代码开头trigPin和echoPin的定义是否与实际接线一致。3. 确保传感器发射面对准空旷区域测量物体在2-400厘米之间表面平整。距离读数跳动剧烈1. 环境干扰如风扇、气流。2. 测量物体表面不平或吸声。3. 电源噪声。1. 在静止环境下测试避开通风口。2. 对准平整硬质表面如墙壁、木板测量。3. 在Arduino的5V和GND之间并联一个100uF的电解电容稳定电源。4. 尝试调整代码中的smoothingFactor增大其值如0.5让滤波效果更强。测量最大距离严重缩水1. 电池电量不足。2. 传感器发射面被部分遮挡。3. 声速常数不准确。1. 更换新电池测试。2. 检查手表外壳开孔是否完全对准传感器金属网清理任何胶渍。3. 进行距离校准修正声速常数。Arduino发热严重1. 线性稳压器负担过重。2. 短路。1. 这是使用9V电池和线性稳压器的通病。考虑改用3.7V锂电池升压模块方案。2. 立即断电检查是否有引脚间短路或金属碎屑导致短路。7.2 来自实战的几点心得先调试后封装在把所有东西粘进手表壳之前务必在桌面上完成所有的功能测试和代码调试直到读数稳定准确。一旦封装再想修改连线或测量电压就非常麻烦了。善用串口调试代码中预留的Serial.print语句是你的“第三只眼”。通过串口监视器观察原始的duration值和计算出的distance能帮你快速定位是传感器没信号还是计算逻辑有问题或是屏幕驱动失败。供电是稳定的基石很多古怪的问题如重启、读数飘忽都源于供电不足。9V电池在电量下降后电压跌落可能导致系统不稳定。如果你发现设备工作一段时间后开始异常第一个要怀疑的就是电池。理解传感器的局限性HC-SR04对细小物体、柔软织物、倾斜角度的表面检测能力会下降。它最适合测量大面积、平整的硬质表面。这不是你代码的错而是物理原理的限制。结构设计优先考虑可维护性不要用死胶把所有东西都封死。考虑用螺丝固定、卡扣设计或者至少让电池仓易于更换。你的第一个版本几乎肯定会有需要调整的地方。这个项目最迷人的地方在于它把一个抽象的物理原理和一行行代码变成了一个可以握在手中、解决实际问题的具体工具。从最初的连线调试到第一次在OLED上看到跳动的数字再到最后把它戴在手上测量书桌的宽度每一步都充满了创造的成就感。它可能不是最精致的可穿戴设备但它毫无疑问是你亲手赋予功能的智能伙伴。希望你在制作过程中不仅能收获一块有趣的表更能深入理解这些电子模块如何协同工作并激发出更多改造世界的灵感。