1. 项目概述与核心思路最近在整理工作室的旧项目时翻出了一个几年前做的“社交距离警示器”原型。当时正值特殊时期大家对于保持物理距离格外关注。市面上虽然有一些成品设备但要么价格不菲要么功能单一。作为一个喜欢动手的硬件爱好者我决定用手头最常见的Arduino开发板、一个超声波传感器和几个LED灯自己做一个既直观又实用的距离警示装置。这个装置的核心逻辑非常简单它就像一个无声的“电子哨兵”持续监测前方一定范围内的障碍物比如人。当有物体进入“安全区”边缘时绿灯会亮起作为温和提醒随着物体继续靠近黄灯亮起表示距离正在缩短一旦物体进入预设的“危险距离”内红灯就会亮起并可能伴随闪烁发出明确的“请保持距离”警告。整个系统成本极低核心部件加起来可能不到50元但实现的效果却非常直观有效非常适合放在办公桌隔断、商店柜台、图书馆自习区等半固定场所使用。我选择Arduino Leonardo作为主控一方面是因为它价格适中、性能足够另一方面是它兼容性极佳有丰富的社区资源和库支持。传感器方面HC-SR04超声波模块是经典之选它非接触式测量、成本低、精度对于这个应用场景厘米级完全足够。显示部分我没有使用复杂的屏幕而是采用了最直接的红、黄、绿三色LED灯通过点亮不同数量和颜色的灯来传递信息这种设计无需文字说明任何人都能一眼看懂状态符合“警示器”简单直接的设计初衷。2. 核心器件选型与原理剖析2.1 主控单元为什么是Arduino Leonardo在众多Arduino板卡中我选择了Leonardo。可能有人会问用更便宜的Uno或者更强大的Mega不行吗当然可以但Leonardo有几个独特的优势让它成为这个项目的“甜点”选择。首先USB通信协议。Arduino Uno/Nano使用的是USB转串口芯片如CH340、FT232而Leonardo以及Micro、Due原生集成了USB功能其ATmega32U4微控制器本身就能被电脑识别为USB设备。这意味着Leonardo可以模拟键盘、鼠标、游戏手柄等HID设备。虽然在这个警示器项目中我们暂时用不到这个高级功能但它为未来升级留下了巨大空间——比如当检测到有人持续闯入危险距离时可以让Leonardo模拟键盘按下“静音”键自动将视频会议静音这个想法是不是很酷其次引脚资源与功耗。Leonardo提供了20个数字I/O引脚其中7个支持PWM和12个模拟输入引脚对于驱动几个LED和一个传感器绰绰有余且仍有大量余量用于扩展。它的功耗也比一些高性能板卡要低适合长期插电运行。最后是性价比它的价格通常只比Uno略高一点但获得了更现代的USB功能和更好的扩展性属于“加量不加价”。注意如果你手头只有Arduino Uno完全没问题本项目代码和接线方式与Uno完全兼容。Leonardo的优势更多体现在未来功能扩展的潜力上。2.2 感知核心HC-SR04超声波测距模块详解HC-SR04几乎是电子爱好者入门测距的首选模块价格通常在5元以内。它的工作原理是超声波渡越时间法。模块上有两个圆柱形“眼睛”一个是超声波发射器T一个是接收器R。其工作流程如下主控给Trig引脚一个至少10微秒的高电平脉冲触发模块发射一束8个40kHz的超声波。超声波在空气中传播遇到障碍物后反射回来。模块的接收器检测到回波Echo引脚会输出一个高电平脉冲。这个高电平脉冲的持续时间正好等于超声波从发射到返回所经历的时间。那么距离怎么算我们知道在空气中声速约为340米/秒随温度变化但常温下可近似。距离等于速度乘以时间。但要注意Echo引脚的高电平时间是超声波“往返”一趟的时间所以单程距离需要除以2。计算公式为距离 (高电平时间 × 声速) / 2在代码中声速通常取34000厘米/秒换算单位。高电平时间由pulseIn()函数读取单位是微秒百万分之一秒。所以最终计算为距离(厘米) (高电平时间(微秒) * 0.034) / 2简化后就是距离(厘米) 高电平时间(微秒) * 0.017。例如如果pulseIn()读到2941微秒那么距离 ≈ 2941 * 0.017 ≈ 50厘米。实操心得HC-SR04的测量角度约为15度属于小角度探测指向性较好但这也意味着需要将它对准你想要监测的区域。它的有效测距是2cm到400cm但超过200cm后回波信号变弱精度和稳定性会下降。对于社交距离警示我们通常关注50cm到200cm的范围正好是它的最佳工作区间。2.3 警示输出多色LED阵列的驱动策略为什么用多个LED而不是一个RGB LED这里主要考虑的是可视角度和警示效果。一个RGB LED虽然能变色但它的发光点小可视角度有限且亮度可能不足。而使用多个离散的LED比如2绿、3黄、2红可以将它们排列成一条直线或弧形模拟“信号强度条”的效果视觉上更直观也从不同角度都更容易看到。我们需要决定如何驱动这7个LED。最简单的方法是为每个LED分配一个独立的I/O口但这会占用7个引脚。另一种方法是使用移位寄存器如74HC595用3个引脚控制无限多个LED。但对于只有7个灯的项目为了简化我选择了直接驱动因为Leonardo的引脚足够用。限流电阻的计算是关键一步。Arduino的I/O口输出电压是5V单个LED的典型正向压降Vf根据不同颜色而不同红光约1.8-2.2V黄/绿光约2.0-2.4V。I/O口最大安全输出电流建议不超过20mA我们通常设计在10-15mA以获得良好亮度且安全。以红色LEDVf2.0V为例计算限流电阻R (Vcc - Vf) / I。Vcc是5VI取15mA0.015A。则R (5 - 2.0) / 0.015 3.0 / 0.015 200欧姆。我们可以取一个接近的标准值如220欧姆。重要提示务必为每个LED串联一个独立的限流电阻绝对不能将多个LED并联后共用一个电阻。因为即使同一批次的LED其正向压降也有微小差异并联会导致压降小的那个LED流过更大电流从而过热烧毁。这是新手最容易犯的硬件错误之一。3. 硬件电路设计与搭建详解3.1 电路连接图与接线表根据上面的选型我们来规划具体的连接方式。为了清晰起见我建议将LED按颜色分组并排列成一条线这样点亮时从绿到红的变化就像一道“距离光栅”。元件清单Arduino Leonardo x1HC-SR04超声波模块 x15mm LED绿色 x2黄色 x3红色 x2220欧姆电阻 x7用于LED限流1k欧姆电阻 x1可选用于Echo引脚上拉部分模块不需要面包板、杜邦线若干外接电源如9V电池适配器或USB供电接线示意图文字描述超声波模块连接HC-SR04 VCC → Arduino 5VHC-SR04 GND → Arduino GNDHC-SR04 Trig → Arduino 数字引脚 9HC-SR04 Echo → Arduino 数字引脚 10LED阵列连接假设排列顺序为绿1绿2黄1黄2黄3红1红2绿色LED1 阳极长脚→ 串联220Ω电阻 → Arduino 数字引脚 2绿色LED2 阳极 → 串联220Ω电阻 → Arduino 数字引脚 3黄色LED1 阳极 → 串联220Ω电阻 → Arduino 数字引脚 4黄色LED2 阳极 → 串联220Ω电阻 → Arduino 数字引脚 5黄色LED3 阳极 → 串联220Ω电阻 → Arduino 数字引脚 6红色LED1 阳极 → 串联220Ω电阻 → Arduino 数字引脚 7红色LED2 阳极 → 串联220Ω电阻 → Arduino 数字引脚 8所有LED的阴极短脚→ 统一连接到 Arduino GND或面包板的负电源轨。为了方便查阅我将关键连接关系整理成下表元件引脚/端连接到 Arduino说明HC-SR04VCC5V电源正极GNDGND电源地Trig数字引脚 9触发测距信号Echo数字引脚 10接收回波信号绿色LED1阳极 ()数字引脚 2 (经220Ω)第一级警示绿色LED2阳极 ()数字引脚 3 (经220Ω)第二级警示黄色LED1阳极 ()数字引脚 4 (经220Ω)第三级警示黄色LED2阳极 ()数字引脚 5 (经220Ω)第四级警示黄色LED3阳极 ()数字引脚 6 (经220Ω)第五级警示红色LED1阳极 ()数字引脚 7 (经220Ω)强烈警示红色LED2阳极 ()数字引脚 8 (经220Ω)强烈警示可闪烁所有LED阴极 (-)GND共地连接3.2 搭建步骤与工艺要点在面包板上搭建这个电路是学习的好方法但如果你希望它成为一个能长期稳定工作的设备我强烈建议进行焊接。下面是我的分步搭建流程第一步规划布局。在面包板或万用板上先不要急着插元件。用笔简单画一下布局把Arduino放在一侧超声波模块预计安装位置通常要伸出外壳附近留出空间7个LED计划排成一排的位置。电源走线5V和GND尽量规划成主干道避免飞线杂乱。第二步焊接电源轨。如果使用万用板先焊接一条5V电源线和一条GND线贯穿板子作为公共电源总线。这能极大简化后续连接。第三步固定并连接LED与电阻。这是最需要耐心的一步。将7个220欧姆电阻焊接到万用板上电阻的一端预留连接至Arduino引脚。然后将每个LED的阳极长脚弯曲焊接到对应电阻的空余端。务必确保LED的极性正确。最后将所有LED的阴极短脚用导线并联焊接在一起并引出一根线连接到公共GND总线。第四步连接传感器与控制线。将HC-SR04模块通过排针焊接到万用板上或者直接用杜邦线引出。将其VCC和GND连接到电源总线。Trig和Echo信号线则用较细的导线连接到Arduino对应的引脚9和10。信号线建议不要太长如果超过20cm可以考虑用双绞线以减少干扰。第五步外壳设计与安装。一个得体的外壳能让项目从“实验品”升级为“产品”。我用的是亚克力板激光切割制作的外壳。关键点在于为超声波传感器的发射/接收头开两个大小合适的圆孔。为7个LED开一排整齐的圆孔或方孔。如果想让光线更柔和可以在LED和外壳之间加一层半透明的磨砂塑料片作为匀光板。预留Arduino的USB口和电源开关的开孔。考虑散热如果长时间工作避免完全密封。将所有部件固定到外壳内可以使用螺丝、热熔胶或3D打印的固定座。确保超声波传感器正面朝外且前方无遮挡。4. 软件程序编写与逻辑解析硬件是躯体软件才是灵魂。下面我们来编写让警示器“活”起来的Arduino程序并逐段解析其逻辑。4.1 核心测距函数与距离滤波首先我们需要一个稳定、可靠的函数来读取超声波传感器的距离值。原始读数可能会有跳动因此加入简单的软件滤波。// 定义引脚 const int trigPin 9; const int echoPin 10; const int ledPins[] {2, 3, 4, 5, 6, 7, 8}; // 7个LED对应的引脚 const int numLeds 7; // 距离阈值定义单位厘米 const int greenThreshold 150; // 小于此值第一盏绿灯亮 const int yellowThreshold 100; // 小于此值黄灯开始亮 const int redThreshold 50; // 小于此值红灯亮 long readDistance() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); // 发送10微秒的高脉冲触发 digitalWrite(trigPin, LOW); // 读取回波高电平持续时间单位微秒 long duration pulseIn(echoPin, HIGH, 30000); // 超时设置为30000微秒约5米 // 计算距离单位厘米声速取340m/s公式距离 (时间 * 0.034) / 2 long distance duration * 0.017; // 简单的异常值过滤如果距离为0或大于400则返回上一次的有效值 static long lastValidDistance 400; if (distance 2 distance 400) { // HC-SR04有效范围约为2-400cm lastValidDistance distance; } return lastValidDistance; }代码逻辑解读pulseIn(echoPin, HIGH, 30000)这个函数会等待echoPin变为高电平并开始计时直到其变回低电平返回持续的微秒数。第三个参数30000是超时时间微秒如果超过这个时间还没收到回波函数会返回0。这对应着测量超出量程约5米。distance * 0.017这是由公式距离 (时间 * 声速) / 2推导而来。声速34000 cm/s除以1000000微秒转秒再除以2得到系数约0.017。软件滤波我们用一个静态变量lastValidDistance来保存上一次的有效读数。如果本次读数在合理范围内2-400cm就更新它如果读数异常比如0或极大值就返回上一次的有效值。这能有效消除偶尔出现的跳变或误触发使显示更稳定。4.2 多级LED显示控制逻辑接下来是核心的控制逻辑根据测得的距离决定哪些LED该亮起。我们希望实现一个渐进式的效果物体越近点亮的LED越多颜色从绿变红。void updateLeds(long distance) { // 首先关闭所有LED for (int i 0; i numLeds; i) { digitalWrite(ledPins[i], LOW); } // 根据距离决定点亮哪些LED if (distance redThreshold) { // 危险距离点亮所有红灯最后两个LED并让其中一个闪烁 digitalWrite(ledPins[5], HIGH); // 红灯1常亮 // 红灯2闪烁 static unsigned long lastBlinkTime 0; static bool red2State false; if (millis() - lastBlinkTime 500) { // 500ms闪烁周期 lastBlinkTime millis(); red2State !red2State; digitalWrite(ledPins[6], red2State ? HIGH : LOW); } // 同时黄灯也全亮表示已从黄区进入红区 for (int i 2; i 4; i) { // 引脚4,5,6对应三个黄灯 digitalWrite(ledPins[i], HIGH); } // 绿灯也亮表示整个警示序列已满 digitalWrite(ledPins[0], HIGH); digitalWrite(ledPins[1], HIGH); } else if (distance yellowThreshold) { // 警告距离点亮所有黄灯和绿灯 int ledsToLight map(distance, redThreshold, yellowThreshold, numLeds, 3); ledsToLight constrain(ledsToLight, 3, numLeds - 1); for (int i 0; i ledsToLight; i) { digitalWrite(ledPins[i], HIGH); } } else if (distance greenThreshold) { // 提醒距离只点亮部分或全部绿灯 int ledsToLight map(distance, yellowThreshold, greenThreshold, 2, 0); ledsToLight constrain(ledsToLight, 0, 2); for (int i 0; i ledsToLight; i) { digitalWrite(ledPins[i], HIGH); } } else { // 安全距离所有LED熄灭或仅点亮一盏绿灯表示设备正常 // digitalWrite(ledPins[0], HIGH); // 可选设备待机指示 } }逻辑深度解析状态清除每次更新显示前先关闭所有LED这是一个好习惯避免状态残留。红区危险处理当距离小于redThreshold50cm时我们不仅点亮所有红灯还让其中一个红灯闪烁500ms周期。闪烁是一种更强的视觉警示。同时我们也点亮了所有黄灯和绿灯形成“满格”报警的效果视觉冲击力最强。黄区警告处理这是最体现“渐进”效果的部分。我们使用Arduino的map()函数将距离值映射到要点亮的LED数量上。例如当距离刚好等于yellowThreshold100cm时我们希望点亮3个LED2绿1黄。当距离无限接近redThreshold50cm时我们希望点亮6个LED2绿3黄1红。map()函数帮我们做了这个线性映射constrain()函数则确保结果不会超出LED索引范围。绿区提醒处理同理在绿区100cm到150cm我们将距离映射到0到2之间即只点亮0盏、1盏或2盏绿灯。距离越近点亮的绿灯越多。安全区在150cm以外我们可以选择让所有灯熄灭或者让一盏绿灯常亮作为设备电源指示。4.3 主循环与整体程序框架最后将以上函数整合到setup()和loop()中形成完整的程序。void setup() { // 初始化串口用于调试可选 Serial.begin(9600); // 初始化超声波传感器引脚 pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); // 初始化所有LED引脚为输出模式 for (int i 0; i numLeds; i) { pinMode(ledPins[i], OUTPUT); digitalWrite(ledPins[i], LOW); // 初始状态为熄灭 } Serial.println(Social Distance Warner Started!); } void loop() { // 1. 读取距离 long distance readDistance(); // 2. 通过串口打印距离值便于调试完成后可注释掉 Serial.print(Distance: ); Serial.print(distance); Serial.println( cm); // 3. 根据距离更新LED显示状态 updateLeds(distance); // 4. 添加一个短暂的延迟避免刷新过快导致LED闪烁或传感器误触发 // 延迟时间决定了测距的频率。100ms是一个平衡点既不会太慢也给传感器留出处理时间。 delay(100); }程序优化提示loop()中的delay(100)会阻塞程序。如果你希望设备同时能响应其他事件比如增加一个按钮来切换模式可以考虑使用非阻塞的定时方法例如用millis()来管理定时这样主循环就不会被delay卡住。但对于这个简单应用delay(100)每秒测量10次完全足够。5. 校准、调试与功能扩展5.1 系统校准与阈值调整硬件搭建和程序烧录完成后第一件事就是校准。你可能会发现实测距离与理论值有细微偏差或者希望调整警示的敏感度。校准步骤将程序中的串口调试功能打开确保Serial.begin(9600)和Serial.print语句未被注释。打开Arduino IDE的串口监视器波特率设为9600。在传感器前方放置一个物体用卷尺精确测量物体到传感器表面的距离例如50.0cm。观察串口监视器打印出的距离值。它可能显示为52cm或48cm。计算偏差。如果 consistently 偏大2cm我们可以在readDistance()函数的返回语句中进行修正return lastValidDistance - 2;。更科学的做法是修改计算系数0.017。例如实测50cm对应29000微秒那么实际系数 50.0 / 29000 ≈ 0.001724乘以1000因为公式是厘米得到0.01724。将程序中的0.017替换为0.01724即可。阈值调整建议greenThreshold世界卫生组织建议的社交距离是至少1米。我们可以将第一级提醒设置为1.5米150cm给予一个缓冲。yellowThreshold设置为1米100cm达到正式建议的社交距离底线时给出明确警告。redThreshold设置为0.5米50cm这是一个非常近的个人距离需要强烈警告。 你可以根据实际应用场景如办公桌间距、排队间隔灵活调整这些值。5.2 常见问题排查速查表制作过程中你可能会遇到一些问题。下表列出了常见故障现象、可能原因及解决方法现象可能原因排查与解决方法所有LED不亮1. 电源未接通或接反。2. Arduino未正确供电或程序未上传。3. 公共GND线未连接。1. 检查USB线或外接电源用万用表测量5V和GND间电压。2. 重新上传Blink示例程序测试Arduino本身是否正常。3. 检查所有LED阴极是否都接到了GND。只有部分LED亮或亮度异常1. LED或电阻虚焊、焊反。2. 限流电阻值错误或损坏。3. 程序中对应该LED的引脚定义错误。1. 用万用表通断档检查LED和电阻通路。2. 确认电阻色环或直接测量电阻值。3. 检查ledPins数组中的引脚号与实际接线是否一致。串口显示距离为0或恒定超大值1. 超声波模块Trig或Echo线接触不良。2. 模块损坏。3. 传感器前方有吸音材料如海绵、厚布。4. 测量距离过近2cm或过远4m。1. 重新插拔杜邦线或检查焊接点。2. 更换一个HC-SR04模块测试。3. 确保传感器前方空旷对准硬质表面墙、木板。4. 在有效量程内测试。距离读数跳动剧烈1. 传感器附近有风扇、空调出风口等气流干扰。2. 测量表面不平整或角度倾斜。3. 电源噪声。1. 远离气流源测试。2. 对准平整、垂直的物体表面测量。3. 尝试给Arduino使用独立的电池供电排除电脑USB口噪声。红灯闪烁不正常常亮或不闪1.updateLeds函数中闪烁逻辑的millis()计时被delay()干扰。2. 红灯对应的引脚模式未设置为OUTPUT。1. 确保闪烁逻辑基于millis()且loop中的delay不能太长如超过闪烁周期。2. 检查setup()中是否初始化了所有LED引脚。5.3 高级功能扩展思路基础版本完成后这个平台还有巨大的扩展潜力添加声音报警连接一个无源蜂鸣器到另一个数字引脚。在进入红区时不仅红灯闪烁还可以让蜂鸣器发出“滴滴”声甚至播放一段警报音调实现声光双重报警。增加显示模块接上一个OLED屏幕如SSD1306可以实时显示精确的距离数值并显示“安全”、“警告”、“危险”等文字提示信息更丰富。数据记录与上传利用Leonardo的USB HID功能或者增加一个Wi-Fi模块如ESP-01S可以将违规靠近的次数和时间戳记录下来并通过串口发送到电脑甚至上传到物联网平台进行统计分析。低功耗优化如果希望用电池供电可以将测距间隔加大如每秒1次在loop中大部分时间让Arduino进入休眠模式需要使用特定的低功耗库只有定时器唤醒时才进行测量和显示这样可以极大延长电池寿命。方向性增强单个HC-SR04的探测角度有限。可以尝试使用两个或多个传感器以一定角度布置形成一个扇形的监测区域减少探测盲区。这个项目最吸引我的地方就在于它用一个非常简单的硬件组合实现了一个有实际意义的应用。从读取一个传感器到控制几个LED再到加入逻辑和状态判断它完整地展示了一个嵌入式系统从感知、处理到执行的全过程。当你看到自己制作的设备能根据外界距离做出准确反应时那种成就感是无可替代的。希望这份详细的教程能帮你顺利复现并激发你更多的创意。
基于Arduino与超声波传感器的低成本社交距离警示器设计与实现
发布时间:2026/6/3 16:30:30
1. 项目概述与核心思路最近在整理工作室的旧项目时翻出了一个几年前做的“社交距离警示器”原型。当时正值特殊时期大家对于保持物理距离格外关注。市面上虽然有一些成品设备但要么价格不菲要么功能单一。作为一个喜欢动手的硬件爱好者我决定用手头最常见的Arduino开发板、一个超声波传感器和几个LED灯自己做一个既直观又实用的距离警示装置。这个装置的核心逻辑非常简单它就像一个无声的“电子哨兵”持续监测前方一定范围内的障碍物比如人。当有物体进入“安全区”边缘时绿灯会亮起作为温和提醒随着物体继续靠近黄灯亮起表示距离正在缩短一旦物体进入预设的“危险距离”内红灯就会亮起并可能伴随闪烁发出明确的“请保持距离”警告。整个系统成本极低核心部件加起来可能不到50元但实现的效果却非常直观有效非常适合放在办公桌隔断、商店柜台、图书馆自习区等半固定场所使用。我选择Arduino Leonardo作为主控一方面是因为它价格适中、性能足够另一方面是它兼容性极佳有丰富的社区资源和库支持。传感器方面HC-SR04超声波模块是经典之选它非接触式测量、成本低、精度对于这个应用场景厘米级完全足够。显示部分我没有使用复杂的屏幕而是采用了最直接的红、黄、绿三色LED灯通过点亮不同数量和颜色的灯来传递信息这种设计无需文字说明任何人都能一眼看懂状态符合“警示器”简单直接的设计初衷。2. 核心器件选型与原理剖析2.1 主控单元为什么是Arduino Leonardo在众多Arduino板卡中我选择了Leonardo。可能有人会问用更便宜的Uno或者更强大的Mega不行吗当然可以但Leonardo有几个独特的优势让它成为这个项目的“甜点”选择。首先USB通信协议。Arduino Uno/Nano使用的是USB转串口芯片如CH340、FT232而Leonardo以及Micro、Due原生集成了USB功能其ATmega32U4微控制器本身就能被电脑识别为USB设备。这意味着Leonardo可以模拟键盘、鼠标、游戏手柄等HID设备。虽然在这个警示器项目中我们暂时用不到这个高级功能但它为未来升级留下了巨大空间——比如当检测到有人持续闯入危险距离时可以让Leonardo模拟键盘按下“静音”键自动将视频会议静音这个想法是不是很酷其次引脚资源与功耗。Leonardo提供了20个数字I/O引脚其中7个支持PWM和12个模拟输入引脚对于驱动几个LED和一个传感器绰绰有余且仍有大量余量用于扩展。它的功耗也比一些高性能板卡要低适合长期插电运行。最后是性价比它的价格通常只比Uno略高一点但获得了更现代的USB功能和更好的扩展性属于“加量不加价”。注意如果你手头只有Arduino Uno完全没问题本项目代码和接线方式与Uno完全兼容。Leonardo的优势更多体现在未来功能扩展的潜力上。2.2 感知核心HC-SR04超声波测距模块详解HC-SR04几乎是电子爱好者入门测距的首选模块价格通常在5元以内。它的工作原理是超声波渡越时间法。模块上有两个圆柱形“眼睛”一个是超声波发射器T一个是接收器R。其工作流程如下主控给Trig引脚一个至少10微秒的高电平脉冲触发模块发射一束8个40kHz的超声波。超声波在空气中传播遇到障碍物后反射回来。模块的接收器检测到回波Echo引脚会输出一个高电平脉冲。这个高电平脉冲的持续时间正好等于超声波从发射到返回所经历的时间。那么距离怎么算我们知道在空气中声速约为340米/秒随温度变化但常温下可近似。距离等于速度乘以时间。但要注意Echo引脚的高电平时间是超声波“往返”一趟的时间所以单程距离需要除以2。计算公式为距离 (高电平时间 × 声速) / 2在代码中声速通常取34000厘米/秒换算单位。高电平时间由pulseIn()函数读取单位是微秒百万分之一秒。所以最终计算为距离(厘米) (高电平时间(微秒) * 0.034) / 2简化后就是距离(厘米) 高电平时间(微秒) * 0.017。例如如果pulseIn()读到2941微秒那么距离 ≈ 2941 * 0.017 ≈ 50厘米。实操心得HC-SR04的测量角度约为15度属于小角度探测指向性较好但这也意味着需要将它对准你想要监测的区域。它的有效测距是2cm到400cm但超过200cm后回波信号变弱精度和稳定性会下降。对于社交距离警示我们通常关注50cm到200cm的范围正好是它的最佳工作区间。2.3 警示输出多色LED阵列的驱动策略为什么用多个LED而不是一个RGB LED这里主要考虑的是可视角度和警示效果。一个RGB LED虽然能变色但它的发光点小可视角度有限且亮度可能不足。而使用多个离散的LED比如2绿、3黄、2红可以将它们排列成一条直线或弧形模拟“信号强度条”的效果视觉上更直观也从不同角度都更容易看到。我们需要决定如何驱动这7个LED。最简单的方法是为每个LED分配一个独立的I/O口但这会占用7个引脚。另一种方法是使用移位寄存器如74HC595用3个引脚控制无限多个LED。但对于只有7个灯的项目为了简化我选择了直接驱动因为Leonardo的引脚足够用。限流电阻的计算是关键一步。Arduino的I/O口输出电压是5V单个LED的典型正向压降Vf根据不同颜色而不同红光约1.8-2.2V黄/绿光约2.0-2.4V。I/O口最大安全输出电流建议不超过20mA我们通常设计在10-15mA以获得良好亮度且安全。以红色LEDVf2.0V为例计算限流电阻R (Vcc - Vf) / I。Vcc是5VI取15mA0.015A。则R (5 - 2.0) / 0.015 3.0 / 0.015 200欧姆。我们可以取一个接近的标准值如220欧姆。重要提示务必为每个LED串联一个独立的限流电阻绝对不能将多个LED并联后共用一个电阻。因为即使同一批次的LED其正向压降也有微小差异并联会导致压降小的那个LED流过更大电流从而过热烧毁。这是新手最容易犯的硬件错误之一。3. 硬件电路设计与搭建详解3.1 电路连接图与接线表根据上面的选型我们来规划具体的连接方式。为了清晰起见我建议将LED按颜色分组并排列成一条线这样点亮时从绿到红的变化就像一道“距离光栅”。元件清单Arduino Leonardo x1HC-SR04超声波模块 x15mm LED绿色 x2黄色 x3红色 x2220欧姆电阻 x7用于LED限流1k欧姆电阻 x1可选用于Echo引脚上拉部分模块不需要面包板、杜邦线若干外接电源如9V电池适配器或USB供电接线示意图文字描述超声波模块连接HC-SR04 VCC → Arduino 5VHC-SR04 GND → Arduino GNDHC-SR04 Trig → Arduino 数字引脚 9HC-SR04 Echo → Arduino 数字引脚 10LED阵列连接假设排列顺序为绿1绿2黄1黄2黄3红1红2绿色LED1 阳极长脚→ 串联220Ω电阻 → Arduino 数字引脚 2绿色LED2 阳极 → 串联220Ω电阻 → Arduino 数字引脚 3黄色LED1 阳极 → 串联220Ω电阻 → Arduino 数字引脚 4黄色LED2 阳极 → 串联220Ω电阻 → Arduino 数字引脚 5黄色LED3 阳极 → 串联220Ω电阻 → Arduino 数字引脚 6红色LED1 阳极 → 串联220Ω电阻 → Arduino 数字引脚 7红色LED2 阳极 → 串联220Ω电阻 → Arduino 数字引脚 8所有LED的阴极短脚→ 统一连接到 Arduino GND或面包板的负电源轨。为了方便查阅我将关键连接关系整理成下表元件引脚/端连接到 Arduino说明HC-SR04VCC5V电源正极GNDGND电源地Trig数字引脚 9触发测距信号Echo数字引脚 10接收回波信号绿色LED1阳极 ()数字引脚 2 (经220Ω)第一级警示绿色LED2阳极 ()数字引脚 3 (经220Ω)第二级警示黄色LED1阳极 ()数字引脚 4 (经220Ω)第三级警示黄色LED2阳极 ()数字引脚 5 (经220Ω)第四级警示黄色LED3阳极 ()数字引脚 6 (经220Ω)第五级警示红色LED1阳极 ()数字引脚 7 (经220Ω)强烈警示红色LED2阳极 ()数字引脚 8 (经220Ω)强烈警示可闪烁所有LED阴极 (-)GND共地连接3.2 搭建步骤与工艺要点在面包板上搭建这个电路是学习的好方法但如果你希望它成为一个能长期稳定工作的设备我强烈建议进行焊接。下面是我的分步搭建流程第一步规划布局。在面包板或万用板上先不要急着插元件。用笔简单画一下布局把Arduino放在一侧超声波模块预计安装位置通常要伸出外壳附近留出空间7个LED计划排成一排的位置。电源走线5V和GND尽量规划成主干道避免飞线杂乱。第二步焊接电源轨。如果使用万用板先焊接一条5V电源线和一条GND线贯穿板子作为公共电源总线。这能极大简化后续连接。第三步固定并连接LED与电阻。这是最需要耐心的一步。将7个220欧姆电阻焊接到万用板上电阻的一端预留连接至Arduino引脚。然后将每个LED的阳极长脚弯曲焊接到对应电阻的空余端。务必确保LED的极性正确。最后将所有LED的阴极短脚用导线并联焊接在一起并引出一根线连接到公共GND总线。第四步连接传感器与控制线。将HC-SR04模块通过排针焊接到万用板上或者直接用杜邦线引出。将其VCC和GND连接到电源总线。Trig和Echo信号线则用较细的导线连接到Arduino对应的引脚9和10。信号线建议不要太长如果超过20cm可以考虑用双绞线以减少干扰。第五步外壳设计与安装。一个得体的外壳能让项目从“实验品”升级为“产品”。我用的是亚克力板激光切割制作的外壳。关键点在于为超声波传感器的发射/接收头开两个大小合适的圆孔。为7个LED开一排整齐的圆孔或方孔。如果想让光线更柔和可以在LED和外壳之间加一层半透明的磨砂塑料片作为匀光板。预留Arduino的USB口和电源开关的开孔。考虑散热如果长时间工作避免完全密封。将所有部件固定到外壳内可以使用螺丝、热熔胶或3D打印的固定座。确保超声波传感器正面朝外且前方无遮挡。4. 软件程序编写与逻辑解析硬件是躯体软件才是灵魂。下面我们来编写让警示器“活”起来的Arduino程序并逐段解析其逻辑。4.1 核心测距函数与距离滤波首先我们需要一个稳定、可靠的函数来读取超声波传感器的距离值。原始读数可能会有跳动因此加入简单的软件滤波。// 定义引脚 const int trigPin 9; const int echoPin 10; const int ledPins[] {2, 3, 4, 5, 6, 7, 8}; // 7个LED对应的引脚 const int numLeds 7; // 距离阈值定义单位厘米 const int greenThreshold 150; // 小于此值第一盏绿灯亮 const int yellowThreshold 100; // 小于此值黄灯开始亮 const int redThreshold 50; // 小于此值红灯亮 long readDistance() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); // 发送10微秒的高脉冲触发 digitalWrite(trigPin, LOW); // 读取回波高电平持续时间单位微秒 long duration pulseIn(echoPin, HIGH, 30000); // 超时设置为30000微秒约5米 // 计算距离单位厘米声速取340m/s公式距离 (时间 * 0.034) / 2 long distance duration * 0.017; // 简单的异常值过滤如果距离为0或大于400则返回上一次的有效值 static long lastValidDistance 400; if (distance 2 distance 400) { // HC-SR04有效范围约为2-400cm lastValidDistance distance; } return lastValidDistance; }代码逻辑解读pulseIn(echoPin, HIGH, 30000)这个函数会等待echoPin变为高电平并开始计时直到其变回低电平返回持续的微秒数。第三个参数30000是超时时间微秒如果超过这个时间还没收到回波函数会返回0。这对应着测量超出量程约5米。distance * 0.017这是由公式距离 (时间 * 声速) / 2推导而来。声速34000 cm/s除以1000000微秒转秒再除以2得到系数约0.017。软件滤波我们用一个静态变量lastValidDistance来保存上一次的有效读数。如果本次读数在合理范围内2-400cm就更新它如果读数异常比如0或极大值就返回上一次的有效值。这能有效消除偶尔出现的跳变或误触发使显示更稳定。4.2 多级LED显示控制逻辑接下来是核心的控制逻辑根据测得的距离决定哪些LED该亮起。我们希望实现一个渐进式的效果物体越近点亮的LED越多颜色从绿变红。void updateLeds(long distance) { // 首先关闭所有LED for (int i 0; i numLeds; i) { digitalWrite(ledPins[i], LOW); } // 根据距离决定点亮哪些LED if (distance redThreshold) { // 危险距离点亮所有红灯最后两个LED并让其中一个闪烁 digitalWrite(ledPins[5], HIGH); // 红灯1常亮 // 红灯2闪烁 static unsigned long lastBlinkTime 0; static bool red2State false; if (millis() - lastBlinkTime 500) { // 500ms闪烁周期 lastBlinkTime millis(); red2State !red2State; digitalWrite(ledPins[6], red2State ? HIGH : LOW); } // 同时黄灯也全亮表示已从黄区进入红区 for (int i 2; i 4; i) { // 引脚4,5,6对应三个黄灯 digitalWrite(ledPins[i], HIGH); } // 绿灯也亮表示整个警示序列已满 digitalWrite(ledPins[0], HIGH); digitalWrite(ledPins[1], HIGH); } else if (distance yellowThreshold) { // 警告距离点亮所有黄灯和绿灯 int ledsToLight map(distance, redThreshold, yellowThreshold, numLeds, 3); ledsToLight constrain(ledsToLight, 3, numLeds - 1); for (int i 0; i ledsToLight; i) { digitalWrite(ledPins[i], HIGH); } } else if (distance greenThreshold) { // 提醒距离只点亮部分或全部绿灯 int ledsToLight map(distance, yellowThreshold, greenThreshold, 2, 0); ledsToLight constrain(ledsToLight, 0, 2); for (int i 0; i ledsToLight; i) { digitalWrite(ledPins[i], HIGH); } } else { // 安全距离所有LED熄灭或仅点亮一盏绿灯表示设备正常 // digitalWrite(ledPins[0], HIGH); // 可选设备待机指示 } }逻辑深度解析状态清除每次更新显示前先关闭所有LED这是一个好习惯避免状态残留。红区危险处理当距离小于redThreshold50cm时我们不仅点亮所有红灯还让其中一个红灯闪烁500ms周期。闪烁是一种更强的视觉警示。同时我们也点亮了所有黄灯和绿灯形成“满格”报警的效果视觉冲击力最强。黄区警告处理这是最体现“渐进”效果的部分。我们使用Arduino的map()函数将距离值映射到要点亮的LED数量上。例如当距离刚好等于yellowThreshold100cm时我们希望点亮3个LED2绿1黄。当距离无限接近redThreshold50cm时我们希望点亮6个LED2绿3黄1红。map()函数帮我们做了这个线性映射constrain()函数则确保结果不会超出LED索引范围。绿区提醒处理同理在绿区100cm到150cm我们将距离映射到0到2之间即只点亮0盏、1盏或2盏绿灯。距离越近点亮的绿灯越多。安全区在150cm以外我们可以选择让所有灯熄灭或者让一盏绿灯常亮作为设备电源指示。4.3 主循环与整体程序框架最后将以上函数整合到setup()和loop()中形成完整的程序。void setup() { // 初始化串口用于调试可选 Serial.begin(9600); // 初始化超声波传感器引脚 pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); // 初始化所有LED引脚为输出模式 for (int i 0; i numLeds; i) { pinMode(ledPins[i], OUTPUT); digitalWrite(ledPins[i], LOW); // 初始状态为熄灭 } Serial.println(Social Distance Warner Started!); } void loop() { // 1. 读取距离 long distance readDistance(); // 2. 通过串口打印距离值便于调试完成后可注释掉 Serial.print(Distance: ); Serial.print(distance); Serial.println( cm); // 3. 根据距离更新LED显示状态 updateLeds(distance); // 4. 添加一个短暂的延迟避免刷新过快导致LED闪烁或传感器误触发 // 延迟时间决定了测距的频率。100ms是一个平衡点既不会太慢也给传感器留出处理时间。 delay(100); }程序优化提示loop()中的delay(100)会阻塞程序。如果你希望设备同时能响应其他事件比如增加一个按钮来切换模式可以考虑使用非阻塞的定时方法例如用millis()来管理定时这样主循环就不会被delay卡住。但对于这个简单应用delay(100)每秒测量10次完全足够。5. 校准、调试与功能扩展5.1 系统校准与阈值调整硬件搭建和程序烧录完成后第一件事就是校准。你可能会发现实测距离与理论值有细微偏差或者希望调整警示的敏感度。校准步骤将程序中的串口调试功能打开确保Serial.begin(9600)和Serial.print语句未被注释。打开Arduino IDE的串口监视器波特率设为9600。在传感器前方放置一个物体用卷尺精确测量物体到传感器表面的距离例如50.0cm。观察串口监视器打印出的距离值。它可能显示为52cm或48cm。计算偏差。如果 consistently 偏大2cm我们可以在readDistance()函数的返回语句中进行修正return lastValidDistance - 2;。更科学的做法是修改计算系数0.017。例如实测50cm对应29000微秒那么实际系数 50.0 / 29000 ≈ 0.001724乘以1000因为公式是厘米得到0.01724。将程序中的0.017替换为0.01724即可。阈值调整建议greenThreshold世界卫生组织建议的社交距离是至少1米。我们可以将第一级提醒设置为1.5米150cm给予一个缓冲。yellowThreshold设置为1米100cm达到正式建议的社交距离底线时给出明确警告。redThreshold设置为0.5米50cm这是一个非常近的个人距离需要强烈警告。 你可以根据实际应用场景如办公桌间距、排队间隔灵活调整这些值。5.2 常见问题排查速查表制作过程中你可能会遇到一些问题。下表列出了常见故障现象、可能原因及解决方法现象可能原因排查与解决方法所有LED不亮1. 电源未接通或接反。2. Arduino未正确供电或程序未上传。3. 公共GND线未连接。1. 检查USB线或外接电源用万用表测量5V和GND间电压。2. 重新上传Blink示例程序测试Arduino本身是否正常。3. 检查所有LED阴极是否都接到了GND。只有部分LED亮或亮度异常1. LED或电阻虚焊、焊反。2. 限流电阻值错误或损坏。3. 程序中对应该LED的引脚定义错误。1. 用万用表通断档检查LED和电阻通路。2. 确认电阻色环或直接测量电阻值。3. 检查ledPins数组中的引脚号与实际接线是否一致。串口显示距离为0或恒定超大值1. 超声波模块Trig或Echo线接触不良。2. 模块损坏。3. 传感器前方有吸音材料如海绵、厚布。4. 测量距离过近2cm或过远4m。1. 重新插拔杜邦线或检查焊接点。2. 更换一个HC-SR04模块测试。3. 确保传感器前方空旷对准硬质表面墙、木板。4. 在有效量程内测试。距离读数跳动剧烈1. 传感器附近有风扇、空调出风口等气流干扰。2. 测量表面不平整或角度倾斜。3. 电源噪声。1. 远离气流源测试。2. 对准平整、垂直的物体表面测量。3. 尝试给Arduino使用独立的电池供电排除电脑USB口噪声。红灯闪烁不正常常亮或不闪1.updateLeds函数中闪烁逻辑的millis()计时被delay()干扰。2. 红灯对应的引脚模式未设置为OUTPUT。1. 确保闪烁逻辑基于millis()且loop中的delay不能太长如超过闪烁周期。2. 检查setup()中是否初始化了所有LED引脚。5.3 高级功能扩展思路基础版本完成后这个平台还有巨大的扩展潜力添加声音报警连接一个无源蜂鸣器到另一个数字引脚。在进入红区时不仅红灯闪烁还可以让蜂鸣器发出“滴滴”声甚至播放一段警报音调实现声光双重报警。增加显示模块接上一个OLED屏幕如SSD1306可以实时显示精确的距离数值并显示“安全”、“警告”、“危险”等文字提示信息更丰富。数据记录与上传利用Leonardo的USB HID功能或者增加一个Wi-Fi模块如ESP-01S可以将违规靠近的次数和时间戳记录下来并通过串口发送到电脑甚至上传到物联网平台进行统计分析。低功耗优化如果希望用电池供电可以将测距间隔加大如每秒1次在loop中大部分时间让Arduino进入休眠模式需要使用特定的低功耗库只有定时器唤醒时才进行测量和显示这样可以极大延长电池寿命。方向性增强单个HC-SR04的探测角度有限。可以尝试使用两个或多个传感器以一定角度布置形成一个扇形的监测区域减少探测盲区。这个项目最吸引我的地方就在于它用一个非常简单的硬件组合实现了一个有实际意义的应用。从读取一个传感器到控制几个LED再到加入逻辑和状态判断它完整地展示了一个嵌入式系统从感知、处理到执行的全过程。当你看到自己制作的设备能根据外界距离做出准确反应时那种成就感是无可替代的。希望这份详细的教程能帮你顺利复现并激发你更多的创意。