☰
基于STM32的商场客流统计与安防系统设计实践
2026/10/20 8:30:36 网站建设 项目流程

去年帮某商场的运营团队做了一套单片机系统,核心就干两件事:统计各个出入口的人流量,同时把夜间安防的布防、报警和环境监测一起管起来。一开始他们想直接买现成的客流统计设备,但一问价格不低,数据接口还封闭,更别说跟门磁、烟雾探测、应急联动这些需求打通了。最后我们决定用单片机自己搭一套,从器件选型、红外判向算法到现场调试,完整走了一遍。这篇文章就把整套方案的设计思路、关键代码和踩过的坑记录下来,既适合正在做相关课程设计、毕业设计的同学参考,也适合想给店铺或小型展厅做低成本客流统计的开发者看。

1. 需求拆解:先搞清楚“数人数”和“看安全”到底要什么

1.1 客流统计不只是数个数,背后是运营和消防双重需求

很多第一次接触这个题目的人,第一反应就是“门口装个计数器,有人经过加一不就行了”。真到商场环境里,需求完全不是这么简单。运营方想知道的是:东门、南门、地下车库入口分别进来了多少人?每个小时进多少、出多少?当前这一分钟商场里实际驻留了多少人?这些数据会影响活动引流效果评估、导购排班、甚至商场开门时要不要限制入场。

消防和安全管理也有明确需求:当在店人数超过某个阈值时,需要触发限流提示,不能再放人进场,否则一旦发生紧急情况,疏散通道会超负荷。所以系统的第一个设计目标很明确——分方向统计进出人数,并且实时算出“当前在店人数”,而不是只给一个总进店数。

另外还要考虑商场出入口的复杂性。一个入口往往有两三米宽,冬天还会挂防风门帘,顾客可能结伴并行,也可能走到一半折返。这些现实情况都会直接影响传感器选型和算法设计。如果前期没有把这些使用场景梳理清楚,后面大概率会反复返工。

1.2 安防需求要拆成白天模式和夜间模式

商场的安防需求同样需要细化,不能笼统地说“装几个报警传感器”。白天营业时段,安防的重点是环境异常预警,比如烟雾浓度超标、温度异常升高,同时结合客流数据做限流联动。夜间闭店之后,重点则变成防入侵:有人闯入、门被打开、非营业时间出现人体活动,系统要能立刻发现并报警。

这里有一个关键设计点:白天和夜间的工作模式完全不同,不能共用同一套触发逻辑。比如白天如果有人从门口走过,被动人体红外传感器可能频繁触发;但在夜间布防模式下,同一个传感器的高电平信号就代表着非法闯入。所以系统必须设计明确的布防、撤防机制,而且撤防和布防状态的切换要可靠,不能误操作。

1.3 把需求量化成可验收的参数

做项目最忌讳需求停留在口头描述阶段。我在项目开始前就把功能和验收标准列成了一张表,后续所有调试和测试都围绕这张表进行:

功能项要求验收方法
单通道客流计数准确率不低于95%安排人员按固定路线往返200次,对比人工计数
进出方向判断正确率不低于90%模拟进出各100次,记录误判次数
报警响应时间不超过2秒触发烟雾/门磁后,用秒表测量蜂鸣器启动时间
连续运行稳定性72小时不死机通电72小时,每12小时检查一次数据
断电数据保留整点数据不丢失断电重启后对比断电前上报数据

这张表看起来简单,但它解决了一个很实际的问题:项目做到后面,往往会陷入“加功能”“调参数”的循环,没有量化标准就无法判断什么时候算“完成”,也无法向运营方交代。

2. 总体架构与器件选型:一套能落地到商场门口的硬件方案

2.1 主控为什么选STM32F103

主控芯片我选了STM32F103C8T6,原因很直接:外设资源够用、功耗可控、开发资料极其丰富。系统需要同时处理红外对射信号、ADC烟雾采样、1-Wire温度读取、OLED显示、按键输入和网络模块通信,普通51单片机的定时器个数和中断优先级管理在这个场景下会比较吃力。

具体来说,双通道红外判向需要至少两个外部中断输入,烟雾传感器需要一路ADC,温湿度传感器占用一个GPIO,ESP8266模块走串口,OLED走I2C,此外还要留引脚给蜂鸣器、继电器和状态指示灯。这些资源在STM32F103上一口气都能满足,不用做复杂的引脚复用优化,这对后续调试和维护都很友好。如果项目预算非常紧张,用国产替代芯片也可以,只要引脚兼容、外设寄存器逻辑一致,代码工程量不大。

2.2 核心器件选型清单

整套系统的硬件模块可以分成四个部分:客流检测、环境安防、报警联动、人机交互与通信。

模块推荐器件数量作用
主控STM32F103C8T61核心逻辑处理、中断、定时器管理
客流检测红外对射光电开关2组成双通道,判断进出方向
烟雾检测MQ-2模拟烟雾传感器1采集烟雾浓度,触发消防预警
温度检测DS18B20防水温度探头1温度异常报警
入侵检测门磁开关 + 人体红外模块各1夜间布防模式下的入侵侦测
报警输出有源蜂鸣器1本地声光报警
联动控制继电器模块1到2联动门禁、限流闸机或提示灯
显示0.96寸OLED屏1现场显示进出人数和在店人数
通信ESP8266串口Wi-Fi模块1通过商场内网上报数据和报警事件
时钟DS3231高精度时钟模块1时间戳、整点报表统计

这里单独说明一下红外对射光电开关的选择。市面上常见的是E3F-DS30C4这类工业对射探头,输出的是开关量信号,NPN常开或常闭可选,供电范围宽。跟普通的红外对射传感器相比,工业探头的抗环境光能力更强,光束能量更高,适合商场这种光照复杂的环境。价格虽然比裸红外管贵一些,但可靠性提升非常明显,这笔钱值得花。

2.3 供电与接口设计

商场环境的电源并不像实验室里那么干净,大功率空调、电梯启停都会造成电压波动。整套系统我建议用12V适配器作为总输入,一级直流降压到5V给传感器和继电器,再用AMS1117线性稳压到3.3V给单片机。

容易忽略的是继电器和蜂鸣器的供电。如果把它们直接和单片机共用3.3V电源轨,一旦继电器吸合,瞬间压降会导致单片机复位,甚至红外信号乱跳。正确的做法是:继电器单独从5V轨取电,用NPN三极管或ULN2003驱动,同时在继电器线圈两端并联续流二极管。MCU、传感器、执行器件三者之间用光耦隔离信号,这样现场的电磁干扰基本不会窜到主控端。

3. 人流量统计模块:双通道红外判向计数的原理与实现

3.1 为什么必须用双通道而不是单通道

单个红外对射传感器只能告诉我们“光束被挡住了”,但无法区分这个人是从外往里走,还是从里往外走。商场客流统计的核心恰恰是方向:进店人数和出店人数必须分开,才能算出在店人数。所以我设计了两个对射传感器,分别命名为光束A和光束B,按一前一后的顺序安装在门口。

判断原理可以理解为“一个门上的两道光线关卡”。顾客从门外进入时,会先挡住外侧的A光束,然后挡住内侧的B光束;离开时顺序正好相反:先挡住B,再挡住A。只要检测到两个光束遮挡事件的时间顺序,就能还原出人员的运动方向。

3.2 方向判定状态机与消抖实现

两个传感器的状态组合可以用一个简单的状态机来描述。每路信号有遮挡(0)和空闲(1)两种状态,因此双通道一共有四种组合:

传感器A传感器B含义
11没有人遮挡
01人先挡住外侧光束A
00人同时挡住两道光束
10外侧光束A恢复,内侧B仍被遮挡

从“A遮挡”到“B遮挡”再到“B先恢复”这一组状态变化,代表行人从外向内走,方向记为“进”;反向的状态顺序则记为“出”。实际代码不能直接对边沿中断计数,因为红外开关信号在遮挡边界会出现抖动,一个下降沿可能连续触发好几次。我的做法是在定时器中断里每5ms采样一次两个通道的电平,连续4次状态完全一致才确认变化,相当于20ms消抖,既不会漏掉快速通过的人,又能过滤掉大部分毛刺。

核心状态机代码如下:

typedef enum { S_IDLE = 0, S_A_HIT, S_B_HIT, S_BOTH, S_CONFIRM_IN, S_CONFIRM_OUT } EntryState; EntryState state = S_IDLE; uint16_t inCount = 0; uint16_t outCount = 0; void update_entry_state(uint8_t a, uint8_t b) { switch (state) { case S_IDLE: if (a == 0 && b == 1) state = S_A_HIT; // 先挡外侧A else if (a == 1 && b == 0) state = S_B_HIT; // 先挡内侧B break; case S_A_HIT: if (a == 0 && b == 0) state = S_BOTH; // 再挡内侧B else if (a == 1 && b == 1) state = S_IDLE; // 折返,回空闲 break; case S_B_HIT: if (a == 0 && b == 0) state = S_BOTH; else if (a == 1 && b == 1) state = S_IDLE; break; case S_BOTH: if (a == 0 && b == 1) { inCount++; state = S_IDLE; } // B先恢复,确定进 else if (a == 1 && b == 0) { outCount++; state = S_IDLE; } // A先恢复,确定出 else if (a == 1 && b == 1) state = S_IDLE; // 异常退出 break; default: state = S_IDLE; break; } }

需要补一个超时复位逻辑:如果顾客在两道光束之间停留了很久,或者中途折返,状态机不能卡在中间态。我在主循环里每次检查状态值,如果超过500ms没有任何变化,就强制回到S_IDLE。这个保护在实测中非常有用,否则一次异常干扰就会导致后面所有计数全部错乱。

3.3 安装间距与通道宽度带来的误差

传感器硬件没有选好、安装位置不对,再好的算法也救不回来。两道红外光束的间距建议控制在20到30厘米。间距太近,两个人并行时两组光束几乎同时被遮挡,无法产生清晰的时间差;间距太大,如果一个人快速跑过,可能只挡到其中一道光束,方向判断直接失效。

另一个关键是通道宽度。商场主入口动辄两三米宽,靠一组双通道红外根本不可能全覆盖。我给出的解决方案是物理导流:用可移动的栏杆把通行宽度压缩到60到80厘米,每个通道内装一组双光束。多组通道各自独立计数,最后汇总到主控。实际测试中,1.5米宽的入口安装三组双光束后,漏计率从单通道的15%降到了3%左右。算法再强也挡不住物理世界的漏检,导流永远是最简单有效的手段。

3.4 软件层面的计数与在店人数计算

方向计数得到两个累加值:进店总数和出店总数。当前在店人数的计算公式很简单:

int currentPeople = initialCount + inCount - outCount;

initialCount是早上开门时商场已经在店内的人数,可以由运营方在管理端设定。为了防止累计算出负数,需要在每次更新后判断一下,如果结果小于0则强制归零并记录一条异常日志,方便排查是传感器漏检还是初始值设置出错。同时,这个值要配合“限流阈值”使用,一旦当前在店人数达到设定上限,系统立刻在OLED屏上显示限流提示,并向上位机报一条高优先级事件。

4. 商场安防子系统:从环境感知到应急联动

4.1 白天模式下的烟雾温度预警

白天营业时段,安防子系统主要做环境异常预警。我选用了MQ-2烟雾传感器和DS18B20温度探头。MQ-2的输出是模拟电压,随可燃气体和烟雾浓度变化,需要用ADC采样。但它的输出曲线不是线性的,而且上电初期会有一段预热过程,模块输出电压可能虚高。

所以软件里要加两条保护规则:第一,系统上电前60秒内只显示数据,不做报警判断;第二,ADC采样值连续5次滑动平均后再参与阈值比较,并且这个平均值必须持续超过阈值3秒以上才触发报警,避免瞬时波动造成误报。温度探头则简单很多,DS18B20直接返回数字温度,只要超过设定上限就进入报警状态。

这里必须强调一点:这套单片机系统的定位是轻量级辅助安防,做的是早期预警和现场联动,不能替代商场按消防规范配置的火灾自动报警系统。我们上报的事件信息主要用于值班人员快速反应,真正的消防通道、喷淋、排烟等设施,还是要靠正规消防系统控制。

4.2 夜间布防模式与防误报机制

夜间闭店后,系统进入布防模式。布防状态通过按键或上位机指令切换,并且保存到内部Flash里,断电重启后还能恢复到原来的布防状态,不会因为一次临时停电就失去防护。

入侵检测由门磁开关和人体红外模块共同完成。门磁负责检测门被打开,人体红外负责检测区域内的人员活动。这里有一个非常重要的细节:布防状态下,管理员自己开门进去时不能让系统马上报警。所以触发入侵信号后,系统不会立即拉响蜂鸣器,而是先启动一个30秒的延时窗口,期间如果收到正确撤防指令,报警自动取消;30秒倒计时结束仍未撤防,才触发声光报警并上报事件。这个延时机制在实际使用中非常必要,直接决定系统能不能被长期使用,误报率太高的安防系统很快会被用户关掉。

4.3 报警联动输出与电气隔离

报警输出的核心是两个:有源蜂鸣器和继电器模块。蜂鸣器负责现场大音量提醒,继电器可以联动门禁、限流提示灯或者其他辅助设备。我特意在继电器驱动电路上加了续流二极管,并且把继电器供电和信号供电分开走线。

为什么要这样做?我在第一版测试时,蜂鸣器一响,计数器就自动加几个人,红外信号乱跳。后来用示波器看5V电源轨,发现继电器吸合瞬间出现明显的电压跌落和毛刺,直接干扰了传感器供电。把执行器件的电源分离,并加光耦隔离信号后,这个问题彻底消失。信号地和功率地必须单点连接,不要大面积共地。

4.4 事件上报协议

安防事件和价值数据最终要送到服务台。系统通过ESP8266模块接入商场局域网,采用MQTT协议上报,主题按节点和事件类型划分,负载用JSON格式,简洁易解析。一个典型的烟雾报警事件会长这样:

{ "type": "alarm", "node_id": "entrance_01", "event": "smoke_detected", "adc_value": 320, "ts": 1735689600 }

如果商场内网不允许额外部署MQTT Broker,也可以简化成HTTP GET请求,把数据拼在URL里发给内网已有的HTTP服务。局域网内通信不用考虑公网穿透,也尽量不要把设备直接暴露到外网。

5. 数据统计与整点报表:让计数结果真正成为管理依据

5.1 整点统计与Flash存储

商场运营方需要的不是实时跳动的数字,而是稳定的分时段报表。系统每整点都要把当前小时内的进店数、出店数、在店人数写入本地存储。存储方案我选用了STM32内部Flash模拟EEPROM,不用额外加存储芯片,缺点是Flash擦写寿命有限。因此写入策略要设计得谨慎:每小时只写一次,并把数据分散到多个扇区轮流写入,分摊擦写次数,保证设备使用几年不出存储故障。

时间基准由外接的DS3231模块提供。这个模块的好处是带温补晶振,走时精度高,断电后还能靠纽扣电池继续走时,不需要依赖商场内网做校时。没有准确时间,整点报表就没有意义,这是很容易被忽略的基础设备。

5.2 关键指标的换算公式

统计模块最终要输出几组核心指标,计算公式固定如下:

指标名计算公式用途
当前在店人数初始人数 + 累计进店 - 累计出店限流判断、消防安全参考
时段净流入该时段进店数 - 该时段出店数评估活动引流效果
客流密度当前在店人数 ÷ 营业面积判断单位面积是否拥挤
进出比累计进店数 ÷ 累计出店数分析顾客停留意愿

这些指标不需要在单片机里全部算完,主要数据在嵌入式端做,复杂的报表交给上位机。但单片机上至少要保留最原始的数据字段:时间戳、进店数、出店数、当前在店人数。这样即使上位机挂了,本地数据也能完整恢复。

5.3 现场显示与内网数据对接

调试阶段OLED屏作用很大。我让它常显示四行信息:当前总进店数、总出店数、在店人数、系统模式。上线后这些信息虽然不再常看,但每次现场排查问题,一眼就能看出计数是否正常。

数据对接方面,除了MQTT上报,系统串口还保留了一个简单的文本调试协议,比如发送“STATUS”返回当前累计值,发送“SET INITCHECK 20”设置初始在店人数。这个调试协议帮了大忙,在商场现场用笔记本接串口就能实时观察传感器状态,不用反复猜内部变量。

6. 实测与避坑:我在商场入口调试时遇到的几个问题

6.1 环境光干扰导致计数器“空跑”

第一次在商场入口安装测试,早上9点一开门,计数器在没有任何人经过的情况下每分钟自动增加二三十人,吓了我一跳。排查过程是这样的:先用万用表接在红外对射接收端,观察信号输出,发现电平一直在快速跳变,说明接收管收到了干扰光。当时商场门口的卷帘门刚打开,阳光直射进来,普通红外对射传感器没有调制编码,接收管会把太阳光里的红外分量当成有效光束。

解决方法是换用带调制功能的工业对射探头,并在发射管和接收管外加遮阳罩。这里想提醒一下:如果你的项目只能在淘宝买“红外对射计数传感器”这种小模块,尽量避开正对阳光的安装位置,或者做一个深色遮光筒套在透镜外面,效果立竿见影。

6.2 继电器吸合引发误计数

这个坑前面提到过。现象是每次蜂鸣器或继电器动作,客流计数器就跳动一次。我用示波器测量发现,继电器线圈断电瞬间产生了很高的反向电动势,同时把5V电源轨拉出明显的坑。虽然MCU没有直接复位,但红外对射传感器的供电被干扰后输出了错误电平。

整改分三步:继电器线圈两端并联续流二极管;继电器和蜂鸣器改由独立5V电源轨供电;MCU与执行器件之间增加光耦隔离。整改后反复触发几百次报警,客流计数再也没受干扰。这个经验可以推广到任何单片机系统:凡是带感性负载的电路,一定不能和敏感采样电路共用电源轨。

6.3 两人并行漏计与导流方案

第一轮测试中,两个人并排走进商场,系统只计了一次甚至没计。原因很直观:双光束间距只有25厘米,两个人并肩而过时,两道光束几乎被同时遮挡,状态机来不及区分先后顺序。

用算法强行解决这个问题非常复杂,比如加装更多光束组成阵列、做模式识别,成本会直线上升。我最终选择物理导流,在入口处放了小段隔离栏杆,把通行宽度压到70厘米左右,并在两侧各装一组双光束,左右入口分开计数。测试200组数据后,漏计次数从单通道时的30次降到了5次以内。这种“物理手段优先、算法兜底”的思路,在工业现场和嵌入式项目里非常通用。

6.4 单片机“死机”与看门狗

有一版烧录上去后,连续运行十多个小时,OLED画面卡住不再更新,计数器全部停摆。接上调试器定位,发现跑进了某个不常用的中断服务函数,而且单片机在中断里待了太长时间,主循环被卡死。

整改措施包括:启用独立看门狗IWDG,在主循环最末端喂狗,一旦任务卡死超过2秒由硬件复位系统;中断服务函数里只做置标志位和读寄存器,所有数据处理全部挪回主循环;消抖操作不用delay阻塞,全部放到定时器中断里做状态采样。改完之后,系统连续运行超过72小时没有出现死机。嵌入式开发里,“系统跑飞”并不可怕,可怕的是没有恢复机制。

7. 成本核算与后续扩展

7.1 单台样机成本

整套系统单台样机物料成本大约在200到250元之间,价格会随采购渠道和批量变化:

项目型号/规格估算单价
主控板STM32F103C8T6最小系统板约25元
红外对射开关E3F-DS30C4约25元 × 2
烟雾传感器MQ-2模块约8元
温度传感器DS18B20防水型约5元
人体红外模块HC-SR501约5元
门磁开关常闭型约6元
继电器模块5V单路带光耦约8元 × 2
蜂鸣器5V有源约3元
OLED屏幕0.96寸I2C约15元
时钟模块DS3231约12元
Wi-Fi模块ESP8266约12元
电源、外壳、线材等——约60元

对比市面上带双方向统计的客流终端,动辄上千元,还要额外买软件授权,这套方案的成本优势非常明显。当然,前提是自己有嵌入式开发和现场调试能力,也愿意承担维护工作。

7.2 可以继续扩展的方向

这套系统在框架上留了几个扩展口。客流检测部分可以做RS485总线组网,每个入口一台从机,所有计数汇总到一台主机,再由主机统一上报管理平台。联动部分可以在人数超限时,通过继电器输出一个脉冲给限流闸机,让闸机进入“只出不进”模式。环境感知方面,还可以增加二氧化碳传感器或空气质量传感器,联动商场的排风系统。

如果以后想做更精准的客流识别,可以考虑毫米波雷达或ToF深度传感器替代红外对射,能够在宽通道内追踪多个目标,准确率更高,但成本和算法复杂度都会明显上升。这套传统红外方案更适合中小型店铺、展厅、工作室等对成本敏感、数据接口希望完全自主可控的场景。

7.3 什么情况下不建议自己开发

最后说点实在的,不是所有场景都适合自己动手做。如果商场已经有完整的中控系统,或者明确需要视频级的人物属性识别,建议直接采购商用方案,自己开发硬件反而会把运维成本拉高。如果项目要求通过消防强制认证,那更不是个人开发者能解决的问题。自己开发这套系统的最大价值,在于数据完全可控、功能可定制,以及在你需要快速迭代的时候不被厂商接口卡住。

整套项目做下来,我最大的体会是:硬件选型差不多的情况下,真正花时间的不是写代码,而是处理现场的光电干扰和物理结构问题。最后分享一个小技巧:确定传感器安装高度和位置时,别急着拧螺丝固定,先用包装箱的硬纸板做了两个简易支架,让人来回走动几遍,同时看串口输出的状态变化日志,确认判向稳定后再固定支架。这套验证方法帮我省掉了大量返工时间。如果下次再做类似系统,我会第一步就把导流栏杆方案定下来,并且直接选用带调制功能的红外对射探头,不给干扰留机会。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询