基于Arduino的水位与降雨监测预警系统设计与实现

基于Arduino的水位与降雨监测预警系统设计与实现 1. 项目概述与核心价值最近在琢磨一个挺有意思的实践项目用Arduino搭建一套针对特定户外场景的水位与降雨监测预警原型系统。这个想法的源头是看到一些朋友喜欢去瀑布、溪谷下游游玩但上游集水区如果突降暴雨下游的人可能毫无察觉等看到水势猛涨时撤离已经非常危险。这种因信息差导致的“静默风险”其实可以通过一些简单的电子传感和物联网技术来预警。这套系统的核心逻辑很直接在上游关键点位部署雨量和水位传感器实时采集数据通过无线或有线方式在原型阶段我们先简化将数据传输到下游的中央处理单元这里用Arduino UnoArduino根据预设的阈值进行逻辑判断并通过下游的LED指示灯绿/黄/红和LCD显示屏直观地向游玩者发布“安全”、“注意”、“危险”三级警报。这本质上是一个典型的“感知-决策-执行”物联网闭环麻雀虽小但涉及了传感器选型、信号处理、逻辑控制和人机交互等多个环节对于想入门硬件开发、环境监测或物联网应用的朋友来说是一个综合性很强的练手项目。它解决的问题很具体弥补自然环境中的信息鸿沟将不可见的风险上游降雨转化为可见、可理解的预警信号。无论是用于山洪预警原型、城市内涝监测点还是自家院子的雨水收集系统溢流报警其底层技术栈都是相通的。如果你对Arduino编程、传感器应用或者如何将电子项目应用于解决实际环境问题感兴趣那接下来的内容应该能给你不少可以直接“抄作业”的细节。2. 系统整体设计与核心思路拆解在动手焊接任何一根线之前我们必须把系统的骨架——也就是整体设计思路——想清楚。一个好的设计能让你在后续开发中少走很多弯路。2.1 系统架构与工作流程整个系统可以清晰地划分为三个层级感知层、控制层、执行层。感知层这是系统的“眼睛”和“皮肤”负责从物理世界采集原始数据。在本项目中我们主要用到两类传感器雨量传感器Rain Sensor用于监测降雨是否存在及强度。通常采用裸露的平行导线或栅格板作为感应区雨水滴落会导致导线间电阻发生变化从而输出模拟电压信号。降雨强度越大导电性越好输出电压值越低或越高取决于电路设计。水位传感器Water Level Sensor用于监测溪流、水渠或预设容器的水位高度。常见的有电阻式如本文原型所用、压力式投入式液位变送器或超声波式。电阻式水位传感器通常有一系列暴露的平行导线水位升高导致更多导线被短路电阻值发生变化进而改变输出的模拟电压。控制层这是系统的“大脑”即Arduino微控制器如Uno、Nano。它的核心任务包括信号读取通过其模拟输入引脚A0~A5持续读取来自传感器的模拟电压值0-5V对应ADC值0-1023。数据处理与逻辑判断将读取的原始ADC值转换为有物理意义的单位如降雨强度等级、水位高度厘米数并与我们预先设定的安全阈值进行比较。决策制定根据比较结果执行预设的逻辑。例如“仅降雨”亮黄灯“降雨且高水位”亮红灯并鸣响警报。执行层这是系统的“嘴巴”和“手势”负责向用户传达信息。我们采用了两种方式视觉指示使用三色LED绿、黄、红来快速传达整体状态。绿色代表安全黄色代表预警降雨红色代表危险水位超限。文字信息使用一块字符型LCD显示屏如16x2 LCD可以显示更详细的信息例如实时的降雨模拟值、水位高度、以及具体的警报文字如“RAINING!”、“WATER HIGH!”。注意在更复杂的实际部署中感知层和控制层可能在地理上是分离的。上游的传感器节点需要通过无线模块如LoRa、NB-IoT、Wi-Fi将数据发送到下游的控制中心。本原型为简化假设所有设备通过导线连接在同一块Arduino上但这并不影响核心逻辑的学习。2.2 硬件选型背后的考量为什么选择这些元件每个选择都有其理由。Arduino Uno作为主控对于原型开发Uno的性价比和生态友好度无可比拟。它有足够的数字和模拟I/O口本项目需要至少3个数字口控制LED2个模拟口读取传感器外加LCD所需的多个IO社区资源丰富任何问题几乎都能找到答案。如果考虑低功耗或小型化部署可以后续迁移到Arduino Nano或ESP32。模拟输出型雨量/水位传感器这类传感器输出的是连续的模拟电压信号相比简单的数字开关型传感器只有“有/无”两种状态能提供更丰富的“强度”信息。这允许我们设置多级阈值实现更精细的预警。例如降雨可以区分为“小雨-注意”和“大雨-高度警惕”。三色LED与有源蜂鸣器警报必须直观、明确。红黄绿灯是国际通用的危险警示色码认知成本极低。蜂鸣器提供声音警报在视觉可能被忽视如背对指示灯或光线不佳时尤为重要。1602 LCD显示屏带I2C接口虽然可以直接用并行方式驱动LCD但使用I2C转接板可以节省至少6个IO口让接线变得异常简洁仅需VCC, GND, SDA, SCL四线。这对于IO口紧张的项目至关重要。3. 核心硬件电路搭建详解理论清晰后我们进入实操环节。正确的电路连接是项目成功的基石任何一处接错都可能导致元件损坏或功能异常。3.1 所需元件清单在开始焊接或插线之前请准备好以下材料Arduino Uno开发板 x1雨量传感器模块模拟输出 x1水位传感器模拟输出长度根据监测深度选择 x1三色LED共阴或共阳需确认 x1 或 单独的红、黄、绿LED各一个有源蜂鸣器模块低电平触发为佳 x11602 LCD显示屏带I2C转接板 x1面包板 x1 及 杜邦线公对公、公对母若干10kΩ电位器如果使用不带I2C的并行LCD则需要 x1220Ω 电阻用于限流保护LED x3USB数据线及电脑3.2 分步电路连接指南这里我们按照功能模块进行连接请务必在断电状态下操作。1. 传感器连接模拟输入雨量传感器模块的VCC引脚 - Arduino的5V。模块的GND引脚 - Arduino的GND。模块的AO模拟输出引脚 - Arduino的模拟引脚A0。模块的DO数字输出引脚暂时不用可以悬空。水位传感器传感器的(或VCC) 引脚 - Arduino的5V。传感器的-(或GND) 引脚 - Arduino的GND。传感器的S(或信号) 引脚 - Arduino的模拟引脚A1。实操心得模拟传感器对电源噪声比较敏感。如果读数跳动剧烈可以在传感器的信号线AO/S与地GND之间焊接一个0.1uF的瓷片电容起到滤波稳波的作用。另外长时间浸泡时电阻式水位传感器的裸露铜线可能会氧化影响精度选用带有防水镀层或不锈钢探针的型号寿命更长。2. 执行器连接数字输出三色LED以共阴为例LED的公共阴极通常是最长的引脚或标注为“-” - Arduino的GND。LED的红色阳极引脚 - 通过一个220Ω电阻 - Arduino数字引脚D2。LED的绿色阳极引脚 - 通过一个220Ω电阻 - Arduino数字引脚D3。LED的黄色阳极引脚 - 通过一个220Ω电阻 - Arduino数字引脚D4。有源蜂鸣器模块模块的VCC- Arduino的5V。模块的GND- Arduino的GND。模块的I/O(或SIG) 引脚 - Arduino数字引脚D5。注意有源蜂鸣器通电即响模块通常内置三极管驱动通过信号引脚高低电平控制。确保你的模块是低电平触发即信号脚给低电平时蜂鸣器响这是最常见的设计。3. 人机界面连接I2C通信1602 LCD with I2C转接板的VCC- Arduino的5V。转接板的GND- Arduino的GND。转接板的SDA- Arduino的A4引脚在Uno上A4同时也是SDA。转接板的SCL- Arduino的A5引脚在Uno上A5同时也是SCL。电路检查清单连接完成后不要急于上电。花两分钟按照以上列表逐一核对[ ] 所有VCC是否接到了5V[ ] 所有GND是否都接到了GND共地[ ] LED的限流电阻是否已串联[ ] 模拟信号线是否接在了A0和A1[ ] I2C的SDA和SCL有没有接反4. 软件逻辑与代码实现解析硬件是躯干软件是灵魂。下面我们深入代码看看如何让这些元件“活”起来协同工作。4.1 核心逻辑流程图与状态机在编写代码前用流程图厘清逻辑至关重要。本系统的核心是一个简单的状态机其状态由两个传感器输入决定开始 | v 初始化传感器、LCD、LED、蜂鸣器 | v 循环开始 | v 读取雨量传感器值(A0) - 计算降雨状态 | v 读取水位传感器值(A1) - 计算水位状态 | v 判断当前组合状态 | |-- [状态1: 无雨且水位正常] -- 点亮绿灯LCD显示SAFE关闭蜂鸣器 | | |-- [状态2: 有雨但水位正常] -- 点亮黄灯LCD显示RAINING关闭蜂鸣器 | | |-- [状态3: 有雨且水位超限] -- 点亮红灯启动蜂鸣器LCD显示DANGER! WATER HIGH! | | |-- [状态4: 无雨但水位超限*] -- 点亮红灯启动蜂鸣器LCD显示WARNING! HIGH WATER | | v (延迟一定时间如500ms) | v 跳回“循环开始”*状态4是一个重要的安全冗余设计。即使没有降雨水位也可能因其他原因如上游闸门放水升高此时也应触发最高级别警报。4.2 代码分步实现与关键函数我们将使用Arduino IDE进行开发。首先需要安装必要的库用于驱动I2C LCD的LiquidCrystal_I2C库。可以通过IDE的库管理器搜索安装。// 1. 包含必要的库 #include Wire.h #include LiquidCrystal_I2C.h // 2. 定义引脚常量提高代码可读性和可维护性 #define RAIN_SENSOR_PIN A0 #define WATER_LEVEL_PIN A1 #define LED_GREEN_PIN 2 #define LED_YELLOW_PIN 3 #define LED_RED_PIN 4 #define BUZZER_PIN 5 // 3. 定义阈值这些值需要根据你的传感器实测校准 #define RAIN_THRESHOLD 300 // 模拟值低于此值认为有雨具体看传感器有的传感器是值越大雨越大 #define WATER_HIGH_THRESHOLD 600 // 模拟值高于此值认为水位过高 // 4. 初始化LCD对象地址通常是0x27或0x3F需用I2C扫描工具确认 LiquidCrystal_I2C lcd(0x27, 16, 2); // 设置LCD地址为0x2716列2行 // 5. 全局变量声明 int rainValue 0; int waterLevelValue 0; bool isRaining false; bool isWaterHigh false; void setup() { // 初始化串口用于调试输出可选但强烈推荐 Serial.begin(9600); Serial.println(System Initializing...); // 初始化数字引脚模式 pinMode(LED_GREEN_PIN, OUTPUT); pinMode(LED_YELLOW_PIN, OUTPUT); pinMode(LED_RED_PIN, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); digitalWrite(BUZZER_PIN, HIGH); // 初始化为高电平关闭蜂鸣器假设低电平触发 // 初始化LCD lcd.init(); lcd.backlight(); // 打开背光 lcd.setCursor(0, 0); lcd.print(Flood Alert Sys); lcd.setCursor(0, 1); lcd.print(Initializing...); delay(2000); // 显示启动信息2秒 lcd.clear(); // 初始化所有LED为关闭状态 allLEDsOff(); } void loop() { // 1. 数据采集 readSensorData(); // 2. 数据处理与状态判断 determineStatus(); // 3. 根据状态执行动作 executeActions(); // 4. 在串口监视器输出调试信息可选 printDebugInfo(); // 5. 控制循环速度避免过于频繁的刷新 delay(500); // 每500ms检测一次 } // --- 自定义函数实现 --- void readSensorData() { // 多次读取取平均值可以减少噪声干扰 rainValue 0; waterLevelValue 0; for (int i 0; i 10; i) { rainValue analogRead(RAIN_SENSOR_PIN); waterLevelValue analogRead(WATER_LEVEL_PIN); delay(5); } rainValue / 10; waterLevelValue / 10; } void determineStatus() { // 判断是否下雨根据传感器特性通常无水时值高有水时值降低 isRaining (rainValue RAIN_THRESHOLD); // 如果值小于阈值表示有雨 // 判断水位是否过高水位越高导电面积越大模拟值通常越高 isWaterHigh (waterLevelValue WATER_HIGH_THRESHOLD); } void executeActions() { // 首先关闭所有LED和蜂鸣器 allLEDsOff(); digitalWrite(BUZZER_PIN, HIGH); // 关闭蜂鸣器 // 清空LCD显示 lcd.clear(); // 状态判断与执行 if (!isRaining !isWaterHigh) { // 状态1: 安全 digitalWrite(LED_GREEN_PIN, HIGH); lcd.setCursor(0, 0); lcd.print(Status: SAFE); lcd.setCursor(0, 1); lcd.print(R:); lcd.print(rainValue); lcd.print( W:); lcd.print(waterLevelValue); } else if (isRaining !isWaterHigh) { // 状态2: 降雨预警 digitalWrite(LED_YELLOW_PIN, HIGH); lcd.setCursor(0, 0); lcd.print(ALERT: RAINING); lcd.setCursor(0, 1); lcd.print(Intensity: ); // 可以简单地将模拟值映射为等级 int rainIntensity map(rainValue, 0, RAIN_THRESHOLD, 10, 1); // 值越小强度等级越高 lcd.print(rainIntensity); } else if (isRaining isWaterHigh) { // 状态3: 危险降雨高水位 digitalWrite(LED_RED_PIN, HIGH); digitalWrite(BUZZER_PIN, LOW); // 触发蜂鸣器 lcd.setCursor(0, 0); lcd.print(DANGER!); lcd.setCursor(0, 1); lcd.print(FLOOD RISK HIGH!); } else if (!isRaining isWaterHigh) { // 状态4: 警告仅高水位 digitalWrite(LED_RED_PIN, HIGH); digitalWrite(BUZZER_PIN, LOW); // 触发蜂鸣器 lcd.setCursor(0, 0); lcd.print(WARNING!); lcd.setCursor(0, 1); lcd.print(HIGH WATER LEVEL); } } void allLEDsOff() { digitalWrite(LED_GREEN_PIN, LOW); digitalWrite(LED_YELLOW_PIN, LOW); digitalWrite(LED_RED_PIN, LOW); } void printDebugInfo() { Serial.print(Rain: ); Serial.print(rainValue); Serial.print( | Water: ); Serial.print(waterLevelValue); Serial.print( | Raining: ); Serial.print(isRaining); Serial.print( | WaterHigh: ); Serial.println(isWaterHigh); }4.3 代码关键点解析与调优建议阈值校准 (RAIN_THRESHOLD,WATER_HIGH_THRESHOLD)这是整个系统的“敏感度旋钮”。绝对不能直接使用示例代码中的数值。你必须进行实地校准将雨量传感器置于完全干燥环境中读取串口输出的rainValue这个值就是你的“无水基准值”。然后滴少量水在感应区观察数值下降。将阈值设定在基准值和明显有水值之间的某个位置。将水位传感器逐步浸入水中记录不同水深对应的waterLevelValue。根据你希望报警的水位高度确定WATER_HIGH_THRESHOLD。软件消抖与滤波在readSensorData()函数中我们采用了“多次采样取平均”的方法。这是抑制随机噪声最简单有效的手段。对于水位这种变化相对缓慢的量还可以加入“滑动窗口平均滤波”或“中值滤波”效果会更好能有效剔除偶然的尖峰干扰。状态执行的互斥与复位在executeActions()开始时我们总是先关闭所有输出设备。这保证了任何时刻只有一种状态被显示避免了状态残留导致的显示混乱。这是一种稳健的编程习惯。LCD显示优化示例中直接显示了原始模拟值这对调试有用。在实际应用中可以将其转换为更直观的单位例如通过map()函数将水位模拟值映射为“水深XX cm”或者将雨量值映射为“小雨/中雨/大雨”。5. 系统调试、校准与实战部署思考代码上传成功后系统可能不会立即按预期工作。调试和校准是让项目从“能动”到“好用”的关键一步。5.1 上电调试与常见问题排查按照以下步骤进行系统调试供电与基础检查连接USB线观察Arduino电源灯是否亮起LCD背光是否点亮。如果不亮立即断电检查电源连接。串口监视器调试打开Arduino IDE的串口监视器波特率设为9600。你应该能看到System Initializing...以及后续持续输出的传感器数据和状态标志。这是你洞察系统内部状态的窗口。问题无数据输出- 检查代码中Serial.begin(9600)是否存在检查串口监视器选择的端口是否正确。问题传感器数值始终为0或1023- 检查传感器接线特别是信号线是否接到了正确的模拟引脚A0/A1检查传感器本身是否损坏。传感器响应测试雨量传感器用手触摸感应区模拟雨水导电。观察串口输出的rainValue是否显著下降。同时观察LCD显示和黄色LED是否亮起。水位传感器将感应部分浸入水中观察waterLevelValue是否上升并触发红色LED和蜂鸣器。执行器功能测试你可以暂时修改代码手动强制设置isRaining和isWaterHigh为true或false来分别测试绿、黄、红LED和蜂鸣器是否正常响应。5.2 阈值校准实战流程校准是让系统适应你具体环境的核心步骤。准备环境将传感器安装到最终计划部署的模拟位置。例如将水位传感器垂直固定在容器或水槽的侧壁将雨量传感器水平放置。采集基准数据干燥状态记录雨量传感器在完全干燥时的稳定读数Rain_Dry。空水位状态记录水位传感器在完全未接触水时的稳定读数Water_Low。模拟触发条件降雨条件用湿布轻轻擦拭或滴几滴水在雨量传感器上模拟小雨。记录此时的读数Rain_Wet。你的RAIN_THRESHOLD应该设定在(Rain_Dry Rain_Wet) / 2附近并根据灵敏度需求微调。高水位条件向容器中注水直到达到你认为是“危险需要报警”的水位线。记录此时水位传感器的稳定读数Water_High。这个值就是你的WATER_HIGH_THRESHOLD。更新代码并验证将校准后的阈值更新到代码的#define部分重新上传程序。反复测试在干/湿、低水位/高水位几种组合下系统的状态判断和警报触发是否符合预期。5.3 从原型到实际部署的进阶思考这个原型系统是功能完整的但要从实验桌走向真实野外还需要考虑更多工程问题供电问题野外部署必须考虑持续供电。可以使用大容量锂电池配合太阳能充电板或者选择低功耗的主控如ESP32进入深度睡眠模式定时唤醒采集和传感器。通信问题原型是“一线通”实际中上下游可能相距数百米。这就需要无线通信。根据距离和功耗要求选择短距离100mWi-FiESP32、蓝牙。中长距离1kmLoRa低功耗远距离、4G/NB-IoT需要SIM卡覆盖广。上游的传感器节点作为“从机”定时发送数据下游的Arduino作为“主机”接收并处理显示。传感器防护户外环境严酷。需要为电子部分制作防水外壳可以使用防水接线盒。水位传感器的探针部分虽然不怕水但其与导线连接处必须做好防水密封如灌封胶防止渗水导致短路。系统可靠性增加看门狗防止程序跑飞。Arduino有软件看门狗也可以使用硬件看门狗芯片。数据冗余与验证无线传输可能丢包。通信协议里应加入数据校验如CRC并设计重发机制。本地日志记录可以添加一个SD卡模块定期将传感器数据和警报事件记录下来便于后期分析。警报方式多样化除了声光可以考虑增加更远程的警报比如通过物联网平台发送短信、电话或者App推送通知确保管理人员即使不在现场也能第一时间知晓。这个项目最吸引我的地方在于它用一个相对简单的硬件组合清晰地演示了物联网系统从感知到执行的完整链条。你在调试和校准过程中遇到的每一个问题——信号不稳定、阈值漂移、电源干扰——都是真实世界电子项目必然会面对的挑战。解决它们的过程远比最终看到LED按预期点亮更有价值。当你成功校准好阈值系统终于能准确地区分“安全”与“危险”时那种通过自己双手创造出能感知环境、做出判断的智能系统的成就感是纯粹的软件编程难以比拟的。