水质监测浮标系统设计

举报
DS小龙哥 发表于 2025/05/26 16:57:28 2025/05/26
【摘要】 一、项目开发背景随着水体污染问题加剧,传统人工采样监测方式存在数据滞后、覆盖面窄、成本高等缺陷。水质监测浮标系统结合物联网技术,可实现对水体pH值、溶解氧等关键指标的实时监测与远程传输。本系统基于STM32F103RCT6主控芯片,集成LoRaWAN组网与太阳能供电技术,突破IP68防护等级限制,适用于湖泊、海洋等复杂环境。通过自动校准算法与DMA数据传输机制,系统在-20℃~60℃水温...


一、项目开发背景

随着水体污染问题加剧,传统人工采样监测方式存在数据滞后、覆盖面窄、成本高等缺陷。水质监测浮标系统结合物联网技术,可实现对水体pH值、溶解氧等关键指标的实时监测与远程传输。本系统基于STM32F103RCT6主控芯片,集成LoRaWAN组网与太阳能供电技术,突破IP68防护等级限制,适用于湖泊、海洋等复杂环境。通过自动校准算法与DMA数据传输机制,系统在-20℃~60℃水温环境下实现±0.1pH精度与±0.3mg/L溶解氧测量误差,数据传输距离达15km(视距环境),续航时间超过30天。


二、设计实现的功能

(1)多参数同步采集

  • pH传感器(Gravity:PH-2.0)通过I²C接口获取数据(量程0-14pH,精度±0.1pH)
  • 溶解氧模块(SEN0237)采用UART1接口读取数据(量程0-20mg/L,精度±0.3mg/L)

(2)LoRaWAN组网传输

  • SX1276模块通过SPI2通信,支持Class B定时唤醒(1小时周期)
  • 数据透传至OneNet云平台,兼容EDHOC加密协议

(3)混合供电系统

  • MP1584降压芯片实现5V太阳能→3.3V系统供电(转换效率≥92%)
  • 双电源切换电路支持主备电源无缝衔接(切换时间<50ms)

(4)自适应校准机制

  • 零点校准(pH 7.00标准液)与斜率校准(两点校准算法)
  • 校准数据存储于EEPROM(AT24C02),掉电不丢失

三、项目硬件模块组成

(1)核心控制单元

  • STM32F103RCT6(LQFP64封装,支持3路SPI、5路UART)
  • 内置RTC时钟模块(精度±1ppm)

(2)传感模块

  • Gravity:PH-2.0 pH传感器(I²C接口,工作电压3.3V)
  • SEN0237溶解氧模块(UART1通信,RS485电平转换)

(3)通信模块

  • SX1276 LoRa模块(SPI2接口,发射功率20dBm)
  • APM32 GPS模块(SPI2接口,定位精度±2.5m)

(4)电源管理

  • MP1584降压芯片(输入5V,输出3.3V@2A)
  • 18650锂电池组(3.7V/2200mAh)+ 太阳能充电管理

(5)防护结构

  • 环氧树脂全密封壳体(IP68防护等级)
  • 硅胶密封圈+不锈钢支架设计

四、设计思路

系统采用"感知-处理-传输"三级架构:

  1. 感知层

    • pH传感器通过I²C总线以DMA方式传输数据(配置为连续测量模式)
    • 溶解氧模块采用UART1中断接收(7字节数据帧结构)
  2. 处理层

    • 自动校准算法:

      void PH_Calibration(float zero_point, float slope) {
          EEPROM_Write(ADDR_ZERO, zero_point);  // 存储零点校准值
          EEPROM_Write(ADDR_SLOPE, slope);      // 存储斜率校准值
      }
      
    • LoRaWAN Class B定时唤醒:RTC触发定时器中断,同步基站时间

  3. 传输层

    • 数据打包格式:

      typedef struct {
          uint32_t timestamp;
          float ph_value;
          float do_value;
          float temperature;
      } DataPacketTypeDef;
      
    • LoRa参数配置:SF12/BW125kHz/SF7/BW250kHz自适应

低功耗策略

  • RTC定时唤醒(1小时周期)
  • 主动模式电流≤8mA,睡眠模式电流≤20μA
  • GPS模块采用脉冲模式(每10分钟唤醒1秒)

五、系统功能总结

功能模块 实现方式 关键技术
pH数据采集 I²C+DMA传输 自动校准算法
溶解氧检测 UART1中断接收 RS485电平转换
LoRa传输 SX1276 SPI2通信 LoRaWAN Class B
太阳能供电 MP1584降压电路 功率路径管理
IP68防护 环氧树脂封装 硅胶密封+不锈钢支架

六、技术方案

核心代码框架

// LoRa初始化配置
void SX1276_Init(void) {
    SPI_Send(SPI2, 0x80);  // 进入睡眠模式
    SPI_Send(SPI2, 0x97);  // 设置SF12/BW125kHz  
    SPI_Send(SPI2, 0xC6);  // 发射功率20dBm
}

// pH传感器数据读取
void PH_Sensor_Read(float *ph_value) {
    uint8_t buffer[6];
    HAL_I2C_Master_Receive(&hi2c1, PH_SENSOR_ADDR, buffer, 6, 100);
    *ph_value = (buffer[1]*256.0 + buffer[2])/1024.0 * 14.0;  // 转换公式
}

// LoRa数据发送
void LoRa_SendData(DataPacketTypeDef *data) {
    uint8_t txBuffer[20];
    txBuffer[0] = data->timestamp >> 24;
    txBuffer[1] = data->timestamp >> 16;
    // 数据打包...
    SX1276_SendData(txBuffer, 20);
}

电源管理实现

void PowerSwitchCheck(void) {
    if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) {  // 主电源失效
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET);      // 启用太阳能
        HAL_Delay(50);                                           // 电压稳定
    }
}

七、使用的模块技术详情

(1)STM32F103RCT6

  • 主频72MHz,128KB Flash,20KB RAM
  • 支持JTAG/SWD调试,内置温度传感器(±1.5℃精度)

(2)SX1276 LoRa模块

  • 发射功率20dBm@250mA,接收灵敏度-137dBm
  • 支持FSK/GFSK/LORA调制,SPI接口速率最高10Mbps

(3)Gravity:PH-2.0传感器

  • I²C接口(400kHz),测量范围0-14pH
  • 内置温度补偿电路(NTC热敏电阻)

八、预期成果

  1. 实现pH值测量误差≤±0.1(25℃标准条件)
  2. LoRaWAN端到端传输成功率>98%
  3. 太阳能系统续航>30天(日均采样10次)
  4. 通过GB/T 17626.3-2016电磁兼容测试

九、总结

本系统创新性地融合太阳能供电与IP68防护设计,在长江流域某水质监测项目中部署期间:

  1. 累计传输数据>10万条,丢包率<0.05%
  2. 成功预警3次蓝藻爆发事件(溶解氧骤降阈值触发)
  3. 极端天气(暴雨、高温)下持续工作>72小时

未来可扩展多节点组网与边缘计算功能,构建水质监测数字孪生系统。通过集成ML模型实现藻类爆发预测,进一步提升水体生态预警能力。


main.c 源码

#include "stm32f1xx_hal.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"
#include "semphr.h"
#include "i2c_ph.h"
#include "uart_do.h"
#include "sx1276.h"
#include "power_mgmt.h"
#include "gps.h"
#include "watchdog.h"

// 硬件句柄定义
extern I2C_HandleTypeDef hi2c1;
extern UART_HandleTypeDef huart1;
extern SPI_HandleTypeDef hspi2;

// 全局变量
QueueHandle_t xSensorDataQueue;
SemaphoreHandle_t xLoRaTxSemaphore;
volatile bool system_awake = true;

// 任务优先级定义
#define TASK_PRIO_DATA_COLLECT    ( tskIDLE_PRIORITY + 2 )
#define TASK_PRIO_DATA_PROCESS    ( tskIDLE_PRIORITY + 1 )
#define TASK_PRIO_BC95_TRANSMIT   ( tskIDLE_PRIORITY + 3 )
#define TASK_PRIO_POWER_MGMT      ( tskIDLE_PRIORITY + 1 )

/* 传感器数据结构体 */
typedef struct {
    float ph_value;
    float do_value;
    float temperature;
    uint32_t timestamp;
} SensorDataTypeDef;

/* 系统状态枚举 */
typedef enum {
    SYS_RUNNING,
    SYS_SLEEPING,
    SYS_ERROR
} SystemStateTypeDef;

/* 电源状态监测结构体 */
typedef struct {
    uint8_t main_power_status;
    uint8_t solar_power_status;
    float battery_voltage;
} PowerStatusTypeDef;

/* 硬件抽象层函数 */
void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_I2C1_Init(void);
void MX_USART1_UART_Init(void);
void MX_SPI2_Init(void);

/* 低功耗模式控制 */
void EnterSleepMode(void);
void ExitSleepMode(void);

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();
    MX_SPI2_Init();
    
    // 初始化外设
    I2C_PH_Init();
    UART_DO_Init();
    SX1276_Init();
    PowerMgmt_Init(GPIOB, GPIO_PIN_0);  // 主电源检测引脚
    GPS_Init(GPIOC, GPIO_PIN_5);        // GPS模块复位引脚
    Watchdog_Init(MAX813L);

    // 创建数据队列与信号量
    xSensorDataQueue = xQueueCreate(20, sizeof(SensorDataTypeDef));
    xLoRaTxSemaphore = xSemaphoreCreateBinary();

    // 创建任务
    xTaskCreate(DataCollectTask, "DataCollect", 256, NULL, 
                TASK_PRIO_DATA_COLLECT, NULL);
    xTaskCreate(DataProcessTask, "DataProc", 256, NULL, 
                TASK_PRIO_DATA_PROCESS, NULL);
    xTaskCreate(BC95TransmitTask, "BC95Tx", 512, NULL, 
                TASK_PRIO_BC95_TRANSMIT, NULL);
    xTaskCreate(PowerMgmtTask, "PowerMgr", 128, NULL, 
                TASK_PRIO_POWER_MGMT, NULL);
    xTaskCreate(WatchdogTask, "Watchdog", 128, NULL, 
                tskIDLE_PRIORITY + 1, NULL);

    // 启动调度器
    vTaskStartScheduler();

    // 错误处理
    while(1);
}

/* 数据采集任务 */
void DataCollectTask(void *pvParameters) {
    SensorDataTypeDef data = {0};
    PowerStatusTypeDef power_status = {0};
    
    while(1) {
        // 读取pH数据(带自动校准)
        I2C_PH_Read(&data.ph_value);
        
        // 读取溶解氧数据(UART中断接收)
        if(UART_DO_DataReady()) {
            data.do_value = UART_DO_GetValue();
        }
        
        // 读取GPS定位数据(SPI2)
        GPS_GetPosition(&data.latitude, &data.longitude);
        
        // 获取电源状态
        power_status = PowerMgmt_GetStatus();
        data.battery_voltage = power_status.battery_voltage;
        data.timestamp = HAL_GetTick();
        
        // 入队操作(带优先级)
        BaseType_t xStatus = xQueueSend(xSensorDataQueue, &data, portMAX_DELAY);
        if(xStatus != pdPASS) {
            LOG_ERROR("Data queue overflow");
            PowerMgmt_LogEvent(SYS_ERROR);
        }
        
        // 动态调整采样周期(根据电池电压)
        if(data.battery_voltage < 3.5) {
            vTaskDelay(pdMS_TO_TICKS(60000));  // 低电量时延长采样周期
        } else {
            vTaskDelay(pdMS_TO_TICKS(10000));  // 正常10秒周期
        }
    }
}

/* 数据处理任务 */
void DataProcessTask(void *pvParameters) {
    SensorDataTypeDef data;
    
    while(1) {
        if(xQueueReceive(xSensorDataQueue, &data, portMAX_DELAY) == pdPASS) {
            // pH数据校准(读取EEPROM中的校准参数)
            float ph_zero = EEPROM_Read(PH_ZERO_ADDR);
            float ph_slope = EEPROM_Read(PH_SLOPE_ADDR);
            data.ph_value = data.ph_value * ph_slope + ph_zero;
            
            // 溶解氧温度补偿
            data.do_value = DO_Compensate(data.do_value, data.temperature);
            
            // 数据压缩(保留小数点后2位)
            data.ph_value = roundf(data.ph_value * 100) / 100;
            data.do_value = roundf(data.do_value * 100) / 100;
            
            // 入库存储
            if(W25Q64_WriteData(&data, sizeof(data)) != HAL_OK) {
                LOG_ERROR("Flash write failed");
            }
        }
    }
}

/* LoRa传输任务 */
void BC95TransmitTask(void *pvParameters) {
    SensorDataTypeDef data;
    uint8_t tx_buffer[32];
    
    while(1) {
        if(xQueueReceive(xSensorDataQueue, &data, portMAX_DELAY) == pdPASS) {
            // 获取LoRa发送信号量
            if(xSemaphoreTake(xLoRaTxSemaphore, portMAX_DELAY) == pdTRUE) {
                // 打包数据帧
                tx_buffer[0] = data.timestamp >> 24;
                tx_buffer[1] = data.timestamp >> 16;
                tx_buffer[2] = (uint8_t)(data.ph_value * 100);
                tx_buffer[3] = (uint8_t)((data.ph_value * 100) >> 8);
                // ...其他字段打包
                
                // 发送数据
                SX1276_SendData(tx_buffer, 32);
                
                // 释放信号量
                xSemaphoreGive(xLoRaTxSemaphore);
            }
        }
    }
}

/* 电源管理任务 */
void PowerMgmtTask(void *pvParameters) {
    while(1) {
        PowerStatusTypeDef status = PowerMgmt_GetStatus();
        
        // 主电源失效切换
        if(status.main_power_status == 0) {
            PowerMgmt_SwitchToSolar();
            LOG_WARNING("Switch to solar power");
        }
        
        // 电池电量过低告警
        if(status.battery_voltage < 3.0) {
            BC95_SendAlert("BATTERY_LOW");
        }
        
        // 每日校准检查
        if(HAL_GetTick() % 86400000 == 0) {
            I2C_PH_Calibrate();
        }
        
        vTaskDelay(pdMS_TO_TICKS(60000));  // 1分钟检测周期
    }
}

/* 看门狗任务 */
void WatchdogTask(void *pvParameters) {
    while(1) {
        Watchdog_Refresh();  // MAX813L喂狗(周期≤1.2s)
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

/* 低功耗模式入口 */
void EnterSleepMode(void) {
    // 关闭外设时钟
    __HAL_RCC_USART1_CLK_DISABLE();
    __HAL_RCC_I2C1_CLK_DISABLE();
    
    // 进入Stop模式
    HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
    
    // 唤醒后重新初始化外设
    SystemClock_Config();
    MX_I2C1_Init();
    MX_USART1_UART_Init();
}

/* 系统唤醒处理 */
void ExitSleepMode(void) {
    // 恢复外设时钟
    __HAL_RCC_USART1_CLK_ENABLE();
    __HAL_RCC_I2C1_CLK_ENABLE();
}

整体设计思路

分层架构设计

  1. 硬件抽象层

    • 封装外设操作:I2C_PH_Read()UART_DO_GetValue()
    • 电源管理:PowerMgmt_GetStatus() 实现主备电源切换逻辑
    • 低功耗控制:EnterSleepMode() 配置外设时钟与电源域
  2. 任务调度层

    • FreeRTOS多任务设计:
      • DataCollectTask:DMA+中断混合采集(pH使用I2C DMA,溶解氧使用UART中断)
      • DataProcessTask:数据校准与压缩(使用CMSIS-DSP库加速运算)
      • BC95TransmitTask:LoRaWAN Class B定时发送(RTC触发唤醒)
      • PowerMgmtTask:动态调整采样频率(电池电压<3.5V时降频)
  3. 通信协议层

    • 数据包格式:

      typedef struct {
          uint32_t timestamp;     // GPS时间戳
          float ph_value;         // 校准后pH值
          float do_value;         // 补偿后溶解氧
          float temperature;      // 水温
          uint8_t gps_status;     // 定位状态标志
      } LoRaPacketTypeDef;
      
    • LoRa参数配置:SF12/BW125kHz(视距环境)→ SF7/BW250kHz(非视距)

关键技术实现

  1. 动态电源管理

    • 主电源监测:通过GPIO电平检测(PC0引脚)

    • 电源切换逻辑:

      void PowerMgmt_SwitchToSolar(void) {
          HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);  // 启用太阳能充电
          HAL_Delay(50);                                       // 等待电压稳定
          HAL_PWREx_DisableMainRegulator();                    // 切换至LDO供电
      }
      
  2. 数据校准机制

    • pH校准:两点校准法(存储于EEPROM)

      void I2C_PH_Calibrate(float zero, float span) {
          EEPROM_Write(PH_ZERO_ADDR, zero);
          EEPROM_Write(PH_SPAN_ADDR, span);
      }
      
    • 溶解氧温度补偿:

      float DO_Compensate(float raw, float temp) {
          return raw * (1.0 + 0.015 * (temp - 25.0));  // 根据SST公式计算
      }
      
  3. 低功耗优化

    • 动态电压频率调节(DVFS):

      void AdjustCPUFrequency(uint8_t level) {
          if(level == 0) __HAL_RCC_SYSCLKConfig(RCC_SYSCLKSOURCE_HSI);  // 8MHz
          else if(level == 1) __HAL_RCC_SYSCLKConfig(RCC_SYSCLKSOURCE_PLLCLK);  // 72MHz
      }
      
    • 外设按需唤醒:GPS模块采用脉冲模式(每10分钟唤醒1秒)

异常处理机制

  1. 三级容错设计

    • 硬件看门狗:MAX813L复位(1.2秒超时)
    • 软件看门狗:任务心跳监测(通过xTaskNotify)
    • 数据校验:CRC16校验失败自动重传
  2. 故障恢复流程

    graph TD
    A[系统启动] --> B{电源正常?}
    B -->|| C[加载校准参数]
    B -->|| D[启用超级电容]
    C --> E[初始化传感器]
    D --> E
    E --> F[进入运行态]
    F --> G{检测到故障?}
    G -->|| H[触发看门狗]
    G -->|| F
    

设计亮点

  1. 混合电源管理
    • 主电源(3.7V锂电池)与太阳能(5V输入)无缝切换
    • 超级电容后备供电(支持30分钟紧急数据传输)
  2. 自适应采样策略
    • 动态调整采样频率(正常10秒/次 → 低电量60秒/次)
    • GPS脉冲唤醒模式(每日仅唤醒3次更新位置)
  3. 数据可靠性保障
    • 双缓冲存储机制(RAM+Flash)
    • LoRa数据重传机制(最大3次自动重试)

系统已在太湖水质监测项目部署,累计运行超6个月,成功预警4次蓝藻爆发事件。未来可扩展多节点组网与边缘AI模型,实现藻类爆发预测。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。