前言
💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗
👇🏻 精彩专栏 推荐订阅👇🏻
单片机设计精品实战案例✅
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助更多的人
资料获取
文章底部名片,详细资料联系我。
设计介绍
水资源一直以来都是人类最重要的财富之一,由于工农业的发展人
们对水资源的污染变得越来越严重,保护水资源应势在必行。在这个科学技术日新月异的时代,嵌入式技术和物联网技术一直在发展未曾被淘汰便足以证明这些技术的优秀,结合现在的时代背景对水质检测的需求,水质检测对世界各国家的发展以及人们的生活至关重要。本文在以上基础上本文利用嵌入式技术和物联网技术设计一款基于 STM32F103C8T6单片机实现水质检测的功能,单片机外接 E-201 系列的 PH 传感器和TSW-30 浑浊度传感器采集数据然后通过单片机计算具体水质数据,再将水质数据显示到 LCD1602 液晶显示器上,并外接 ESP8266WIFI 模块通过单片机将水质数据实时传输到手机应用上显示,该设计与传统的水质检测相比有着采集效率高,实时性好,成本低等优点。同时,水资检测是保护水资源的重要手段之一,对人们的身体健康有着良好的保障,对国家的发展有着重要意义。
功能介绍
本设计以单片机为基础对水质进行检测,需要实现显示功能、水质数据采集功能、无线通信功能,实现一个自动采集水质数据并显示出来的系统。
显示需求分析:
单片机较为常用的液晶显示屏主流有 LCD1602 和 LCD12864,这两款液晶显示器区别不大,显示内容上 LCD12864 比 LCD1602 能够呈现的信息更多,LCD12864能够显示中文,LCD1602 显示数字和英文更为方便,后者比前者相对便宜,且本设计用于显示大小对 LCD1602 已经足够,所以显示方面选择性价比更高的 LCD1602。
水质传感器需求分析:
水质可以检测的常见参数有 COD、氨氮、色度、浑浊度、PH 值等,但由于成本和技术上的问题,只能选取少量参数进行检测。
(1)COD 是水中的还原物被氧化需要的量,是一种化学检测方法,但一般用在工业级别的检测上,且会因使用的氧化剂会导致结果有所区别,故不选取。
(2)氨氮是检测由 NH3 和 NH4+ 在水中结合而成的化合物含量,这中化合物会导致水富营养化,这种检测仪器较为昂贵,设计成本太高所以不适用于本设计。
(3)色度是天然水或者对水中的悬浮物进行处理,然后进行检测其颜色的一种检测方式,但由于检测原理较为复杂,应用于单片机检测上难度较大,故也不选用
(4)PH 是指水中氢离子浓度,这种检测方式虽然也在工业上使用,且市面上的 PH 检测仪器无法进行二次开发,但却有成熟的 PH 检测模块可以配合 ph 测量电极使用,价格便宜,使用起来简单方便,可采用。
(5)浑浊度指水中悬浮物质的含量,检测原理是根据水对光线的穿透量的大小,虽然工业级的检测仪器价格高昂,但可采用洗衣机、洗碗机所使用的浑浊度传感器,这种传感器价格低廉,适合用于开发,可采用。
无线通信需求分析:
目前嵌入式使用比较多的无线通信技术有红外遥控、蓝牙、WIFI。红外遥控技术需要端口对接,受障碍物影响较大,而且传输距离较短;而蓝牙技术虽然没有了障碍物的影响,能够全方位地传输信息,但缺点是传输距离仍然较短,传输速率较慢;WIFI 相对以上两者,没有了那些缺点,传输距离和传输速率都有了明显的提升,以上三种技术中显然 WIFI是最适用的。
设计程序
#include "sys.h"
#include "delay.h"
#include "gpio.h"
#include "OLED_I2C.h"
#include "ds18b20.h"
#include "usart1.h"
#include "esp8266.h"
#include "adc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STM32_RX1_BUF Usart1RecBuf
#define STM32_Rx1Counter RxCounter
#define STM32_RX1BUFF_SIZE USART1_RXBUFF_SIZE
#define Offset 0.00 //deviation compensate
#define RATIO 4.51/4.08
short temperature=0; //温度
u8 tempSetVal=40; //温度上限
u8 shuaxin = 0; //刷新标志
u8 setFlag = 0; //设置标志
float PH = 0.0;
u16 Ph_min = 300,Ph_max = 900; //PH下限上限
u16 Turbidity=0;
u16 TurSetMax=1000; //浊度上限
unsigned long int avgValue; //Store the average value of the sensor feedback
char display[16];
void Usart1RxBufClear(void) //清除串口接收缓存
{
memset(STM32_RX1_BUF, 0, STM32_RX1BUFF_SIZE);//清除缓存
STM32_Rx1Counter = 0;
}
void InitDisplay(void) //初始化显示
{
unsigned char i=0;
OLED_ShowStr(0, 2, "PH:", 2,0);
for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+0,0);//显示中文:温度
for(i=0;i<2;i++)OLED_ShowCN(i*16,6,i+2,0);//显示中文:浊度
OLED_ShowChar(32,4,':',2,0);
OLED_ShowChar(32,6,':',2,0);
}
void displaySetValue(void) //显示设置的值
{
if(setFlag == 1 ||setFlag == 2)
{
sprintf(display,"%5.2f",(float)Ph_min/100);
OLED_ShowStr(40, 4,(u8 *)display, 2,setFlag+1-1);
sprintf(display,"%5.2f",(float)Ph_max/100);
OLED_ShowStr(40, 6,(u8 *)display, 2,setFlag+1-2);
}
if(setFlag == 3)
{
sprintf(display,"%02d",tempSetVal);
OLED_ShowStr(40, 4,(u8 *)display, 2,setFlag+1-3);
}
if(setFlag == 4)
{
sprintf(display,"%04d",TurSetMax);
OLED_ShowStr(40, 4,(u8 *)display, 2,setFlag+1-4);
}
}
void keyscan(void) //按键扫描
{
unsigned char i=0;
if(KEY1 == 0) //设置键
{
delay_ms(20);
if(KEY1 == 0)
{
while(KEY1 == 0);
BEEP=0;
setFlag ++;
if(setFlag == 1)
{
OLED_CLS(); //清屏
for(i=0;i<2;i++)OLED_ShowCN(i*16+32,0,i+8,0);//显示中文:设置
OLED_ShowStr(62, 0, " PH", 2,0);
for(i=0;i<2;i++)OLED_ShowCN(i*16,4,i+4,0);//显示中文:下限
for(i=0;i<2;i++)OLED_ShowCN(i*16,6,i+6,0);//显示中文:上限
OLED_ShowChar(32,4,':',2,0);
OLED_ShowChar(32,6,':',2,0);
}
if(setFlag == 3)
{
for(i=0;i<2;i++)OLED_ShowCN(i*16+64,0,i+0,0);//显示中文:温度
OLED_ShowStr(56, 4, " ", 2,0);
OLED_ShowCentigrade(56, 4); //℃
OLED_ShowStr(0, 6, " ", 2,0);
}
if(setFlag == 4)
{
for(i=0;i<2;i++)OLED_ShowCN(i*16+64,0,i+2,0);//显示中文:浊度
OLED_ShowStr(72, 4, "NTU", 2,0);
}
if(setFlag >= 5)
{
setFlag = 0;
OLED_CLS(); //清屏
InitDisplay();
}
displaySetValue();
}
}
if(KEY2 == 0) //加键
{
delay_ms(100);
if(KEY2 == 0)
{
if(setFlag == 1)
{
if(Ph_max-Ph_min > 10)Ph_min+=10;
}
if(setFlag == 2)
{
if(Ph_max < 1400)Ph_max+=10;
}
if(setFlag == 3)
{
if(tempSetVal<99)tempSetVal++;
}
if(setFlag == 4)
{
if(TurSetMax<3000)TurSetMax+=10;
}
displaySetValue(); //显示没有设置值
}
}
if(KEY3 == 0) //减键
{
delay_ms(100);
if(KEY3 == 0)
{
if(setFlag == 1)
{
if(Ph_min >= 10)Ph_min-=10;
}
if(setFlag == 2)
{
if(Ph_max-Ph_min > 10)Ph_max-=10;
}
if(setFlag == 3)
{
if(tempSetVal>0)tempSetVal--;
}
if(setFlag == 4)
{
if(TurSetMax>=10)TurSetMax-=10;
}
displaySetValue(); //显示没有设置值
}
}
}
void Get_PH(void) //获取PH
{
u16 buf[10];//buffer for read analog
u8 i,j;
float phValue=0.0;
for(i=0;i<10;i++) //Get 10 sample value from the sensor for smooth the value
{
buf[i]=Get_Adc_Average(ADC_Channel_8,10);
}
for(i=0;i<9;i++) //sort the analog from small to large
{
for(j=i+1;j<10;j++)
{
if(buf[i]>buf[j])
{
int temp=buf[i];
buf[i]=buf[j];
buf[j]=temp;
}
}
}
avgValue=0;
for(i=2;i<8;i++) //take the average value of 6 center sample
avgValue+=buf[i];
phValue=((float)avgValue*5.0/4095/6)*RATIO; //convert the analog into millivolt
PH=(phValue*(-5.290))+23.053; //convert the millivolt into pH value
if(PH<0)PH=0;
if(PH>14.0)PH=14.0;
}
void Get_Turbidity(void) //获取浑浊度
{
float T;
u16 adcx = 0;
adcx = Get_Adc_Average(ADC_Channel_9,20);//读取AD值
T = adcx;
T = T*(3.3/4096)+1.72;
if(T < 2.5)
{
T = 3000;
}
else
{
T = (-1120.4*T*T+5742.3*T-4352.9); //Tul是AD值
}
if(T < 0)
{
T = 0;
}
Turbidity = (u16)T;
if(Turbidity > 3000)Turbidity = 3000;
}
void UsartSendData(void) //串口发送数据
{
char SEND_BUF[100];
char BUF[50];
memset(SEND_BUF,0,sizeof(SEND_BUF)); //清空缓冲区
sprintf(SEND_BUF,"PH:%5.2f\r\n",PH);
memset(BUF,0,sizeof(BUF)); //清空缓冲区
sprintf(BUF,"温度:%d℃\r\n",temperature);
strcat(SEND_BUF,BUF);
memset(BUF,0,sizeof(BUF)); //清空缓冲区
sprintf(BUF,"浊度:%dNTU\r\n",Turbidity);
strcat(SEND_BUF,BUF);
strcat(SEND_BUF,"\r\n");
ESP8266_SendData((u8 *)SEND_BUF, strlen(SEND_BUF)); //ESP8266发送数据
}
int main(void)
{
u16 timeCount1 = 300;
u16 timeCount2 = 10;
u8 shanshuo=0;
delay_init(); //延时函数初始化
NVIC_Configuration(); //中断优先级配置
I2C_Configuration(); //IIC初始化
delay_ms(200);
Adc_Init(); //ADC初始化
OLED_Init(); //OLED液晶初始化
OLED_CLS(); //清屏
OLED_ShowStr(0, 2," Loading... ", 2,0);
ESP8266_Init();
OLED_CLS(); //清屏
InitDisplay();
KEY_GPIO_Init(); //按键引脚初始化
DS18B20_GPIO_Init();
DS18B20_Init(); //初始化显示
uart1_Init(9600);
while(1)
{
keyscan(); //按键扫描
timeCount1 ++;
if(timeCount1 >= 300 && !setFlag) //延时一段时间读取
{
timeCount1 = 0;
shanshuo=!shanshuo;
Get_PH() ; //获取PH
/*超限的时候闪烁显示*/
if(((PH*100)<=Ph_min || (PH*100)>=Ph_max) && shanshuo)
{
OLED_ShowStr(32, 2," ", 2,0);
}
else
{
sprintf(display,"%5.2f ",(float)PH);
OLED_ShowStr(32, 2,(u8 *)display, 2,0);
}
temperature = ReadTemperature();//读取温度
/*超限的时候闪烁显示*/
if((temperature>=tempSetVal) && shanshuo)
{
OLED_ShowStr(40, 4," ", 2,0);
}
else
{
sprintf(display,"%02d",temperature);
OLED_ShowStr(40, 4,(u8 *)display, 2,0);
OLED_ShowCentigrade(56, 4); //℃
}
Get_Turbidity() ;
/*超限的时候闪烁显示*/
if((Turbidity>=TurSetMax) && shanshuo)
{
OLED_ShowStr(40, 6," ", 2,0);
}
else
{
sprintf(display,"%dNTU ",Turbidity);
OLED_ShowStr(40, 6,(u8 *)display, 2,0);
}
if(((PH*100)<=Ph_min || (PH*100)>=Ph_max)||(temperature>=tempSetVal)||(Turbidity>=TurSetMax))BEEP= 1;else BEEP=0; //超限蜂鸣器报警
timeCount2 ++;
if(timeCount2 >= 3)
{
timeCount2 = 0;
UsartSendData(); //串口发送数据
}
}
delay_ms(1);
}
}
具体实现截图
参考文献
[1]顾超.基于物联网技术的水质监测系统的设计与实现[D].北京:北京邮电大学,2020.
[2]佟以轩.多参数水质监测设备及多层监测站研究[D].大连:大连理工大学,2019.
[3]李文,蔡永青,马永跃,陈银银.基于嵌入式技术的双光谱水质多参数一体化系统设计[J]. 仪表技术与传感器,2022,(02):101-106.
[4]范璇逸.基于 LoRa 的水质检测仪的设计[D].武汉:华中科技大学,2019.
[5]赵世栋.基于物联网技术的化工厂污水水质监测系统的研究[D].淮安:淮阴工学院,2021.
[6]史亚敬,饶勇.嵌入式技术在远程监控系统中应用[J].计算机产品与流通,2018(02):153+164.
[7]秦学伟.基于物联网的水质实时在线监测系统设计与实现[D].聊城:聊城大学,2017.
[8]夏云飞.基于无线传感网络的水质检测研究[D].马鞍山:安徽工业大学,2018.
[9]吴迪.基于云平台的多参数实时在线水质检测[D].杭州:中国计量大学,2019.
[10]杜剑峰.基于物联网技术的养殖水质监测系统的设计与实现[D].大连:大连海洋大学,2019.
[11]唐明佳,田孝文,周子鹏.基于嵌入式物联网技术的水质检测系统设计[J].吉首大学学报(自然科学版),2020,41(03):22-27
设计获取
文章下方名片联系我即可~
精彩专栏推荐订阅:在下方专栏👇🏻
毕业设计精品实战案例
收藏关注不迷路!!
🌟文末获取设计🌟