如果你正在做一个需要统计通过数量的项目不管是产线上的零件、仓库里的包裹还是实验室里的样本“知光”这个名字你可能不陌生——它是我花了大半年时间打磨的一套低成本实时计数方案而整套系统最核心、也最容易翻车的部分就是计数模块。计数模块听起来简单东西过去数量加一。但真正把它放到现场你会发现电磁干扰、灰尘污染、物料遮挡方式、传感器响应速度每一个变量都能让数字变得离谱。这篇文章不打算讲PPT式的架构图而是老实记录我在知光项目里从硬件选型、信号调理、软件状态机到看板展示踩过的坑和沉淀下来的方法。内容既适合正在选型传感器的硬件工程师也适合写计数逻辑的嵌入式开发者甚至对想自己搭一套计数系统的创客同样有参考价值。1. 项目思路拆解计数模块到底要解决什么问题1.1 “知光”的含义与核心设计理念知光这个名字来源于项目的核心感知方式通过光线的通断变化识别物体的通过。当物体经过传感器时光路被遮挡传感器输出电平翻转MCU检测到这个翻转就知道“有一件东西过去了”。这听起来像最基础的光电开关应用但真正深入做下去你会发现“知道光变了”只是第一步难点在于知道这次变化是有效的事件而不是噪声。设计理念可以概括为三点。第一感知层用成熟的光电传感方案不追求花哨保证硬件成本和可靠性可接受。第二判定层把计数这件事从“数脉冲”上升到“识别事件”用状态机把抖动脉冲、反复遮挡、连续通过这些现场情况过滤掉。第三数据层把计数结果以统一格式上报方便接入产线看板、MES系统或者自建的统计页面。整个模块的定位不是做一个玩具Demo而是能在车间、仓库、实验室这种实际环境里长期运行的部件。1.2 计数需求的三层拆解我在做需求分析的时候把计数需求拆成了三层每一层对应不同的实现重点。第一层是物理事件感知。物体是否出现在检测区域传感器能不能可靠地给出信号。这一层最容易踩坑的是选型错误比如漫反射传感器遇到黑色物体检测距离急剧缩短或者对射传感器被灰尘挡住导致信号没法恢复。第二层是信号去噪与事件判定。传感器输出的原始波形往往带着毛刺物体边缘可能反射多次电机启停会引入干扰如果不做消抖就把信号直接接到中断引脚计数结果会非常离谱。第三层是数据记录与可视化。计数结果存在哪里怎么上传断网时怎么办看板怎么展示多通道怎么管理。这一层虽然不直接影响单个计数的准确性却决定了系统能不能真正投入使用。这三层是一层层往上叠的。底层硬件不可靠上层软件做得再好也没用软件逻辑不严谨再贵的传感器也会数错数据链路不通计数再准也只是设备上的一个数字。所以我在知光项目里始终强调每一层都要独立验证不能等全部做完再回来找问题。1.3 适用场景分析与影响范围知光计数模块可以覆盖的场景比想象中广。最典型的应用是产线产量统计传送带上的零件经过光电传感器系统自动记录每个班次的产出数量。这个场景最看重的是长时间运行不出错因为一个班次动辄几千上万个零件漏掉或重复几个可能就会被现场人员质疑。其次是仓库进出库计数包裹或料箱通过输送线时自动计数帮助核对发货数量。再次是自动化设备动作循环计数比如注塑机每完成一次合模动作就计数一次用于统计设备利用率。还有一些比较轻量的场景比如展会门口统计人流、实验室记录样本试管通过数量这些场景不需要采集任何生物信息只统计通过数量合规风险很低。影响范围要从数据源头来看。计数模块是整个系统里离物理世界最近的一环它给出的数字会直接进入生产报表、库存台账和设备效率计算。如果源头数据不可信后面所有分析都是空中楼阁。因此这套模块的设计目标很明确单次计数准确率达到99.9%以上长时间运行不漂移断电重启后计数不丢失多通道数据能统一汇总。2. 硬件选型与信号调理计数准确的第一道关卡2.1 三类光电传感器的选型对比光电传感器看起来都差不多实际用起来差别很大。我在知光项目里先后试过三类这里把它们的特性列出来供参考。类型检测方式检测距离抗干扰能力成本适用场景对射型发射端与接收端分离物体遮挡光线可达数十米较强不受背景物体影响中高传送带零件、包裹安装空间允许时优先选漫反射型发射与接收一体靠物体反射光线几十厘米到数米较弱颜色、角度、背景反射都影响低检测体积较大且表面反光较好的物体槽型光电物体穿过U形槽遮挡光路几毫米到几厘米强结构固定低小零件、计数轮、纸张卡片等薄片类从经验来看计数类应用最优先选对射型或者槽型。它们在原理上就只认“光路有没有被遮断”不依赖物体表面的反射特性所以黑色物体、透明物体也能可靠检测。漫反射型虽然安装方便但遇到深色表面、斜面、高反光背景时容易误判我通常只在检测对象是规则浅色箱体的场景里用它。选型还需要注意传感器输出类型。常见的输出有NPN开集输出、PNP输出、继电器输出。MCU读取电平变化最好的是NPN或PNP输出继电器输出响应太慢不适合高频计数。我用的较多的是NPN开集输出配合上拉电阻直接接到MCU引脚逻辑简单接线也省事。2.2 从传感器到MCU上拉、滤波与整形传感器信号不能直接一根线接到MCU引脚就算完事中间有几个细节值得认真处理。以NPN输出为例传感器不导通时引脚通过上拉电阻被拉到高电平导通时引脚被拉到低电平MCU检测的就是这个电平跳变。上拉电阻我一般选4.7kΩ到10kΩ阻值太小会增加功耗太大则容易被分布电容拖慢边沿。现场信号往往带着毛刺特别是电机、变频器附近传感器供电线上会出现几十毫伏到几伏的噪声。我的做法是在传感器输出和MCU引脚之间加一级RC低通滤波电阻选1kΩ电容选100nF时间常数约0.1ms既不会滤掉正常的物体遮挡信号又能吸收大部分高频毛刺。如果信号还有严重的沿抖动可以再加施密特触发器整形常见的74HC14或者带施密特输入的MCU引脚都能解决边沿慢导致的重复触发问题。更强硬的保护手段是光耦隔离。传感器在现场MCU在控制箱里两者地电位可能不一样长距离走线也容易感应浪涌。用光耦把信号隔离后再进MCU可以有效避免地环路噪声和静电损伤。知光模块里我给每一路传感器都设计了光耦隔离实测在电柜附近频繁启停电机的情况下计数不再出现偶发跳变。2.3 主控选型与通信接口主控芯片的选择取决于计数速率和通信需求。如果只是简单计数一个STM32F103或者国产GD32F103就足够内部定时器资源多外部中断数量够用价格还很低。如果还需要跑网络上报我会用ESP32自带的Wi-Fi和蓝牙能直接连MQTT省掉一颗单独的通信芯片。对纯工业场景也可以选带CAN或者RS485接口的芯片走Modbus协议接到PLC或上位机。通信接口方面知光模块预留了三种方式。第一种是串口TTL电平直接输出计数结果适合调试和短距离对接。第二种是RS485走Modbus RTU工业现场最常用抗干扰能力强一根总线可以挂多台设备。第三种是Wi-Fi走MQTT适合没有布线的仓库、门店配合配网功能和看板系统非常方便。我的经验是不要把通信做成只用某一种至少保留串口因为现场调试时串口是最可靠的救命通道。3. 软件逻辑从脉冲毛刺到可信计数的关键实现3.1 为什么不能直接数脉冲上升沿很多第一次做计数模块的人会把传感器输出直接接到中断引脚上升沿计数加一。这个方案在实验室里通常能跑通一到现场就露馅。问题在于一个物体通过时产生的电平变化不只是一次干净的跳变。物体边缘往往不是完全垂直于光路传送带振动也会让物体在传感器前晃光路被部分遮挡后很快又恢复再遮挡这就会形成一串窄脉冲。如果直接把边沿送给计数器同一个物体可能被记成三四个。另外传感器本身的响应也有延迟和回差慢速移动的物体可能让输出信号长时间处于中间状态产生抖动。还有电磁干扰继电器吸合或变频器启动的瞬间长线上会感应出几十纳秒的电压毛刺如果恰好接近阈值就能产生一个假脉冲。所以我在软硬件上采用了双重手段硬件上做RC滤波和施密特整形把大部分毛刺挡在MCU外面软件上做时间窗口判定只有遮挡信号持续超过一定时间才认为是一次有效通过。两个手段配合误触发率才能压到极低。3.2 状态机消抖手写可靠的通过判定软件消抖的核心是状态机。我这里给出一套经过现场验证的判定逻辑用C语言伪代码表示逻辑上有四个状态空闲、确认、锁定。每隔5ms扫描一次传感器输入。typedef enum { IDLE, // 无遮挡等待事件 CONFIRMING, // 检测到遮挡正在消抖确认 LOCKED // 已计数等待遮挡结束并冷却 } state_t; static state_t state IDLE; static uint32_t enter_ms 0; static uint32_t last_keep_ms 0; #define HOLD_MS 20 // 遮挡持续超过20ms才算有效 #define COOL_MS 80 // 信号恢复后冷却80ms才能再次计数 void update_count(uint32_t now_ms) { bool blocked read_sensor_blocked(); switch (state) { case IDLE: if (blocked) { state CONFIRMING; enter_ms now_ms; } break; case CONFIRMING: if (!blocked) { // 抖动或异物短暂掠过回到空闲 state IDLE; } else if (now_ms - enter_ms HOLD_MS) { // 遮挡时间足够长确认一次有效通过 count; state LOCKED; last_keep_ms now_ms; } break; case LOCKED: if (blocked) { // 物体还在传感器前持续刷新时间 last_keep_ms now_ms; } else if (now_ms - last_keep_ms COOL_MS) { // 遮挡已结束且冷却完成准备下一次计数 state IDLE; } break; } }这个状态机的逻辑并不复杂关键在于把“有效遮挡”和“干扰脉冲”区分开。HOLD_MS设得太小会过滤不掉窄干扰设得太大则快速通过的物体会被漏计。我的经验是先量通过遮挡的最短时间取它的三分之一作为HOLD_MS的上限再留出余量。比如传送带上最小零件遮挡时间为60msHOLD_MS可以设15到20ms。LOCKED状态解决的是物体还没完全离开时不能再次计数的问题。如果两个物体挨得很近前一个还没走完后一个已经进入检测区传感器信号会一直保持遮挡状态这时候不应计数。等到信号恢复再等COOL_MS时间让传感器输出完全回落到稳定的高电平才允许识别下一个事件。3.3 快速连续通过的速度上限与补偿软件消抖会限制最大计数速度。最直接的计算方式是一个完整计数周期 物体遮挡时间 冷却时间。假设物体遮挡时间为80ms冷却时间为80ms那么理论最大计数速率是每秒约6个。如果产线速度更高就需要调整HOLD_MS和COOL_MS或者改用硬件计数器。对于非常快的应用比如每分钟几百次的冲压计数软件轮询可能应付不来。这时我会用MCU的硬件计数功能比如STM32的定时器外部时钟模式或者编码器模式把传感器信号直接接到定时器的输入引脚由硬件对边沿计数MCU只负责周期性读取计数值。这种方式可以轻松应付几十kHz的信号但要注意的是硬件计数无法做复杂的消抖所以前端信号调理电路必须做得足够干净。还有一种情况是双传感器互补判定。在传送带的两个位置各放一个传感器检测物体的到达顺序可以判断物体的运动方向还能在两个传感器的信号同时有效时判定为一次完整的通过。这个方案对方向区分有硬性要求的场景很实用代价是硬件成本翻倍。我在知光模块里保留了第二路传感器接口需要时扩展就行。4. 完整落地流程从原理验证到可视化看板4.1 原型搭建与测试方法从原理到实物我建议先搭一个最简原型再往后推进。原型阶段的硬件清单很基础一块STM32或ESP32开发板、一个槽型光电或对射传感器、一个面包板、几根杜邦线、一个万用表。先把传感器接到IO口用串口打印原始电平状态手动拿物体通过传感器观察串口输出的变化。这一步其实是在验证最底层的东西传感器接线是否正确上拉电阻有没有接信号极性对不对电平翻转是否干脆。别小看这个环节我遇到过很多次接反信号、供电电压不足导致传感器输出异常的问题如果直接跳到写完整代码往往会被这些低级错误折磨一两天。原型验证通过后再把状态机代码烧进去用同一物体反复通过测试连续计数的一致性。测试物料要覆盖不同情况。至少准备黑色、白色、金属、透明四种样品分别测试。黑色物体对漫反射传感器不友好透明物体对红外对射传感器可能检测不到这些都要在原型阶段暴露出来。我还会用一块薄挡板模拟快速遮蔽和恢复用来验证HOLD_MS参数设得是否合理。4.2 固件参数配置与发布固件里不应该写死太多参数我把关键参数全部做成可配置项烧录后用串口命令或者配置文件就能修改。这个做法在进场调试时非常省事不用为了改一个冷却时间反复重新烧录固件。参数默认值说明HOLD_MS20遮挡确认时间决定最快可识别速度COOL_MS80计数后冷却时间防止连续重复计数通道使能1哪一路传感器参与计数计数上限999999超出后自动清零或保持上报间隔5s定时上报计数值也可边沿变化即时上报调试模式下固件还要输出事件日志每条日志带时间戳和状态机迁移信息。现场出现问题的时候靠这些日志可以快速还原当时的信号时序而不用靠猜。我自己习惯把日志写成一行一条比如“12345ms stateCONFIRMING blocked1”方便在串口助手或者终端里直接查看。发布固件前要做一个连续压力测试。我会用一个小电机带动圆盘盘上固定一个挡片让它持续转动来模拟连续通过跑大约一万次记录误计次数。早期版本我遇到过一万次里多计了三次的情况后来发现是HOLD_MS偏小挡片边缘在临界位置抖动被当成了两次。调整参数后再次测试误计数降到零这台测试工装也一直保留下来每次改代码都重新跑一遍。4.3 数据上报与可视化看板搭建计数结果只在本地设备里没有意义必须能汇总到看板上。知光模块的数据上报方式我做了两种一种是传统工业现场用RS485 ModbusPLC或上位机定时轮询读取另一种是Wi-Fi设备直接走MQTT上报JSON格式数据适合轻量级看板。MQTT上报的数据结构设计得比较简单核心是设备标识、时间戳和各个通道的计数值例如{ device_id: zhiguang-count-01, ts: 1712312345, channels: { ch1: 12345, ch2: 9876 } }看板我推荐先用Node-RED搭一个最小可用版本它自带MQTT节点收到消息后在UI里直接显示数字十分钟内就能跑通。后续如果要做历史趋势和报表可以对接Grafana或者InfluxDB用时间序列数据库存储计数快照绘制产量曲线。注意数据上报和本地计数要解耦设备本地始终维护最新计数值通信中断时先缓存恢复后再补报避免断网几分钟导致产量数据丢失。5. 现场调试的坑与排查技巧5.1 数字乱跳先查电源和地现场技术员反馈最多的问题是“数字自己会跳”。第一次遇到时我以为是传感器坏了后来用示波器一看传感器供电线上全是几十毫伏的纹波而且传感器地和MCU地之间存在0.5V左右的电位差。原因是24V开关电源在大功率负载变化时输出电压波动传感器在这种供电条件下输出信号自然不干净。排查方法很直接拿万用表测传感器供电脚和地脚之间的电压纹波再把示波器探头夹在传感器输出信号上看波形。如果是电源问题在传感器供电端加一只100µF电解电容和100nF陶瓷电容通常能压掉大部分纹波。地电位差的问题则需要把传感器返回地和主控板地单独用粗线相连避免把地线走成环。5.2 强光干扰与粉尘环境车间里最头疼的是自然光和环境光源带来的干扰。红外对射传感器抗强光能力通常不错但阳光直射接收管时仍然可能让接收电路饱和导致输出状态异常。我的处理方式有两个方向机械上给传感器加遮光罩把检测区域之外的光线挡掉电气上选择带调制的传感器也就是发射端调制到几十kHz频率接收端只放大同频信号这样能显著抑制环境光的直流分量。粉尘环境是另一个隐形杀手。对射式传感器使用时间长了发射端和接收端的透镜会蒙上一层灰光强衰减到一定程度后物体还没完全离开光路接收端已经认为光线恢复导致冷却时间提前结束出现重复计数。维护上要定期清洁透镜更稳妥的办法是在设计安装位时让透镜朝下减少积灰面积有条件还能加气吹装置。5.3 常见问题速查表现象可能原因处理措施计数偏多信号抖动、接线引入毛刺增大HOLD_MS检查地线加RC滤波计数偏少HOLD_MS太大、物体遮挡过快实测最快通过遮挡时间下调HOLD_MS数字完全不动传感器损坏、接线松动串口看原始电平用万用表量传感器供电干扰导致偶发跳变电机启停、继电器吸合噪声光耦隔离、屏蔽线、远离动力线走线物体经过不识别黑色物体、反光角度差换成对射式或槽型传感器看板数据不对设备上报失败、断网丢数据设备本地增加缓存恢复后补报5.4 调试工具与参数调优建议调试计数问题我的常备工具是万用表、示波器、逻辑分析仪和一根USB转TTL串口线。万用表负责量电压和检查通路示波器负责看信号波形和噪声逻辑分析仪在需要同时观察多路信号时序时非常好用。串口线则用来直接读取MCU打印的事件日志。参数调优不要凭感觉。先摸清楚现场的实际运动参数用秒表或示波器量一个物体从进入检测区到完全离开的时间再把这组数据代入状态机逻辑里去推导合理的HOLD_MS和COOL_MS。比如测得遮挡时间是100ms冷却时间应该留出至少50%的余量设80ms比较合适。同时要考虑到最极端的情况比如两个物体紧挨着连续通过这时遮挡时间会被拉长状态机应该把这种连续遮挡识别为多次独立事件关键是COOL_MS之后要立即重新开始判断而不是死等一个完整的空闲时间。还有一个小技巧在固件里加入统计变量把“检测到的遮挡次数”“有效计数次数”“被过滤掉的抖动次数”分别记录下来。现场调试时直接看这三个数就能知道问题出在物理层还是软件层。如果抖动次数很高优先查硬件干扰如果有效计数次数和实际数量对不上再看状态机参数是否合理。最后分享一个我自己的习惯每次改完计数逻辑我都会用同一个测试工装跑一万次连续触发记录误计次数再上线。知光项目走到今天这个模块前前后后改了六版大部分时间都不是在写功能而是在跟“为什么多了一个数字”死磕。如果你也在做类似的东西不用急着堆功能先把一次通过只记一次这件事做到位后面所有数据才有意义。
阅读完成 · 觉得有帮助?