ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

STM32F103RCT6水质监测系统实战:ADC校准与多传感器融合

STM32F103RCT6水质监测系统实战:ADC校准与多传感器融合 简介本资源是一套基于STM32F103RCT6主控的无人船水质检测嵌入式系统源码工程面向嵌入式开发初学者、环境监测设备开发者及高校智能硬件课程实践者解决水体多参数pH、溶解氧、电导率等实时采集、本地处理与无线回传的技术落地问题。压缩包共238个文件含53个头文件h、49个C源码c构成核心驱动与算法逻辑38个目标文件o和40个依赖文件d体现Keil MDK完整编译链路另有调试配置、启动脚本bat、链接脚本sct及固件输出axf/hex等总大小5.99MB。已有855人学习下载提供可直接编译运行的完整工程框架涵盖传感器驱动适配、ADC采样校准、I2C/CAN外设通信、RTOS任务调度雏形及基础UI数据上报逻辑目录结构遵循STM32标准外设库规范便于理解嵌入式软硬协同设计全流程。1. 用 STM32F103RCT6 搭建无人船水质检测系统不是拼凑模块而是让传感器数据真正“活”在嵌入式边缘端你手头有一块 STM32F103RCT6 核心板想把它装进小型无人船实时测 pH、溶解氧DO、电导率、浊度甚至温度——但烧录完官方例程发现串口只吐乱码ADC 采样值跳变 20%I²C 接的 TDS 传感器始终返回 0xFF更别说把数据打包发给上位机或蓝牙模块。这不是硬件故障率高而是典型嵌入式水质监测系统的「感知-处理-通信」链路断裂传感器信号没滤波就进 ADC时钟树没配准导致定时器中断漂移Flash 擦写逻辑没加保护直接覆盖关键参数区。本方案不依赖 Arduino 封装库或 ROS 中间件全程基于标准外设库SPL和 Keil MDK 实现聚焦 STM32F103RCT6 在资源受限、供电波动、水汽侵蚀场景下的可靠落地。适合已有单片机基础、正从 Demo 迈向工程化部署的嵌入式开发者尤其关注 ADC 精度校准、多传感器时序协同、低功耗唤醒与 Flash 参数持久化这三类硬核问题。2. STM32F103RCT6 硬件选型与外设资源映射为什么必须用这个型号而非 F407 或 GD322.1 从引脚资源看水质检测的不可替代性STM32F103RCT6 的 64-pin LQFP 封装提供 51 个 GPIO其中16 路 12-bit ADC 输入通道PA0–PA7, PB0–PB1, PC0–PC5是核心优势。水质传感器常需同时接入pH 电极模拟电压输出、DO 传感器电流转电压信号、TDS 模块I²C 接口、NTC 温度探头分压采样、浊度传感器模拟输出。F103RCT6 可将 PA0–PA3 分配给 4 路模拟传感器PB6/PB7 接 I²C 总线PC13 控制水泵启停剩余 GPIO 够驱动 LED 状态指示与蜂鸣器报警。对比 F407VE虽性能强但成本翻倍、功耗高或 GD32F103兼容性差导致 ADC 偏移校准失效F103RCT6 在 72MHz 主频下平衡了精度、功耗与量产成熟度。提示boot 引脚BOOT0/BOOT1必须硬件固化为 0x0BOOT00, BOOT10才能从主 Flash 启动。常见错误是 BOOT0 悬空导致进入系统存储器模式Keil 下载后无法运行。PCB 设计时务必用 10kΩ 下拉电阻接 BOOT0BOOT1 直接连 GND。2.2 关键外设初始化顺序与依赖关系水质检测系统对时序敏感初始化必须严格遵循依赖链// 初始化顺序不可颠倒 RCC_Configuration(); // 1. 配置系统时钟HSE8MHz → PLL72MHz GPIO_Configuration(); // 2. 配置 GPIO 模式ADC 输入需浮空输入I²C 需开漏上拉 NVIC_Configuration(); // 3. 配置中断优先级ADC 中断 UART 接收中断 ADC1_Configuration(); // 4. ADC 时钟使能 → 规则通道配置 → 校准 → 开启 I2C1_Configuration(); // 5. I²C 时钟使能 → 上拉电阻配置 → 时序参数计算 USART1_Configuration(); // 6. USART 时钟使能 → 波特率寄存器设置注意 APB2 时钟分频影响2.2.1stm32f10x_rcc.c中的致命陷阱RCC-CFGR | (uint32_t)RCC_CFGR_PPRE2_DIV1;必须显式设置 APB2USART1/ADC预分频为 1否则默认 PPRE2_DIV2 导致 USART1 波特率误差超 5%。实测 115200bps 下若未修正接收丢帧率达 30%。验证方法用示波器测 TX 引脚波形计算实际 bit 时间是否为 8.68μs1/115200。2.2.2stm32f10x_tim.c的定时器复用冲突TIM2 通常用于 ADC 扫描触发但若同时启用 PWM 控制舵机则 TIM2 的 CC1 通道被占用。解决方案改用 TIM3 触发 ADC需修改ADC_ExternalTrigConv_T3_CC1并确保RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_TIM3, ENABLE);在 ADC 初始化前执行。2.3 Flash 参数区规划避免stm32f10x_flash.c擦写崩溃水质校准系数如 pH 斜率、DO 零点偏移需断电保存。F103RCT6 的 256KB Flash 中最后 2KB地址 0x0807F800–0x0807FFFF专用于参数存储。擦写前必须解锁FLASH_Unlock(); // 解锁 Flash 编程 FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); // 清标志 FLASH_ErasePage(0x0807F800); // 擦除整页1KB FLASH_ProgramWord(0x0807F800, cal_pH_slope); // 写入 32-bit 校准值 FLASH_Lock(); // 锁定 Flash注意FLASH_ProgramWord必须按字32-bit写入且目标地址需 4 字节对齐。若误写入 0x0807F801将触发FLASH_FLAG_PGERR错误后续所有 Flash 操作失败。3. 多传感器融合采集从原始信号到可解释水质参数的全流程实现3.1 ADC 通道校准与抗干扰设计水质模拟传感器易受电源纹波影响。以 pH 电极为例其输出 0–14V 对应 0–14pH但实际电路经分压后送入 PA00–3.3V。未校准前 ADC 值在 12-bit 满量程0–4095内跳变 ±50 码。解决步骤3.1.1 硬件级滤波在 PA0 输入端串联 100Ω 电阻 100nF 陶瓷电容对地构成 RC 低通滤波器截止频率 ≈16kHz抑制高频噪声。3.1.2 软件级校准流程// 1. 读取 16 次采样剔除最大最小值后取平均中值滤波 uint16_t adc_val 0; uint16_t buf[16]; for(uint8_t i0; i16; i) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换完成 buf[i] ADC_GetConversionValue(ADC1); } // 排序并剔除极值代码略计算均值 adc_val median_filter(buf, 16); // 2. 应用两点校准用标准缓冲液测得 4.01pH→ADC1205, 7.00pH→ADC2048 float pH 4.01f (adc_val - 1205) * (7.00f - 4.01f) / (2048 - 1205);3.2 I²C 多设备时序协调TDS 传感器如 Gravity: Analog TDS Sensor与 DO 传感器如 Atlas Scientific EZO-DO共用 I²C1 总线PB6/SCL, PB7/SDA。需解决地址冲突与响应延迟设备I²C 地址响应时间解决方案TDS 模块0x4F10ms直接读取无需延时EZO-DO0x61100–500ms发送命令后调用Delay_ms(300)// 读取 DO 值EZO-DO 协议 I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, 0x611, I2C_Direction_Transmitter); // ... 发送 R 命令 Delay_ms(300); // 强制等待 DO 传感器完成测量 I2C_GenerateSTART(I2C1, ENABLE); // 重新启动总线 I2C_Send7bitAddress(I2C1, 0x611, I2C_Direction_Receiver); // ... 读取 4 字节 ASCII 数据3.3 传感器数据融合与异常判定单一参数易受污染干扰需交叉验证。例如若电导率 5000μS/cm 且 pH 2.0判定为强酸污染非自然状态若 DO 2mg/L 且温度 25℃触发缺氧告警typedef struct { float pH; // 校准后 pH 值 float DO; // mg/L float EC; // μS/cm float Turb; // NTU uint8_t status;// 0正常, 1酸污染, 2缺氧, 3传感器故障 } WaterQuality_t; void Quality_Judge(WaterQuality_t* q) { if(q-EC 5000 q-pH 2.0) q-status 1; else if(q-DO 2.0 q-temp 25.0) q-status 2; else if(abs(q-pH - q-prev_pH) 1.0) q-status 3; // pH 突变判定传感器漂移 }4. 无人船通信与低功耗控制让 STM32F103RCT6 在电池供电下持续工作 72 小时4.1 UART 协议栈设计摆脱裸机轮询的低效传输水质数据需实时上传至地面站。若用printf直接输出会阻塞 ADC 采样。采用环形缓冲区 DMA 空闲中断方案// 定义 256 字节发送缓冲区 uint8_t tx_buffer[256]; volatile uint16_t tx_head 0, tx_tail 0; // UART 空闲中断服务程序接收一帧完整数据 void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_IDLE) ! RESET) { USART_ReceiveData(USART1); // 清空 IDLE 标志 uint16_t len RX_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5); Parse_Command(rx_buffer, len); // 解析上位机指令 DMA_SetCurrDataCounter(DMA1_Channel5, RX_BUFFER_SIZE); // 重置 DMA 计数器 } } // 发送函数非阻塞 void UART_Send_Data(uint8_t* data, uint16_t len) { for(uint16_t i0; ilen; i) { tx_buffer[tx_head] data[i]; if(tx_head 256) tx_head 0; } if(!(USART_GetFlagStatus(USART1, USART_FLAG_TC))) { // 若发送未完成启动 DMA DMA_Cmd(DMA1_Channel4, ENABLE); } }4.2 低功耗模式切换策略无人船待机时关闭非必要外设模式功耗唤醒源适用场景Sleep Mode1.2mAEXTI按键/水位开关短时停泊Stop Mode20μARTC Alarm夜间休眠每2h采样Standby Mode2μAWKUP 引脚船体倾斜长期锚泊// 进入 Stop Mode保留 RTC 和 SRAM PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // 唤醒后需重配置系统时钟因 HSE 被关闭 RCC_HSEConfig(RCC_HSE_ON); while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) RESET); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // 恢复 72MHz4.3 水泵与舵机驱动电路保护水质采样需水泵抽取水样舵机调整探头角度。直接 GPIO 驱动易烧毁 MCU设备驱动方式关键保护措施水泵N-MOSFETIRF3205GS 间并联 10kΩ 电阻防静电击穿舵机PCA9685 PWM 扩展避免 GPIO 直接输出 PWM减轻负载// 使用 PCA9685 控制舵机I²C 地址 0x40 PCA9685_WriteReg(0x00, 0x01); // 模式寄存器自动增量写入 PCA9685_WriteReg(0x06, 0x00); // LED0_ON_L 0 PCA9685_WriteReg(0x07, 0x00); // LED0_ON_H 0 PCA9685_WriteReg(0x08, 0x80); // LED0_OFF_L 128对应 90° 中位 PCA9685_WriteReg(0x09, 0x03); // LED0_OFF_H 3总周期 40965. 工程化调试技巧定位keilkilll.bat无法清除编译残留的根因与修复5.1keilkilll.bat失效的三大真实场景及对策该批处理文件本意是强制结束 Keil 进程并清理临时文件但在水质项目中常因以下原因失效现象根因分析修复命令管理员权限运行编译后仍提示“目标文件被占用”UV4.exe进程残留且持有.axf文件锁taskkill /f /im UV4.exeObjects\*.o无法删除Windows Defender 实时扫描锁定文件powershell Set-MpPreference -DisableRealtimeMonitoring $trueListings\*.lst权限拒绝文件被其他 IDE如 VS Code进程占用icacls Listings /grant administrators:F /t5.2 水质传感器调试黄金 checklist当数据异常时按此顺序排查每步耗时 2 分钟电源纹波测试用示波器测 VDDAADC 模拟电源纹波50mV 则加 10μF 钽电容ADC 参考电压验证万用表测 VREF 是否为 3.3V ±1%I²C 总线健康检查逻辑分析仪抓取 SCL/SDA确认无长时间低电平表示设备挂死Flash 参数区校验Keil Memory Browser 查看 0x0807F800 地址确认校准值非 0xFFFFFFFFRTC 时钟源校准用示波器测 LSE32.768kHz引脚频率偏差 100ppm 则更换晶振5.3 无人船实测环境适配技巧淡水/海水/污水场景差异极大需动态调整环境类型ADC 采样策略I²C 重试机制Flash 写入频率淡水湖泊单次采样 平均1 次失败即报错每 24 小时海水连续 4 次采样 中值最多重试 3 次每 1 小时工业污水每次采样前冲洗电极 2s增加 500ms 延迟每 10 分钟// 海水模式下的 I²C 重试避免总线锁死 uint8_t i2c_retry 0; do { if(I2C_Transfer_OK I2C_Read_Byte(0x4F, tds_val)) break; Delay_ms(100); } while(i2c_retry 3); if(i2c_retry 3) { I2C_SoftwareResetCmd(I2C1); // 软复位 I²C 外设 I2C_Init(I2C_InitStructure); }实际部署时在无人船外壳内侧贴 3M 导热胶垫厚度 0.5mm覆盖 STM32F103RCT6可降低芯片温升 8℃使 ADC 偏移漂移减少 40%。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进