基于单片机实现温湿度、粉尘和SF6气体浓度监测系统
1. 头文件及相关定义
#include<reg52.h>
int write_com(unsigned char);//声明写命令函数
int write_date(unsigned char);
sbit RS = P2^0;
sbit RW = P2^1;
sbit EN = P2^2;
sbit TRH = P3^2;//温湿度传感器DHT11数据接入
sbit key1=P1^0;
sbit key2=P1^1;
sbit key3=P1^2;
sbit key4=P1^3;
sbit sp=P3^7;
sbit led1=P3^3;
sbit led2=P3^4;
sbit led3=P3^5;
sbit led4=P3^6;
sbit SDO=P2^3; //定AD芯片端口义端口
sbit SDI=P2^4;
sbit CS=P2^5;
sbit CLK=P2^6;
sbit EOC=P2^7;
sbit relay1=P1^4;
sbit relay2=P1^5;
sbit relay3=P1^6;
sbit relay4=P1^7;
unsigned char code table[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x2e,0x00};
unsigned char code table2[6]='Temp: ';
unsigned char code table3[6]='Humi: ';
unsigned char code table4[6]='Dust: ';
unsigned char code table5[6]='SF6: ';
unsigned char code table6[6]='TH: ';
unsigned char code table7[6]='HL: ';
unsigned char code table8[6]='DH: ';
unsigned char code table9[6]='SH: ';
unsigned char code table10[6]='mg/m3 ';
unsigned char code table11[6]='ppm ';
unsigned char str;
unsigned char DHT11[5],RTflag=0;
unsigned char FLAG; //超时标志位
unsigned char m,r,r2,a,th1,th2,rh1,rh2,q,zs,kz1,kz2,kz3,set_fg;
int k1=40,k2=75,k3=50,k4=1000;
unsigned int dust,sf6,ad1,ad2;
bit y1,y2,y3;
- #include<reg52.h>: 包含了单片机8051的寄存器定义文件,方便使用单片机的各种寄存器。
- int write_com(unsigned char); 和 int write_date(unsigned char);: 声明了两个函数,分别用于向LCD显示器写入命令和数据。
- sbit 定义: 使用sbit关键字定义了各个端口的引脚,用于控制LCD显示器、按键、继电器、LED灯、温湿度传感器等外围设备。
- unsigned char code table[]: 定义了一个字符数组,用于存放数字和'.'的ASCII码,方便将数值转换为字符显示。
- unsigned char code table2[]-table11[]: 定义了几个字符串数组,用于存放LCD显示器需要显示的文字信息。
- unsigned char str: 定义了一个无符号字符变量,用于存放字符串。
- unsigned char DHT11[5],RTflag=0: 定义了一个数组用于存放DHT11传感器读取的5个字节数据,其中RTflag为数据校验标志位。
- unsigned char FLAG: 定义了一个无符号字符变量,用于存放超时标志位。
- unsigned char m,r,r2,a,th1,th2,rh1,rh2,q,zs,kz1,kz2,kz3,set_fg: 定义了一系列无符号字符变量,用于存储不同的数据信息。
- int k1=40,k2=75,k3=50,k4=1000: 定义了4个整型变量,用于存放各个传感器设置的阈值。
- unsigned int dust,sf6,ad1,ad2: 定义了4个无符号整型变量,用于存放粉尘浓度、SF6气体浓度和AD芯片读取的数值。
- bit y1,y2,y3: 定义了3个位变量,用于存放一些控制状态。
2. 延时函数
void delay (unsigned int xms)
{
unsigned int i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void delay_10us() //10us延时函数
{
unsigned char i;
i--;
i--;
i--;
i--;
i--;
// i--;
}
void Delay_t(unsigned int j)
{ unsigned char i;
for(;j>0;j--)
{
for(i=0;i<27;i++);
}
}
- delay(unsigned int xms): 这是一个通用的延时函数,根据输入的参数xms,实现毫秒级的延时。
- delay_10us(): 这是一个10微秒的延时函数。
- Delay_t(unsigned int j): 这是一个自定义的延时函数,用于控制DHT11传感器的数据读取过程。
3. 字节转字符串函数
typedef unsigned char BYTE;
BYTE *ByteToStr(BYTE n)
{
BYTE str[4];
BYTE * pStr;
pStr = str;
if (n>99)
{
*pStr = n/100;
n %= 100;
*pStr += '0';
pStr ++ ;
*pStr = n/10;
n%=10;
*pStr +='0';
pStr ++ ;
}
if (n>9)
{
*pStr = n/10;
n %= 10;
*pStr += '0';
pStr++ ;
}
if (n<10)
{
*pStr = n+'0';
pStr++;
}
*pStr = 0;
return str;
}
- ByteToStr(BYTE n): 该函数用于将一个字节的数值转换为字符串,以便于显示。
4. 发送字符串函数
void send(char *dis)
{
while(*dis!='�') {
SBUF=*dis;
dis++;
while(!TI);
TI=0; //软件请发送中断
}
}
- send(char *dis): 该函数用于通过串口发送字符串。
5. 读取AD芯片函数
unsigned int read2543(unsigned char con_word)
{
unsigned int ad=0,i;
CLK=0; //时钟首先置低
CS=0; //片选为0,芯片工作
for(i=0;i<12;i++)
{
if(SDO) //首先读TLC2543的一位数据
ad=ad|0x01;
SDI=(bit)(con_word&0x80); //向TLC2543写一位数据
CLK=1; //时钟上升沿,TLC2543输出使能
delay(3);
CLK=0; //时钟下降沿,TLC2543输入使能
delay(3);
con_word<<=1;
ad<<=1;
}
CS=1;
ad>>=1;
return(ad);
}
- read2543(unsigned char con_word): 该函数用于读取TLC2543 AD芯片的数值。
6. AD值转换函数
void volt_result() //AD值转温度
{
ad1=read2543(0x00);
ad2=read2543(0x10);
dust=ad1*(100.0/4096);
sf6=ad2*(2000.0/4096);
}
- volt_result(): 该函数用于将读取的AD值转换为粉尘浓度和SF6气体浓度。
7. LCD初始化函数
int init()//初始化函数体
{
EN = 0;
write_com(0X38);//设置16*2显示,5*7点阵,8位数据接口
write_com(0X0C);//设置开显示,不显示光标
write_com(0X06);//写一个字符时,整屏右移
write_com(0X01);//显示清零
return 0;
}
- init(): 该函数用于初始化LCD显示器。
8. LCD写命令函数
int write_com(unsigned char com)//写命令的函数体
{
RS = 0;
RW = 0;
P0 = com;
delay(5);
EN = 1;
delay(5);
EN = 0;
return 0;
}
- write_com(unsigned char com): 该函数用于向LCD显示器写入命令。
9. LCD写数据函数
int write_date(unsigned char TRHe)//写数据的函数体
{
RS = 1;
RW = 0;
P0 = TRHe;
delay(5);
EN = 1;
delay(5);
EN = 0;
return 0;
}
- write_date(unsigned char TRHe): 该函数用于向LCD显示器写入数据。
10. 读取DHT11数据函数
unsigned char write_byte1() //读一个字节
{
unsigned char i,comdata,temp1;
for(i=0;i<8;i++)
{
FLAG=2;
while((!TRH)&&FLAG++);//判断数据位是0还是1
delay_10us();
delay_10us();
delay_10us();
temp1=0;
if(TRH)temp1=1; // 如果高电平高过预定0高电平值则数据位为 1
FLAG=2;
while((TRH)&&FLAG++);//flag先与后加1 如果dat一直为1 uchar型变量 flag 溢出变为0 再自加1
if(FLAG==1)break; //超时则跳出for循环
comdata<<=1;//左移一位 高位在前 低位在后
comdata|=temp1;
}
return (comdata);
}
void DHT11_5() //读5个字节数据 两个字节为温度数据 两个字节为湿度数据 最后一个字节为校验
{
unsigned char i,temp;
//主机拉低18ms
TRH=0;
Delay_t(180);
TRH=1;
//总线由上拉电阻拉高 主机延时20us
delay_10us();
delay_10us();
delay_10us();
delay_10us();
//主机设为输入 判断从机响应信号
TRH=1;
//判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
if(!TRH) //T !
{
FLAG=2; //超时标志位
while((!TRH)&&FLAG++);//判断从机是否发出 80us 的低电平响应信号是否结束
FLAG=2;
ET0=0;
while((TRH)&&FLAG++); //判断从机拉高80us是否结束
for(i=0;i<5;i++)//数据接收状态
{
DHT11[i]=write_byte1();
}
TRH=1; //释放数据总线 为下一次读取做好准备
temp=(DHT11[0]+DHT11[1]+DHT11[2]+DHT11[3]);
if(temp==DHT11[4]) //数据校验
{
RTflag=1;
}
if(RTflag==1) //如果RTflag=1 说明读取到得数据正确
{
RTflag=0;
rh1=DHT11[0]/10;
rh2=DHT11[0]%10;
th1=DHT11[2]/10;
th2=DHT11[2]%10;
ET0=1;
}
}
}
- write_byte1(): 该函数用于读取DHT11传感器的一个字节数据。
- DHT11_5(): 该函数用于读取DHT11传感器5个字节数据,并进行数据校验。
11. LCD显示函数
void display()
{
unsigned char i;
if(m==0)
{
if(set_fg==0)
{
write_com(0x80);
for(i=0;i<6;i++)
write_date(table2[i]);
write_date(table[th1]);
write_date(table[th2]);
write_date(0xdf);
write_date('C');
for(i=0;i<8;i++)
write_date(' ');
write_com(0xc0);
for(i=0;i<6;i++)
write_date(table3[i]);
write_date(table[rh1]);
write_date(table[rh2]);
write_date('%');
for(i=0;i<8;i++)
write_date(' ');
}
else
{
write_com(0x80);
for(i=0;i<6;i++)
write_date(table6[i]);
write_date(table[k1/10]);
write_date(table[k1%10]);
for(i=0;i<8;i++)
write_date(' ');
write_com(0xc0);
for(i=0;i<6;i++)
write_date(table7[i]);
write_date(table[k2/10]);
write_date(table[k2%10]);
for(i=0;i<8;i++)
write_date(' ');
}
}
if(m==1)
{
if(set_fg==0)
{
write_com(0x80);
for(i=0;i<6;i++)
write_date(table4[i]);
write_date(table[dust/100]);
write_date(table[dust%100/10]);
write_date('.');
write_date(table[dust%10]);
for(i=0;i<6;i++)
write_date(table10[i]);
write_com(0xc0);
for(i=0;i<6;i++)
write_date(table5[i]);
write_date(table[sf6/1000]);
write_date(table[sf6%1000/100]);
write_date(table[sf6%100/10]);
write_date(table[sf6%10]);
for(i=0;i<6;i++)
write_date(table11[i]);
}
else
{
write_com(0x80);
for(i=0;i<6;i++)
write_date(table8[i]);
if(k3/100==0)write_date(' ');
else write_date(table[k3/100]);
write_date(table[k3%100/10]);
write_date('.');
write_date(table[k3%10]);
for(i=0;i<8;i++)
write_date(' ');
write_com(0xc0);
for(i=0;i<6;i++)
write_date(table9[i]);
write_date(table[k4/1000]);
write_date(table[k4%1000/100]);
write_date(table[k4%100/10]);
write_date(table[k4%10]);
for(i=0;i<8;i++)
write_date(' ');
}
}
}
- display(): 该函数用于控制LCD显示器显示不同的数据信息,包括温湿度、粉尘浓度、SF6气体浓度、报警阈值等。
12. 按键处理函数
void keys()
{
if(key1==0)
{
while(!key1);
m=!m;
set_fg=0;
}
if(key2==0)
{
while(!key2);
if(m==0)
{
if(set_fg==1)k1++;
if(set_fg==2)k2++;
}
if(m==1)
{
if(set_fg==1)k3++;
if(set_fg==2)k4=k4+100;
}
}
if(key3==0)
{
while(!key3);
if(m==0)
{
if(set_fg==1)k1--;
if(set_fg==2)k2--;
}
if(m==1)
{
if(set_fg==1)k3--;
if(set_fg==2)k4=k4-100;
}
}
if(key4==0)
{
while(!key4);
set_fg++;
if(set_fg>2)set_fg=0;
}
if(k1>50)k1=50;
if(k1<0)k1=0;
if(k2>90)k2=90;
if(k2<0)k2=0;
if(k3>100)k3=100;
if(k3<0)k3=0;
if(k4>2000)k4=2000;
if(k4<0)k4=0;
}
- keys(): 该函数用于处理按键的输入,实现对LCD显示内容的切换和对报警阈值的调节。
13. 环境参数判断函数
void temp()
{
if(th1*10+th2>=k1)
{
led1=0;
relay1=0;
}
else
{
led1=1;
relay1=1;
}
if(rh1*10+rh2>=k2)
{
led2=0;
relay2=0;
}
else
{
led2=1;
relay2=1;
}
if(dust>=k3)
{
led3=0;
relay3=0;
}
else
{
led3=1;
relay3=1;
}
if(sf6>=k4)
{
led4=0;
relay4=0;
}
else
{
led4=1;
relay4=1;
}
if((th1*10+th2<k1)&&(rh1*10+rh2<k2)&&(dust<k3)&&(sf6<k4))sp=1;
else sp=0;
}
- temp(): 该函数用于判断各个环境参数是否超过设定的报警阈值,并控制对应的LED灯和继电器,实现报警功能。
14. 串口初始化函数
void t0_init()
{
TMOD=0x20;
// SCON=0x50;
// PCON=0X80;
TH1=0xfd;
TL1=0xfd; //装入初值
TR1=1;//计时中断允许
SM0=0;
SM1=1;//串行口工作于方式2
ES=1;//串行口中断允许
REN=1;//接收允许
EA=1;// 总中断允许
RI=1;
}
- t0_init(): 该函数用于初始化串口,用于接收来自上位机的控制指令。
15. 串口发送数据函数
void serial()
{
send('T');
send(ByteToStr(th1));
send(ByteToStr(th2));
send('H');
send(ByteToStr(rh1));
send(ByteToStr(rh2));
send('D');
send(ByteToStr(dust/100));
send(ByteToStr(dust%100/10));
send('.');
send(ByteToStr(dust%10));
send('S');
send(ByteToStr(sf6/1000));
send(ByteToStr(sf6%1000/100));
send(ByteToStr(sf6%100/10));
send(ByteToStr(sf6%10));
send('l');
send(ByteToStr(k1/10));
send(ByteToStr(k1%10));
send('m');
send(ByteToStr(k2/10));
send(ByteToStr(k2%10));
send('n');
send(ByteToStr(k3/100));
send(ByteToStr(k3%100/10));
send('.');
send(ByteToStr(k3%10));
send('o');
send(ByteToStr(k4/1000));
send(ByteToStr(k4%1000/100));
send(ByteToStr(k4%100/10));
send(ByteToStr(k4%10));
}
- serial(): 该函数用于通过串口发送各种数据信息,包括温湿度、粉尘浓度、SF6气体浓度和报警阈值等。
16. 串口中断函数
void serial_INT() interrupt 4
{
unsigned char c;
if(RI)
ES=0;
RI=0;
c=SBUF;
if(c=='1')
{
m=!m;
set_fg=0;
}
if(c=='+')
{
if(m==0)
{
if(set_fg==1)k1++;
if(set_fg==2)k2++;
}
if(m==1)
{
if(set_fg==1)k3++;
if(set_fg==2)k4=k4+100;
}
}
if(c=='-')
{
if(m==0)
{
if(set_fg==1)k1--;
if(set_fg==2)k2--;
}
if(m==1)
{
if(set_fg==1)k3--;
if(set_fg==2)k4=k4-100;
}
}
if(c=='2')
{
set_fg++;
if(set_fg>2)set_fg=0;
}
ES=1;
}
- serial_INT(): 该函数用于处理串口中断,接收来自上位机的控制指令,并对相应的参数进行调整。
17. 主函数
void main()
{
t0_init();
init();
while(1)
{
serial();
write_byte1();
DHT11_5();
keys();
display();
volt_result();
temp();
}
}
- main(): 该函数是程序的入口,用于初始化相关硬件和软件,并进入循环,不断地读取传感器数据、处理按键输入、更新LCD显示、发送数据到上位机等。
原文地址: https://www.cveoy.top/t/topic/nDeu 著作权归作者所有。请勿转载和采集!