简介:本资源是一套面向高校电子类、物联网方向本科生的毕业设计完整实现方案,聚焦图书馆座位使用效率低下的现实痛点,基于STM32微控制器与窄带物联网(NB-IoT)技术构建非接触式智能座位监测系统。系统采用热释电红外传感器实时感知座位占用状态,通过移远BC95模块将数据稳定上传至物联网平台,具备低功耗、广覆盖、高并发接入等工程实践特征,适用于课程设计、毕设开发及嵌入式物联网入门项目。压缩包共含若干文件(具体数量未提供),主体为Keil工程源码、电路原理图、PCB设计文件及平台对接说明文档,整体大小为50.03MB,结构清晰,模块划分明确,涵盖采集端固件、通信协议解析、平台数据可视化逻辑等关键环节。已有243人学习下载,读者可直接复现硬件采集—NB传输—云平台接收全流程,获取可运行的嵌入式代码、典型传感器驱动范例及NB-IoT在校园场景中的落地调试经验。
1. 项目缘起:从“占座”到“智管”的图书馆痛点
每次期末复习或者考研冲刺季,图书馆门口排起的长龙和自习室里“一座难求”的景象,想必大家都深有体会。更让人头疼的是,明明座位上没人,却放着几本书、一个水杯,宣告着“此座已占”,让后来者只能望座兴叹。这种低效的座位资源分配,不仅浪费了公共资源,也影响了真正想学习同学的心情。传统的管理方式,比如人工巡查、预约系统,要么成本高、效率低,要么依赖用户自觉,效果总是不尽如人意。
我最近完成的一个项目,就是针对这个痛点,设计并实现了一套基于STM32和窄带物联网(NB-IoT)的图书馆座位智能管理系统。它的核心目标很简单:让每个座位“会说话”,能自动、实时地感知是否有人使用,并将状态上传到云端,供用户通过手机小程序或网页实时查询和预约。这样一来,空座一目了然,“占座”行为无处遁形,图书馆的管理效率和用户体验都能得到质的提升。
这个项目听起来简单,但麻雀虽小五脏俱全,它融合了嵌入式硬件开发、低功耗无线通信、传感器数据处理、云端交互和前端应用展示等多个技术栈,是一个非常好的物联网综合实践案例。下面,我就把自己从零开始搭建这套系统的完整过程、踩过的坑以及积累的经验,毫无保留地分享出来。
2. 系统架构设计与核心组件选型
在动手写代码之前,清晰的系统架构和合理的硬件选型是项目成功的基石。这套系统的核心逻辑是“端-管-云-用”四层结构,每一层都有其特定的技术考量。
2.1 整体架构:四层模型解析
我们的系统可以清晰地划分为四个层次:
- 终端感知层(End Device):这是系统的“神经末梢”,部署在每个图书馆座位上。它的核心任务是采集座位状态(是否有人),并通过无线网络将数据发送出去。这一层对功耗、成本和体积有严格要求。
- 网络传输层(Pipeline):负责连接终端和云端。考虑到图书馆通常位于室内,可能信号覆盖复杂,且终端设备数量庞大、需要长续航,我们选择了窄带物联网(NB-IoT)作为通信方式。
- 云端平台层(Cloud):作为数据中枢和大脑。它接收所有终端上报的数据,进行解析、存储和处理;同时提供API接口,供应用层调用,并可能执行一些简单的业务逻辑,如预约超时释放。
- 应用展示层(Application):面向管理员和用户的交互界面。对于管理员,可能是一个Web后台,用于查看全局状态、管理设备;对于学生用户,则是一个轻量级的微信小程序或手机App,用于实时查看空座、预约座位。
这个架构的优势在于解耦清晰。终端只负责最原始的感知和发送;网络提供稳定通道;云端专注数据处理和业务支撑;应用负责友好交互。任何一层的技术升级或变更,对其他层的影响都相对较小。
2.2 硬件核心:为什么是STM32 + NB-IoT?
硬件选型直接决定了项目的可行性、稳定性和成本。
主控MCU:STM32F103C8T6(蓝色药丸核心板)在众多单片机中,我选择了STM32F103C8T6,也就是大家常说的“蓝色药丸”核心板。原因如下:
- 性能与资源平衡:基于Cortex-M3内核,主频72MHz,拥有64KB Flash和20KB RAM,对于处理传感器数据、运行轻量级协议栈(如连接NB模块的AT指令解析)绰绰有余。
- 丰富的外设:它拥有多个UART、I2C、SPI和GPIO,方便连接各种传感器和通信模块。特别是多串口,可以一个用于调试打印,一个专用于和NB-IoT模块通信,互不干扰。
- 极高的生态与性价比:STM32的社区资源(标准库、HAL库、各种驱动例程)极其丰富,遇到问题几乎都能找到答案。核心板价格仅在十元左右,极大地降低了单点成本,这对于需要部署成百上千个节点的系统至关重要。
- 低功耗潜力:虽然F103系列并非超低功耗MCU的旗舰,但其支持多种睡眠模式。在我们的场景中,通过合理的程序设计(如定时唤醒采集发送),依然可以实现以周甚至月为单位的电池续航。
人体存在检测:RCWL-0516微波雷达传感器 vs. 红外热释电(PIR)检测座位上是否有人,是本项目的关键。常见方案有:
- 红外热释电传感器(HC-SR501):成本极低,但对静止人体检测效果很差。学生坐下学习时很可能长时间不动,会导致传感器误判为空座。
- 压力传感器/薄膜压力垫:检测准确,但安装不便(需要铺在座椅上),且长期受压可能疲劳损坏。
- 微波雷达传感器(RCWL-0516):这是我最终选择的方案。它通过发射和接收微波来探测微动(甚至呼吸、心跳等微小动作),对静止人体的检测效果远好于PIR。它的感应范围可调(通过板上电容),且不受温度、光线等环境因素影响。虽然成本比PIR稍高(约10-20元),但对于确保检测准确性来说,这笔投入是值得的。
通信模块:移远BC35-G NB-IoT模块NB-IoT模块是连接设备与云端的桥梁。选择移远BC35-G的原因在于:
- 行业标杆:移远通信在物联网模组领域市场占有率很高,BC35-G是一款非常成熟且广泛应用的NB-IoT模块,资料和社区支持都很好。
- 低功耗与强覆盖:NB-IoT本身就是为了低功耗、广覆盖、大连接而生的LPWAN技术。它的功耗比2G更低,信号穿透力比4G Cat.1更强,非常适合图书馆这种室内场景。模块本身也支持PSM(省电模式)和eDRX(扩展不连续接收),可以进一步节能。
- 易于开发:通过标准的AT指令集进行控制,STM32只需通过串口发送AT命令即可完成网络注册、数据发送等所有操作,开发门槛低。
其他组件:
- 电源管理:采用18650锂电池(约3000mAh)配合TP4056充电管理芯片和AMS1117-3.3V稳压芯片,为整个系统供电。需要考虑整个系统的平均功耗来估算续航。
- 状态指示:一颗LED灯,用于指示设备工作状态(如开机、联网成功、发送数据等)。
- 安装结构:3D打印一个小外壳,将核心板、传感器、电池集成在一起,可以贴在座位下方或桌肚侧面,既隐蔽又不影响美观和使用。
注意:RCWL-0516传感器对金属比较敏感,安装时应尽量避免紧贴金属座椅腿,最好用非金属材料(如塑料、泡沫胶)进行隔离固定,以免影响感应灵敏度。
3. 终端设备:STM32的软件设计与低功耗策略
硬件搭好之后,大脑(软件)的设计才是让设备“活”起来的关键。终端设备的软件核心是状态机和低功耗策略。
3.1 程序主逻辑:状态机驱动
整个终端程序不应该是一个简单的while(1)轮询,而应该是一个清晰的状态机。这能让程序逻辑更清晰,也更容易实现低功耗。我设计的主要状态如下:
- 初始化状态(INIT):上电后,初始化所有硬件(GPIO、UART、定时器、I2C等),读取EEPROM中保存的设备ID、上报间隔等配置信息。
- 传感器检测状态(SENSING):控制RCWL-0516传感器上电,并持续采样其输出引脚电平。为了抗干扰,通常不会只检测一次,而是连续采样10次,如果超过7次为高电平,则判定为有人。检测完成后,立即关闭传感器电源以省电。
- 数据打包与NB-IoT唤醒状态(PREPARE):将检测结果(有人/无人)、设备ID、电池电压等信息,按照与云端约定好的协议格式(例如简单的JSON字符串或自定义二进制协议)打包成一条数据。
- 网络通信状态(COMMUNICATION):
- 唤醒NB-IoT模块(如果之前处于深度睡眠)。
- 发送AT指令,检查网络注册状态(
AT+CGATT?),等待注册成功(返回+CGATT: 1)。 - 建立与云平台的数据连接(例如,通过
AT+QIOPEN指令打开一个到云服务器IP和端口的Socket)。 - 发送打包好的数据(
AT+QISEND)。 - 等待云端确认回复,然后关闭连接(
AT+QICLOSE)。
- 深度睡眠状态(DEEP_SLEEP):数据发送成功后,STM32通过
__WFI()或HAL_PWR_EnterSLEEPMode()等函数进入停机(Stop)或睡眠(Sleep)模式。同时,通过一个GPIO输出低电平,控制一个MOSFET开关,彻底切断NB-IoT模块和雷达传感器的电源。整个系统只有STM32的RTC(实时时钟)在低速运行,等待定时唤醒中断。
这个状态机由RTC的定时唤醒中断(比如每5分钟一次)来驱动。每次唤醒,STM32退出低功耗模式,从INIT状态(或直接从SENSING状态)开始,走完一个完整流程,然后再次进入睡眠。如此循环。
3.2 低功耗实现的魔鬼细节
低功耗不是简单地调用一个库函数,它贯穿于硬件设计和软件编写的每一个细节。
1. 静态功耗控制(漏电流):
- 未使用的GPIO:所有未使用的GPIO引脚必须配置为模拟输入模式。如果悬空或配置为输出,可能会因为引脚电平不定产生漏电流。
- 外设时钟:在进入睡眠前,除了必要的RTC和唤醒中断相关的时钟,其他外设时钟(如ADC、多余的TIM、SPI等)都应关闭(
__HAL_RCC_XXX_CLK_DISABLE())。 - 电源域隔离:STM32的VBAT引脚可以为RTC和备份寄存器提供独立电源。在我们的系统中,虽然主电源(电池)会整体断电,但如果有持续计时需求,可以考虑此方案。
2. 动态功耗优化(运行时的节能):
- 外设分时供电:NB-IoT模块和雷达传感器是耗电大户。通过STM32的GPIO控制MOSFET管,仅在需要通信和检测时才为其供电,其他时间完全断电。这是降低平均功耗最有效的手段之一。
- CPU频率与运行速度:在非关键计算阶段,可以适当降低系统时钟(SYSCLK)。但要注意,与NB模块通信的串口波特率需要稳定,降频可能会影响通信。
- 通信策略优化:
- 避免频繁注册:让NB模块附着网络后,尽量保持,利用PSM模式。每次重新附着网络耗时耗电。
- 数据合并发送:如果不是必须每分钟上报,可以适当延长上报间隔(如5-10分钟)。或者采用“变化上报”策略,只有当座位状态发生变化(从有人到无人或反之)时才立即上报,否则按长间隔上报心跳包。
- 使用CoAP协议:如果云平台支持,使用CoAP这种为物联网设计的轻量级协议,比HTTP(S)开销小得多。
3. 测量与验证: 说一千道一万,功耗到底多少,需要用数据说话。你需要一个高精度的万用表或电流探头。
- 平均电流计算:测量设备在一个完整工作周期(如睡眠5分钟+工作10秒)内的电流曲线。计算平均电流 = (睡眠电流 * 睡眠时间 + 工作电流 * 工作时间) / 总周期时间。
- 续航估算:假设使用3000mAh的18650电池,理论续航时间 = 电池容量(mAh) / 平均电流(mA)。例如,平均电流为0.5mA,则续航约6000小时(250天)。但实际要考虑电池自放电、低温容量衰减等因素,打7-8折比较稳妥。
在我的实测中,采用5分钟间隔,STM32大部分时间在Stop模式,NB模块和传感器仅在工作时上电,系统平均电流可以控制在0.8mA左右,配合3000mAh电池,预期续航超过4个月,完全满足一个学期的使用需求。
4. 云端与通信:数据流转与业务逻辑
终端产生的数据,需要有一个可靠的“家”来接收、存储和处理,这就是云端平台。对于个人开发者或中小型项目,使用成熟的物联网云平台是最快捷、最经济的选择。
4.1 云平台选择与数据接入
国内主流的物联网云平台,如阿里云物联网平台、腾讯云物联网开发平台、OneNET等都提供了完善的产品。它们通常包含设备管理、物模型、数据流转、规则引擎等核心功能。以阿里云为例,其接入流程高度标准化:
- 创建产品与设备:在平台上创建一个“图书馆座位检测器”产品,定义好物模型(属性:
seat_status[有人/无人];事件:status_change)。然后为每一个实际的硬件节点创建设备,获取三元组(ProductKey,DeviceName,DeviceSecret),这相当于设备的身份证。 - 设备端SDK集成:阿里云提供了C-SDK,但集成到资源有限的STM32中比较臃肿。更常见的做法是使用AT+MQTT指令。NB模块(如BC35-G)支持MQTT协议,我们可以通过一系列AT指令,让模块直接作为MQTT客户端连接到阿里云的MQTT Broker。
- 通信过程:
- 设备上电后,NB模块利用自身的CoAP协议连接到运营商网络,获取IP。
- STM32通过AT指令,指导NB模块使用设备三元组进行加密计算,生成MQTT连接参数(ClientId, Username, Password),然后连接到指定的MQTT Broker地址。
- 连接成功后,STM32将传感器数据封装成MQTT报文(发布到特定的Topic,如
/sys/{pk}/{dn}/thing/event/property/post),通过串口发送给NB模块,由模块发送至云端。 - 云端收到数据后,会解析物模型,将
seat_status更新到设备影子中。
提示:直接使用AT+MQTT指令需要对MQTT协议和阿里云的接入规范有较深理解。一个更简单的替代方案是使用HTTPS/CoAP上报。平台提供标准的HTTP/CoAP API接口,设备只需将数据按格式打包,通过POST请求发送到指定URL即可。这种方式代码更简单,但实时性和双向通信能力不如MQTT。
4.2 数据存储与业务逻辑处理
数据上传到云平台后,通常有几种处理方式:
平台内置存储与转发:像阿里云物联网平台,设备属性上报后会自动存储在平台内。你可以通过平台提供的“规则引擎”功能,将数据实时转发到其他更专业的服务中,比如:
- 转发到阿里云表格存储(Tablestore)或时序数据库(TSDB),用于长期存储和海量数据查询。
- 转发到云数据库RDS(MySQL),用于业务系统(如预约系统)直接读写。
- 转发到消息队列RocketMQ,用于解耦和异步处理,比如触发一个“座位空闲超过30分钟自动释放”的服务。
自建业务服务器:对于复杂的业务逻辑(如预约、选座、冲突处理、信用积分),通常需要一台独立的业务服务器。这台服务器可以通过调用云平台提供的API(如查询设备最新属性)来获取座位状态,也可以直接接收规则引擎转发的数据。
- 服务器可以用任何你熟悉的语言开发,如Python(Django/Flask)、Java(Spring Boot)、Node.js等。
- 它负责维护用户信息、座位地图、预约规则、订单状态等核心业务数据。
- 当用户发起预约时,服务器检查目标座位的实时状态(通过查询云平台),若为空闲则创建预约记录,并可能通过云平台的“下行指令”功能,向该座位对应的设备发送一个“预约锁定”的指令(虽然我们的硬件可能不支持锁定物理座位,但可以在服务器逻辑上标记为“已预约”)。
4.3 通信协议设计:精简与可靠性的平衡
终端与云端之间的数据包必须尽可能精简,以节省宝贵的网络流量和电量。一个简单的二进制协议比JSON文本协议更省空间。
例如,我们可以设计一个8字节的数据帧:
| 帧头(1B) | 设备ID(2B) | 状态(1B) | 电池电压(2B) | 预留(1B) | 校验和(1B) |- 帧头:固定值0xAA,用于标识帧开始。
- 设备ID:65535个ID,足够一个图书馆使用。
- 状态:0x00无人,0x01有人,0x02传感器故障等。
- 电池电压:实际电压值乘以100的整数(如3.21V存储为321)。
- 校验和:前面所有字节的累加和取低8位,用于简单的数据校验。
在云端(或服务器)收到数据后,再将其解析并转换为业务层易于处理的JSON格式存入数据库。这种“终端用二进制,云端用JSON”的策略,兼顾了传输效率和开发便利性。
5. 应用层实现:用户如何与系统交互?
对于学生用户来说,他们不关心背后的STM32和NB-IoT,只关心能不能快速找到一个能坐的座位。因此,一个简洁、直观、稳定的前端应用至关重要。微信小程序因其免安装、易传播的特性,成为不二之选。
5.1 小程序核心功能与界面设计
小程序主要包含以下几个页面:
- 图书馆楼层/区域地图页:以平面图或列表形式展示所有座位。每个座位用一个色块(绿色为空闲,红色为占用,黄色为已预约)和编号表示。用户可以一目了然地看到全局空座分布。
- 座位详情与预约页:点击某个空闲座位,进入详情页,显示座位编号、位置描述(如“靠窗”、“有插座”)、预计空闲时长等。提供“立即预约”按钮。
- 我的预约页:展示用户当前有效的预约,包括座位号、预约时间、使用时限,并提供“签到入座”和“取消预约”功能。
- 个人中心页:显示用户信息、信用积分、预约历史等。
关键技术点:
- 实时数据更新:小程序需要实时反映座位状态变化。有两种方式:
- 轮询(Polling):小程序前端定时(如每10秒)向业务服务器发起请求,查询所有座位状态。实现简单,但频繁请求会增加服务器压力,且实时性有延迟。
- WebSocket:与服务器建立长连接,当任何座位状态发生变化时,服务器主动推送更新消息给所有在线的小程序客户端。实时性最佳,体验流畅,但服务器需要维护连接状态,复杂度稍高。对于初期项目,短轮询(如30秒一次)是可以接受的。
- 地图渲染:如果使用平面图,可以考虑使用SVG或者Canvas来绘制。更简单的做法是使用一个固定背景图,然后通过CSS绝对定位,将代表座位的
<view>组件动态地放置在对应坐标上,并根据状态改变其背景色。 - 用户认证:与学校统一身份认证系统(如学工号)对接是最理想的。如果暂时无法对接,可以采用手机号+验证码注册登录,并绑定学号信息。
5.2 预约业务逻辑与防作弊思考
预约系统是整个应用逻辑的核心,必须考虑周全:
- 预约规则:
- 可预约时间:通常只能预约当前时间之后一段时间内的座位(如未来30分钟内)。
- 预约时长:单次预约最长使用时间(如4小时),超时后系统自动释放并可能扣除信用分。
- 同时预约数:限制每个用户只能同时有一个有效预约。
- 签到机制:为了防止“只约不用”,需要引入签到。用户到达预约座位后,在小程序点击“签到”。签到可以通过:
- 蓝牙信标:在座位附近部署低功耗蓝牙信标(iBeacon),小程序检测到特定信标信号时才允许签到。成本较高。
- 地理位置:要求用户打开手机GPS,判断其位置是否在图书馆地理围栏内。精度一般,且耗电。
- 手动签到+监督:最简单的方案,依赖用户自觉和他人监督。可辅以“扫码签到”,在座位上贴一个唯一二维码。
- 信用体系:建立简单的信用积分规则。预约后不签到、占用超时、恶意占座等行为扣分。信用分过低者,限制其预约功能。这是维持系统健康运行的重要软约束。
6. 系统集成、部署与实测中的坑
当硬件、固件、云端、小程序都开发完成后,真正的挑战才刚刚开始:把它们集成起来,并部署到真实环境中去测试。
6.1 从实验室到图书馆:部署流程
- 硬件批量生产与烧录:如果要做几十上百个节点,手工焊接和烧录效率太低。可以考虑:
- 绘制统一的PCB,委托工厂贴片生产。
- 使用ST-Link的脱机烧录器,或者编写一个简单的串口IAP(在应用编程)固件,通过无线网络批量更新程序。
- 为每个设备写入唯一的设备ID(可以基于STM32自带的唯一芯片ID进行派生)。
- 现场安装与调试:
- 信号测试:在图书馆各个角落,特别是地下室、角落座位,测试NB-IoT网络信号强度(AT+CSQ)。信号弱(如CSQ<10)的区域可能需要调整设备安装位置,或与运营商沟通优化覆盖。
- 传感器校准:RCWL-0516的感应范围和灵敏度需要通过板载的电位器或更换电容来调节。在空座位上,调整到有人坐下能稳定触发,人离开后能稳定关闭的状态。避免因感应范围过大,检测到过道行人。
- 电源与固定:确保电池电量充足,设备外壳牢固粘贴,线束整理好,避免被踢到或扯断。
- 云端设备批量导入:将生产好的设备ID和三元组信息,整理成CSV文件,通过云平台提供的批量创建设备功能导入,并关联到你的产品下。
6.2 实测中遇到的典型问题与解决方案
在真实部署和长期运行中,我遇到了不少预料之外的问题:
问题一:NB-IoT模块偶尔上线失败或掉线。
- 现象:设备日志显示,发送
AT+CGATT?指令后,长时间无法返回+CGATT:1,或者在使用过程中突然掉线。 - 排查:
- 检查天线是否连接牢固。NB-IoT对天线非常敏感。
- 用
AT+CSQ查询信号质量。如果RSSI(接收信号强度)很差(例如大于-100dBm),说明位置信号覆盖不佳。 - 检查SIM卡状态,是否欠费、是否开通了NB-IoT服务。
- 在代码中增加网络注册超时机制和重试逻辑。如果连续3次注册失败,让设备进入更长时间的深度睡眠后再重试,避免因频繁尝试导致耗电剧增。
- 解决:对于信号盲点,尝试调整设备安装方位。与运营商确认该区域NB-IoT网络覆盖情况。在代码中实现指数退避的重试算法,增强鲁棒性。
问题二:微波雷达传感器误触发。
- 现象:座位上明明没人,但设备上报“有人”状态。或者人已经离开很久,状态才切换为“无人”。
- 排查:
- 环境干扰:检查座位附近是否有空调出风口、摇摆的植物、频繁开关的门窗。微波雷达对移动的金属物体(如晃动的椅子)也很敏感。
- 安装位置:传感器是否正对着过道?其感应锥形区域是否覆盖了邻座?
- 检测算法:软件上的防抖算法是否合理?我采用的是“持续检测到高电平超过2秒才判定有人,持续低电平超过5秒才判定无人”的迟滞比较法,有效避免了短时干扰。
- 解决:重新调整传感器朝向,避开干扰源。优化安装结构,必要时增加金属屏蔽罩。在软件中进一步优化检测阈值和延时逻辑。可以考虑增加“心跳包”机制,即使状态未变,也定时上报,这样云端如果长时间未收到“无人”信号,可以判断设备可能异常。
问题三:多设备数据上报冲突。
- 现象:当大量设备在同一时间点(如整点)被RTC唤醒并同时尝试连接网络上报数据时,可能会对基站造成瞬时压力,导致部分设备接入失败。
- 解决:为每个设备引入一个随机延迟。在初始化时,读取STM32的唯一ID作为随机种子,生成一个0到最大偏移量(如60秒)的随机数。每个设备在自己的上报周期基础上,加上这个随机延迟再执行网络操作。这样就将同时并发的请求在时间上错开了。
问题四:电池续航远低于预期。
- 现象:计算出的理论续航有几个月,但实测几周就没电了。
- 排查:
- 用电流表精确测量各工作阶段的电流。重点检查“深度睡眠”时的电流是否真的在微安级别。常见原因是GPIO配置不当或外部电路漏电。
- 检查程序逻辑,确认NB模块和传感器在睡眠期是否被彻底断电。用万用表测量其供电引脚电压是否为0。
- 检查上报频率是否因调试而被意外提高。
- 解决:逐项排查硬件和软件,确保低功耗设计落到实处。对于电池本身,也要注意其质量和新旧程度。
这个项目从构思到最终稳定运行,是一个不断遇到问题、分析问题、解决问题的过程。它不仅仅是一个技术拼装,更是一个系统工程。通过它,你能够串联起嵌入式开发、无线通信、云服务、前端应用等多个领域的知识,并对物联网项目的全生命周期有一个深刻的实践认知。最大的收获不在于做出了一个能用的系统,而在于获得了处理真实世界复杂性和不确定性的能力。
本文还有配套的精品资源,点击获取