单片机毕业设计里,“城市河道监控”算是经典题目,但大部分方案最后都停在“单片机采集数据→串口助手显示”这一步,论文里贴几张图就收工。如果把LoRa加进去,整套东西就会从单机采集变成无线传感网络,硬件、协议、上位机、测试全都有事可做,技术层次和工作量完全不一样。
这个题目的完整形态是:在河道沿线部署多个采集节点,每个节点用单片机读取水位、水温、pH、溶解氧等参数,数据通过LoRa无线链路发给网关,网关再借助WiFi或以太网推到云平台,最后在上位机界面看到实时数据和告警记录。配套的LW文档则把需求分析、方案选型、硬件设计、软件流程、系统测试全部写清楚。
这篇文章适合两类人看:一类是正在选嵌入式或物联网方向毕设题目的同学,另一类是想把这个题目做出区分度、不想做成串口助手加强版的同学。我会把从题目拆解、硬件选型、通信协议到论文撰写和答辩避坑的完整链路拆开讲,尽量让后来者少走弯路。
1. 这个题目到底在做什么
1.1 从题目关键词拆出真实任务
“基于LoRa的城市河道监控系统设计——单片机毕业设计+LW文档”,这个标题可以拆成四个关键词:LoRa、城市河道、单片机、LW文档。
- LoRa决定传输层怎么做;
- 城市河道决定采集对象和安装场景;
- 单片机决定核心控制方案;
- LW文档就是配套的毕业设计说明书,通常表现为论文形式。
所以这个题目本质上不是做一个App,也不是纯网页系统,而是一套完整的物联网最小系统:传感采集、无线传输、汇聚网关、上位机展示、文档闭环。把这条链路想清楚,后面每一步才不会被带偏。
具体要交付的东西大致有这几件:
- 至少一个采集节点样机,如果有条件做两到三个节点,就能体现组网能力;
- LoRa传输链路,点对点或星型拓扑都行;
- 一个网关节点,负责接收LoRa数据并接入互联网;
- 上位机平台,能显示实时数据、历史曲线和告警记录;
- 配套论文,篇幅一般在1.5万到2万字左右,包含方案对比、硬件设计、软件流程和测试数据。
河道的实际监控需求大致分三类:
- 水文类:水位、流速、流量;
- 水质类:pH、溶解氧、浊度、水温、电导率;
- 图像类:水面垃圾、蓝藻、异常排口,这一类通常需要摄像头,复杂度会明显上升。
毕业设计不建议全部覆盖。选两到四个参数做到数据稳定,就已经能撑起一篇合格论文。我见过有同学一开始把浊度、溶解氧、流速全买了,结果连传感器供电问题都折腾了两个月,最后只能砍掉一半内容。
1.2 通信选型:LoRa为什么比WiFi/4G更适合河道
河道的现场条件和办公室完全不同:监测点分散,每隔几百米甚至一两公里一个点;河岸边没有网口和电源;节点数量可能不少;传感器上报的数据量却很小,一条几十字节,一分钟上报一次都算频繁。
LoRa正好匹配这种场景。它工作在Sub-GHz频段,常用的433MHz和470MHz都属于微功率短距离设备可用频段,做的是扩频通信,接收灵敏度可以做到-130dBm甚至更低。在城市河道这类环境下,开阔地带实测一到两公里不是问题,状态好的时候三到五公里也有人跑出来。
把常见无线方式放在一起对比就非常直观:
| 通信方式 | 典型覆盖 | 功耗 | 部署成本 | 河道适配度 |
|---|---|---|---|---|
| WiFi | 50—100米 | 中高 | 需要布点、拉网线 | 差,覆盖不够 |
| 4G蜂窝 | 依赖运营商覆盖 | 中 | 模块贵、有流量费 | 可以,但综合成本高 |
| LoRa | 1—5公里开阔地 | 低 | 模块便宜,自建网关 | 好,适合固定低频上报 |
WiFi的问题在覆盖范围太小,河道沿线不可能拉一排路由器。蜂窝网络确实省事,但每个节点都要插SIM卡,模块成本和流量费用会随节点数量线性上涨。LoRa可以自建网关,模块价格低,没有流量费用,很适合这类“分布广、数据小、频率低”的监测系统。
2. 系统总体设计与硬件选型
2.1 先画清楚三层架构
河道监控系统在逻辑上分三层:感知层、传输层、应用层。
感知层由多个采集节点组成,每个节点包含传感器、单片机、LoRa模块和电源系统,负责按设定周期采集数据并通过LoRa发射出去。
传输层的核心是LoRa网关。采集节点和网关之间用星型拓扑,网关内部实际上是“LoRa接收模块加联网模块”,一边收射频数据,一边把数据转成MQTT或HTTP请求发到服务器。
应用层就是上位机平台,负责接收数据、入库、展示和告警。
整个数据流可以写成一条链路:
传感器 → ADC或485总线 → 单片机处理 → LoRa发送 → LoRa网关接收 → 网关联网上传 → 云数据库 → 前端展示与告警
这张架构图放进论文第一章,就是系统总体设计图。画图不需要花哨,用Visio或draw.io画分层框图,标注每一层的设备、接口和协议,答辩老师一眼就能看出你的系统结构是清楚的。
2.2 单片机与传感器怎么选
单片机选择主要看三点:开发资料、外设接口、功耗。
想快速跑通并做足工作量,STM32F103C8T6是非常稳的选择。它带串口、ADC、I2C和SPI,资料成堆,遇到问题很容易查到解决方案,缺点是功耗偏高。想体现低功耗设计,可以选择STM32L0或STM32L4系列,Stop模式下的电流能到微安级别,配合RTC定时唤醒,电池续航能明显拉长。
如果之前没有STM32基础,用常见的单片机最小系统板或者Arduino兼容板起步也可以,但在论文的低功耗章节要谨慎措辞,不要把话说得太满。
传感器选型取决于课题参数,这里给一个常见组合参考:
| 监测参数 | 常用方案 | 接口 | 注意点 |
|---|---|---|---|
| 水位 | 超声波液位计或雷达液位计 | 485接口 | 水面波动影响读数,安装要固定 |
| 水温 | 不锈钢封装温度传感器 | 单总线 | 简单可靠,成本低 |
| pH值 | 模拟量pH电极模块 | ADC | 需要校准,探头要浸入水中 |
| 溶解氧 | 荧光法或电化学法传感器 | 485接口 | 价格偏高,按预算决定 |
| 浊度 | 散射式浊度传感器 | 模拟量或485 | 光源衰减,需要定期清洁 |
多数毕设采用“水温加水位加pH”的组合,再选一个浊度或溶解氧,就足够支撑“多参数监测”的定位。传感器接口优先选485,抗干扰能力强,两芯线就能串联多个探头,而且很多河道传感器本身就是485输出,接线逻辑更清晰。
2.3 LoRa模块与网关方案
LoRa模块的核心是射频芯片,主流常见型号有SX1278、SX1262等。选模块时要注意三件事:
- 频率:国内常用433M或470M,发射功率必须控制在合规范围内;
- 接口:优先选串口透明传输模块,开发简单,进阶玩法是用SPI接口的模块自己控制协议;
- 天线:必须外接,天线尽量竖直,远离金属外壳和电源线。
网关方案有两条路。
第一条是自制网关:用“ESP32加LoRa模块”组合,LoRa模块接收节点数据,通过串口给ESP32,ESP32再通过WiFi或以太网上传。这个方案逻辑都在你手里,论文能写的东西多。
第二条是直接用成品LoRa网关硬件,内部协议已经封装好。这种方案开发效率高,但毕设不建议选,因为大部分工作都被黑盒吃掉了,论文的软件设计部分会很空。
自制网关还有个隐藏好处:你可以在网关上做数据解析、断线缓存和重启重连逻辑,把网关当作边缘节点来写。这样论文里的软件设计内容会充实不少。
3. 核心电路与通信链路实现
3.1 采集节点硬件设计要点
采集节点看起来就是传感器、单片机、LoRa模块三块东西,但实际做下来,有四个坑非常典型。
供电设计。河道节点一般没有市电,常见方案是“太阳能板加锂电池加充放电管理”。太阳能板选12V或18V,经过充电控制器给锂电池充电,再用DC-DC降压出5V和3.3V给不同模块。注意很多河道传感器供电要12V,不能直接把传感器接到3.3V单片机上。
传感器分时供电。水质传感器工作电流不小,溶解氧探头正常工作时可能上百毫安。如果让传感器一直通电,电池消耗会非常快。常见做法是用MOS管做电源开关,单片机在采集前先给传感器上电,等输出稳定后读数据,读完立刻断电。我第一次做的时候没考虑这一点,一个12V 10Ah电池只能撑两天,加了分时供电之后,直接撑到两周以上。
模拟量保护。pH和浊度这类传感器输出微弱模拟信号,布线时要尽量远离LoRa射频天线和电源开关的噪声区域。条件允许时,传感器供电端加一个LC滤波,ADC引脚串一个100Ω电阻,读数稳定性会明显改善。
485总线终端。使用485接口的水位计或溶解氧探头时,A/B线不能接反,长线传输需要加120Ω终端电阻。现场有电机、继电器动作时,建议加TVS管或者使用隔离模块,防止尖峰损坏接口。
3.2 数据帧:自己定一套精简协议
LoRa传输速率不高,数据帧要尽量精简。推荐使用二进制帧而不是JSON字符串,原因很简单:少传一个字节,空中时间就短一截,碰撞和丢包概率跟着下降。
一个简单帧格式可以这样定义:
| 字段 | 字节数 | 说明 |
|---|---|---|
| 帧头 | 2 | 固定0xAA 0x55 |
| 设备ID | 1 | 节点编号,1到255 |
| 数据长度 | 1 | 后续数据字段字节数 |
| 命令字 | 1 | 0x01表示上报数据 |
| 数据区 | N | 按顺序放各参数 |
| CRC16 | 2 | 从设备ID到数据区的校验值 |
举个例子:节点1上报水位0.65米,放大100倍就是65;水温23.5摄氏度,放大10倍就是235;pH值7.35,放大100倍就是735。三个参数各占2字节,数据区一共6字节。整帧长度是2加1加1加1加6加2,等于13字节。
接收端解析代码可以这样设计:
if (buf[0] == 0xAA && buf[1] == 0x55) { uint8_t dev_id = buf[2]; uint8_t len = buf[3]; uint16_t sum = 4 + len; if (crc16_check(buf, sum) == (buf[sum] << 8 | buf[sum + 1])) { // 校验通过,按顺序解析水位、水温、pH } }协议里必须加CRC或至少做累加和校验。LoRa误码率虽然不高,但河道现场偶尔一帧数据翻转很正常,不做校验就会出现明显的毛刺点,后面排查起来非常浪费时间。
3.3 LoRa参数配置与射频调试
模块买回来用默认参数通常能通,但通信距离和稳定性要靠参数调。
关键参数有三个:扩频因子SF、带宽BW、编码率CR。
- 扩频因子SF范围为7到12。SF越大,灵敏度越高,距离越远,但空中速率越低;
- 带宽BW常见125kHz、250kHz、500kHz。带宽越大速率越高,但灵敏度下降,远距离场景一般选125kHz;
- 编码率CR范围4/5到4/8。编码率越高抗干扰越强,但有效数据率越低,常规选4/5即可。
毕设场景,如果节点距离网关一公里内,用SF9、BW125、CR4/5的组合就能兼顾距离和上报速度。想体现进阶内容,可以让近点节点用SF7,远点节点用SF10,做成“按距离自适应速率”的演示,这也是论文里的一个亮点。
不同参数组合的经验值:
| 配置 | 空中速率估算 | 适合场景 |
|---|---|---|
| SF7/BW125 | 约5.5kbps | 近距离高频率采样 |
| SF9/BW125 | 约1.7kbps | 常规河道节点上报 |
| SF12/BW125 | 约0.3kbps | 超远距离、低频上报 |
注意,一分钟上报一次,13字节的数据体量,用SF12也能轻松扛住,所以为了传得更远把扩频因子调大并不算错,但论文里要写清楚代价是什么。
参数配置方式取决于模块接口。串口AT指令模块的配置示例是这样的:
AT+ADDR=1 AT+CH=470000000 AT+SF=9 AT+BW=125 AT+POWER=20 AT+SAVE如果用SPI接口的原始模块,就要直接读写寄存器,工作量更大,但论文的深度也会不一样。
3.4 网关转发:从串口到云端
网关程序本质上是一个桥接任务:
- 初始化LoRa模块,进入接收模式;
- 从串口读取一帧LoRa数据;
- 解析帧结构,转换成JSON;
- 通过MQTT或HTTP发布到服务器;
- 网络断线时,先把数据暂存,恢复后补传。
以ESP32和MQTT为例,核心逻辑可以这样表达:
import serial, json, paho.mqtt.client as mqtt ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1) def on_connect(client, userdata, flags, rc): print('mqtt connected', rc) client = mqtt.Client() client.on_connect = on_connect client.connect('broker-host', 1883, 60) client.loop_start() while True: frame = ser.read(13) if len(frame) == 13 and frame[0] == 0xAA and frame[1] == 0x55: dev_id = frame[2] payload = { 'device_id': dev_id, 'water_level': frame[7] * 100 + frame[8], 'temperature': (frame[9] * 100 + frame[10]) / 10.0, 'ph': (frame[11] * 100 + frame[12]) / 100.0 } client.publish('river/monitor/' + str(dev_id), json.dumps(payload))我在实际项目里发现,网关崩溃最常见的原因不是逻辑写错,而是WiFi或网络断线后没有自动重连。网关程序必须做联网状态检测,断线自动重连,数据先进入本地队列。否则会出现节点数据看起来正常,但平台一直不更新的情况,排查起来非常头大。
4. 上位机与告警功能落地
4.1 上位机怎么设计才算不失分
不少单片机毕设的上位机就是串口助手的改版,放几个文本框显示收到的数据。这种程度放在“城市河道监控系统”里明显不够。
一个能拿得出手的上位机至少包含四块内容:
- 设备状态面板:每个节点的在线、离线状态,最后上报时间;
- 实时数据卡片:水位、水温、pH的当前值,带单位和更新时间;
- 历史曲线:支持按时间范围查询并画出趋势曲线;
- 告警记录:显示报警时间、设备号、参数类型和阈值。
技术路线上有两类选择。第一类是Web系统:后端用Python或Node.js搭一个HTTP或MQTT服务,数据写入数据库,前端用ECharts画曲线。第二类是桌面端:用C#写WinForm或用PyQt写界面。对于大多数毕设,Web路线更合适,现场演示时用手机浏览器也能看,不用提前装软件。
数据库不需要复杂,一张设备表、一张实时数据表、一张告警记录表足够。实时数据表可以这样设计:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int | 自增主键 |
| device_id | int | 节点编号 |
| water_level | float | 水位,单位米 |
| temperature | float | 水温,单位摄氏度 |
| ph | float | pH值 |
| report_time | datetime | 上报时间 |
后端最核心的逻辑就是接收MQTT消息、解析JSON、插入数据库。前端定期拉取接口或通过WebSocket接收新数据并更新图表。这个链路讲清楚,软件设计章节就会有血有肉。
4.2 阈值告警:别让误报毁了演示
告警是河道监控里最能体现系统闭环的功能,但误报也是最容易翻车的环节。水位偶尔跳一下,pH探头表面附着一个气泡导致瞬时异常值,如果这些数据直接触发告警,一个下午就会被假报警折腾死。
我的做法是“连续多点确认”:连续三次上报数据超过阈值,系统才生成一条告警记录。同时阈值要配置化,不能写死在代码里。比如一个河段警戒水位是2.5米,换一个河段可能是3米,做成配置表比改代码可靠得多。
参考阈值范围可以这样给:
| 参数 | 参考正常范围 |
|---|---|
| pH | 6.0—9.0 |
| 溶解氧 | 不低于2mg/L |
| 水温 | 自然水体波动范围 |
| 水位 | 以当地警戒水位为准 |
告警触达建议做两个渠道:平台内记录和推送通知。推送可以调用常见的第三方消息接口,论文里把这一节叫“告警信息分发模块”,重点描述实现逻辑,不需要过度包装。
5. 常见问题与调试避坑指南
5.1 LoRa通信距离达不到预期
这是被问得最多的问题。芯片宣传页面写能传好几公里,实际在河边只能传几百米,问题多数出在四个地方。
天线问题最容易被忽略。模块配的天线,长度和频率必须匹配,433M天线和470M天线不是一回事。天线要垂直地面,距离金属外壳至少几厘米,不能塞进防水盒里。我见过有人把天线直接横躺在铝壳内部,通信距离直接腰斩。
环境问题。水面反射、桥梁遮挡、岸边树木都会带来信号衰减,河道弯道后面的盲区尤其明显。调试距离时尽量选直线通视的河段,分段测试。
参数问题。把扩频因子从7调到10,灵敏度会提升好几个dB,距离明显变远,代价是速率变慢,但对于监测系统来说通常可以接受。
供电噪声问题。LoRa发射瞬间电流可能超过100mA,如果电池或稳压输出被拉低,射频输出就不稳定。模块供电端电容要给足,至少47μF电解电容,再并一个100nF高频瓷片电容。
5.2 传感器数据跳变和校准
模拟量传感器最常见的表现是数值漂移,今天7.2明天7.8,或者偶尔冒一个明显异常值。跳变原因通常是这几个:
- 电源不稳定,特别是传感器和LoRa发射共用一路电源;
- 线缆接触不良或屏蔽层没处理好;
- 探头表面污染、气泡附着。
排查时先把数据带时间戳打印出来,观察跳变规律。如果跳变正好出现在LoRa发射瞬间,基本就是电源耦合问题,把传感器供电和射频供电分开就行。
校准方面,pH传感器必须做两点校准:先用标准缓冲液校准零点,再用另一个标准点校准斜率。浊度传感器要定期用纯水校零,用标准液校满度。河道水草、藻类附着在探头上,数据会慢慢飘,论文的运行维护章节一定要写定期清洁计划。
软件上可以用滑动平均滤波:
uint16_t filter_value(uint16_t new_value) { static uint16_t buf[5] = {0}; static uint8_t cnt = 0; uint32_t sum = 0; buf[cnt++ % 5] = new_value; for (int i = 0; i < 5; i++) { sum += buf[i]; } return (uint16_t)(sum / 5); }注意,水质突变时滑动平均会带来滞后,所以窗口不要太大,5到10个点比较合适。
5.3 功耗:从撑两天到撑一个月
低功耗是LoRa方案最大的卖点,但如果代码里没有睡眠逻辑,这个卖点就体现不出来。
功耗大头按顺序排:LoRa发射、传感器工作、单片机运行、LED指示灯。很多同学喜欢加一个常亮电源指示灯,这在电池系统里非常浪费,一个LED十几毫安,一天就是0.24Ah。
低功耗的正确思路是:
- 单片机平时进入Stop模式,用RTC唤醒;
- 每5分钟醒一次,给传感器上电;
- 等传感器稳定1到3秒,读取数据;
- LoRa模块发射一帧数据;
- 立即进入下一轮睡眠。
以STM32L0为例,Stop模式电流大约3到5μA,RTC每秒唤醒一次,折算下来单片机功耗几乎可以忽略。即使用STM32F103,Stop模式也能进到几十微安级别,配合大容量锂电池和太阳能,长期运行没有问题。
实测数据可以这样理解:某项目用12V 10Ah电池,不做睡眠时系统常转电流约80mA,理论续航只有125小时;加入5分钟周期工作后,平均电流降到10毫安以内,续航超过1000小时。差距一目了然。
5.4 LW文档和答辩怎么写出加分项
系统做出来只是前一半,后一半在LW文档里。论文结构建议按这个顺序走:
- 绪论:背景与意义、国内外现状、主要工作;
- 系统总体设计:需求分析、架构设计、通信方案选型;
- 硬件设计:采集节点电路、LoRa模块接口、电源管理;
- 软件设计:下位机流程、LoRa数据帧、网关程序、上位机实现;
- 系统测试:通信距离测试、功耗测试、数据稳定性测试;
- 总结与展望。
写的时候有三个加分点。
第一,每个关键选型都要有对比分析。不用WiFi、不用4G的原因要写成对比表,用覆盖范围、功耗、成本数据说话。
第二,测试章节不要只写“功能正常”。要给出100米、500米、1000米距离下RSSI的变化,给出不同扩频因子下的丢包率对比。这些数据最容易被答辩老师认可。
第三,实物图、电路原理图、上位机截图、测试现场照片缺一不可。每个图都要有编号和一段说明,不能光贴图不解释。
答辩演示时,提前把节点放在窗边而不是讲台上。LoRa信号在室内金属桌面附近衰减严重,我见过不止一个同学把模块放在讲台铁皮机箱上,演示时一条数据都收不到,最后只能站在台上干说原理。
6. 我做这类题目的一点体会
这类题目做完,我最大的感受是通信链路越短越可靠。最开始把数据流程想得很复杂,传感器经过单片机再到LoRa,再到网关、云端、数据库、页面,中间任何一环出问题都头疼。后来养成一个习惯:每一跳都单独验证。先用串口直接读传感器,再验证LoRa点对点,然后连网关,最后接上位机。一次只调一个环节,问题定位非常快,论文里的测试数据也自然有了。
另一个经验是不要等实物全部做好再写LW文档。硬件设计阶段就开始整理原理图和选型对比,写软件的时候同步记录代码结构,最后文档只是把素材串起来。全部堆到最后两周写,论文质量会差非常多。
如果正打算用这个题目做毕业设计,我建议把“低功耗、配置化告警、实测数据”这三件事做扎实。它们不需要额外太多经费,却能让系统从“课程实验”变成“工程设计”。做成之后你会发现,LoRa这个题目的上限比想象中高不少。