1.设计概述
本系统的软件设计采用模块化、层次化思想,以STM32F103C8T6为核心,完成底层硬件驱动、数据处理、通信协议解析及控制逻辑执行。整个软件架构从上到下分为应用层、中间层和硬件驱动层。应用层负责主控流程、按键响应、报警判断及UI刷新;中间层封装传感器标定算法、滤波处理、数据打包解包以及MQTT/AT指令集解析;硬件驱动层则直接操作寄存器或通过HAL库实现对GPIO、ADC、I2C、USART及定时器等外设的初始化与数据收发。采用这种分层设计可显著提高代码的可读性、可移植性和后续扩展能力。
系统主程序采用前后台(超循环)架构:前台为中断服务程序,负责接收ESP8266 Wi-Fi模块的串口数据、处理定时器溢出中断以及按键外部中断;后台为主循环,顺序执行传感器采集、数据处理、OLED显示更新、数据上报及设备控制任务。为保证数据采集的实时性与控制响应的及时性,主循环周期控制在50ms以内,其中ADC多通道采样使用DMA传输,避免占用CPU过多时间;对于pH传感器和电导率传感器这类模拟量输入,软件中加入滑动平均滤波算法(窗口长度10)抑制随机噪声,并通过标定公式(如三阶多项式拟合)将ADC原始值转换为实际工程单位(pH值、μS/cm)。浊度传感器输出电压与NTU值之间采用分段线性插值法进行标定,提高不同浓度区间的测量精度。
2.ESP8266 WIFI模块
在通信与数据上报方面,STM32通过USART3与ESP8266交互,采用AT指令集完成Wi-Fi模块的STA模式配置、TCP连接建立及MQTT协议登录。系统预先将网络SSID、密码及物联网平台地址(如阿里云IoT或OneNET的IP及端口)固化在代码中,上电后自动连接;屏幕上显示"ThingsColud connect..."连接信息。
c
OLED_DisplayStr(20,26,16,"ThingsColud ");
OLED_DisplayStr(16,42,16,"connect..... ");
OLED_Refresh();
u16 i=0;
u16 idex=0;
u8 stat;
u8 setup_ctl=0;
u8 buffer[200];
while(1)
{
stat=Esp8266_STA_TCPclinet_Init((u8 *)WIFI_NAME,(u8 *)WIFI_PASSWORD,(u8 *)SERVER_IP,SERVER_PORT);
if(stat==0)break;
Delay_Ms(500);
printf("stat=%d\r\n",stat);
}
printf("服务器连接成功\r\n");
while(1)
{
MQTT_Init();
stat=MQTT_Connect(ClientID,Username,Password);
if(stat==0)break;
Delay_Ms(500);
printf("正在连接....\r\n");
}
printf("连接成功\r\n");
stat=MQTT_SubscribeTopic(SET_TOPIC,0,1);
if(stat)printf("订阅失败\r\n");
else printf("订阅成功\r\n");
以5s为周期上报数据信息,数据内容包含有turbidity(浊度)、ph(ph值)、ec(电导率)、discharge(水流量)
c
if(time3>=5000)//5s上报一次数据
{
time3=0;
/*
turbidity(浊度)
ph(ph值)
ec(电导率)
discharge(水流量)
*/
sprintf(mqtt_message,"{\"turbidity\":%d,\"ph\":%.1f,\"ec\":%.1f,\"discharge\":%.1f}",zhuodu_val,PH_val,TDS_value,discharge_temp);//温度
printf("msg=%s\n",mqtt_message);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
}
3.ThingsColud平台配置
1.注册账号登录平台。thingscloud地址

进入控制台,创建项目


2.创建设备



3.创建设备类型


4.关联设备

5.添加功能


6.创建用户

7.创建用户应用



8.配置应用UI


9.接入平台

10.数据上报与下发

3.PH传感器驱动
溶液的酸碱度(PH 值)是溶液的一个重要特性。工业级PH 变送器价格昂贵;市面上的PH 测试笔是成熟产品,无法进行二次设计开发;PH 复合电极输出mV 级的电压信号,单片机无法直接进行识别处理,基于这些现状,本次采用了这款 PH 传感器模块。该模块价格低廉、使用方便、测量精度高、可直接输出0~5V。
PH 传感器模块的组成如下图所示。该模块通过BNC 接头与PH复合电极进行连接,扩展有DS18B20 温度传感器接口,方便进行软件温度补偿设计。调节10K 蓝色电位器的旋钮可以进行放大倍数调节(顺时针调节增大、逆时针调节减小)。


PH数据处理:
依据测的得电压值用excel 进行曲线公式拟合。图中橙色线为5V ADC 采集系统标准公式,蓝色线为3.3V ADC 采集系统标准公式。

c
float PH_val;
//PH值数据处理
void PH_Value_Conversion(u16 ad_val)
{
//此模块输出电压范围调整为0~3V3,调整方法如下
//需要在PH计放在9.18标准缓冲液里,调节旋转电位器,将输出调整为1.3V
//需要在PH计放在6.86标准缓冲液里,调节旋转电位器,将输出调整为1.7V
//需要在PH计放在PH4.0标准缓冲液里,调节旋转电位器,将输出调整为2.2V
char buffer_show[100];
PH_val=(float)ad_val*(3.3/4096);
PH_val = -5.7541*PH_val+16.654; //输出电压范围0~3V3
// printf("adc4 val: %d\r\n",ad_val);
// printf("PH val: %f\n",PH_val);
if(PH_val>=10 ||PH_val<0)BEEP=1;
else BEEP=0;
snprintf(buffer_show,sizeof(buffer_show),"%.1f ",PH_val);
OLED_DisplayStr(45,48,16,(u8*)buffer_show);
}
4.TDS电导率传感器驱动
TDS(TotalDissolved Solids),中文名总溶解固体,又称溶解性固体总量,表明1升水中溶有多少毫克溶解性固体。一般来说,TDS值越高,表示水中含有的溶解物越多,水就越不洁净。虽然在特定情况下TDS并不能有效反映水质的情况,但作为一种可快速检测的参数,TDS目前还是可以作为有效的水质情况反映参数来作为参考。常用的TDS检测设备为TDS笔,虽然价格低廉,简单易用但不能把数据传给控制系统,做长时间的在线监测,并做水质状况分析。使用专门的仪器,虽然能传数据,精度也高,但价格很贵。为此,推出了这款TDS传感器模块。该模块即插即用,使用简单方便。测量用的激励源采用交流信号,可有效防止探头极化,延长探头寿命的同时,也增加了输出信号的稳定性.TDS探头为防水探头,可长期浸入水中测量。该产品可应用于生活用水、水培等领域的水质检测。有了这个传感器,可轻松DIY-套TDS检测仪了,轻松检测水的洁净程度,为你的水质把好关。

-
产品参数
-
供电电压:3.3 ~ 5.0V
-
工作电流:3~6mA
-
TDS探针接口:2Pin XH-2.54
-
温度传感器接口:3PinXH-2.54
-
输出信号范围:0~ 2.3V
-
TDS测量范围:0~1000ppm
-
TDS测量精度:土5%F.S.(25C)
-
模块尺寸:42mmX31.2mm
-
信号输出:0~2.3V模拟信号输出,兼容5V、3.3V两种控制系统
-
DS探头参数:TDS探头适用2分PE管
-
激励源为交流信号,有效防止探头极化
-
防水:防水探头,可长期浸入水中测量
-
引脚说明:

-
VCC:供电电压正级
-
GND:供电电压负极
-
T1:温度传感器DS18B20信号输出口(可通过软件进行温度补偿)
-
A0:模拟信号输出(输出电压范围0-2.3V)
-
+:温度传感器电源正级
-
T:温度传感器信号线
-
:温度传感器电源负极
-
1:TDS探针引线1
-
2:TDS探针引线2
-
程序驱动:
c
// 用于保存转换计算后的电压值
float ADC_ConvertedValueLocal[4];
float compensationCoefficient=1.0;//温度校准系数
float TEMP_Value=25.0;
float compensationVolatge;
float TDS_value=0.0,voltage_value;
float kValue=1.67;
/**************TDS值采集函数***************/
void TDS_Value_Conversion(u16 ad_val)
{
char buffer_show[100];
ADC_ConvertedValueLocal[0]=(float)ad_val/4096*3.3; //AD转换
compensationCoefficient=1.0+0.02*((TEMP_Value/10)-25.0);
compensationVolatge=ADC_ConvertedValueLocal[0]/compensationCoefficient;
TDS_value=(133.42*compensationVolatge*compensationVolatge*compensationVolatge -
255.86*compensationVolatge*compensationVolatge + 857.39*compensationVolatge)*0.5*kValue;
if((TDS_value<=0)){TDS_value=0;}
if((TDS_value>1400)){TDS_value=1400;}
// printf("TDS=%.2f\n",TDS_value);//单位ppm,溶解性总固体≤1000ppm
//电导率
if(TDS_value>1000)
{
BEEP=1;
}
else BEEP=0;
snprintf(buffer_show,sizeof(buffer_show),"%.1f ",TDS_value);
OLED_DisplayStr(61,32,16,(u8*)buffer_show);
/*
(1)TDS 的测量单位有时也用 mg/L 表示,与 ppm 的换算关系为 1mg/L=1ppm;
(2)TDS 和电导率往往存在一种相通的关系,有时候 TDS 也可以用来表示电导率,
两者的关系:1ppm =2uS/cm,其中 uS/cm 为电导率的单位。
*/
}
5.浊度传感器
水的浑浊度是指水中含有的泥沙,粘土,有机物,浮游生物和微生物等悬浮物质,造成的浑浊程度。工业级的浊度传感器或浊度仪价格昂贵,在电子产品设计中成本太高不适合选用;因此我们选取了一款在家用电器洗衣机、洗碗机上广泛应用的浑浊度传感器,这款浊度传感器利用光学原理,通过溶液中的透光率和散射率来综合判断浊度情况。传感器内部是一个红外线对管,当光线穿过一定量的水时,光线的透过量取决于该水的污浊程度,水越污浊,透过的光就越少。光接收端把透过的光强度转换为对应的电流大小,透过的光多,电流大,反之透过的光少,电流小。浊度传感器模块将传感器输出的电流信号转换为电压信号,通过单片机进行 AD 转换数据处理。改款模块具有模拟量和数字量输出接口。模拟量可通过单片机A/D 转换器进行采样处理,以获知当前水的污浊度。数字量可通过模块上的电位器调节触发阈值,当浊度达到设置好的阈值后,D1 指示灯会被点亮,传感器模块输出由高电平变成低电平,单片机通过监测电平的变化,判断水的浊度是否超标,从而预警或者联动其他设备。该模块价格低廉、使用方便、测量精度高可以用于洗衣机、洗碗机等产品的水污浊程度的测量;也可以用于工业现场控制,环境污水采集等需要浊度检测控制的场合。

传感器模块输出电压与浑浊度关系如下图所示:

浊度值与模块输出电压满足如下关系:
TU=-865 .68*U +K
上式中TU 为当前浊度值,U 为当前温度条件下模块的输出电压值,K 为截距值,需通过标定方法得到。
传感器输出电压值大小受温度影响,输出电压与温度曲线关系如下图所示。进行浊度测量时需进行温度补偿以保证测量精度。

温度校正公式:
△U=-0 .0192 *(T -25)
上式中△U 为温度变化引起的电压差;T 为当前测量温度值。
-
校准方法
由于浊度传感器的个体差异、环境光或未进行温度补偿等原因。为获得更精确的浊度值,在测量之前,必须进行校准。具体操作方法介绍如下。
第一步:安装浊度传感器,给传感器模块供电。使用0NTU 的标准溶液(或者接近0NTU 的纯净水或蒸馏水)进行校准;
第二步:在传感器使用环境状态下(尽量避免光线强弱引起的误差)测量记录当前校准溶液的温度值并记录为T测试;测量并记录传感器模块的输出电压为U 测试。
第三步:计算温差引起的电压差值U。将测量得到T 测试代入温度修正公式。
△U =-0.0192*(T测试-25)
第四步:计算0NTU 标准液(25℃)标准电压值U25℃。
U 25℃=U 测试-△U
第五步:计算K 值,将计算得到标准电压值U25℃代入标准曲线公式。
K =865.68*U 25℃
第六步:修正标准曲线公式。将计算得到的K 代入标准曲线公式。
TU =865 .68 * U + K
-
程序设计
c
/**************TDS值采集函数***************/
float TU=0.0;//读取的AD数值转换为电压值
float TU_value=0.0;//浊度值
float TU_calibration=0.0;//校准后的电压值
float temp_data=0.0;//温度值
float K_Value=3047.19;
void TU_Value_Conversion()
{
temp_data=DS18B20_Get_Temp();//读取温度
TU =(float) ADC_ConvertedValue/4096*3.3; // 读取转换的AD值
TU_calibration=-0.0192*(temp_data/10-25)+TU;
TU_value=-865.68*TU_calibration + K_Value;
if(TU_value<=0){TU_value=0;}
if(TU_value>=3000){TU_value=3000;}
}