大石桥 发表于 2021-6-11 10:24

基于单片机的室内环境监测系统参考例程

#include<reg52.h>
#include<SendDataToPC.h>
#include<AcceptData.h>
#define uint unsigned int
#define uchar unsigned char
#include <math.h>
#define LCD1602_DB P0
uchar   DHT11,RTflag=0;
ucharFLAG;//超时标志位
ucharxdata a;
floatidata set0,set1;
float idataset2,set3;
sbitLCD1602_RS = P2^0;
sbitLCD1602_RW = P2^1;
sbitLCD1602_EN = P2^2;
sbitAlarmSystemVoice = P2^3;
sbitAlarmTemperatureFlag_Light = P2^4;
sbitAlarmCoFlag_Light = P2^5;
sbitAlarmCh2oFlag_Light = P2^6;
sbitALarmSystemLight = P2^7;
sbitAlarmCoFlag_Wind = P1^6;
sbitAlarmCoFlag_Walve = P1^7;
sbit Return = P1^4;
sbit dat=P1^0;
void InitLcd1602();
uchar   table;
uint   xdata wd,sd;
void Delay_t(uint j)
{      uchar i;
          for(;j>0;j--)
          {        
                for(i=0;i<27;i++);       
          }
}
voidDelay_10us(void) //10us延时函数
{
      uchar i;
         i--;
         i--;
         i--;
         i--;
         i--;
         i--;
}

void delay(uint z)//1毫秒延时函数
{
   uint x,y;
   for(x=z;x>0;x--)
    for(y=110;y>0;y--);
}

void lcd_write_com(uchar com) //1602写指令
{
   LCD1602_RS=0;
   LCD1602_RW=0;
   LCD1602_EN=1;
   P0=com;
   delay(1);
   LCD1602_EN=0;

}
void lcd_init()        //1602初始化
{

lcd_write_com(0x38);
delay(1);
lcd_write_com(0x08);
delay(1);
lcd_write_com(0x01);//1602清屏指令
delay(1);
lcd_write_com(0x06);
delay(1);
lcd_write_com(0x0C);
delay(1);

}
void lcd_write_data(uchar date)//1602写数据
{
   LCD1602_RS=1;
   LCD1602_RW=0;
   LCD1602_EN=1;
   P0=date;
   delay(1);
   LCD1602_EN=0;
}
void write_str(uchar x,uchar y,uchar *s)//在任意地址写符号字母或数字
{
          if(y==0)                                                                                  
          lcd_write_com(0x80+x);
          else
          lcd_write_com(0xc0+x);
        while(*s)
        {
           lcd_write_data(*s);
           s++;
        }



}
void write_shu(uchar x,uchar y,uchar num)//数据显示函数
{
          
          uchar s,g;
          if(y==0)
          lcd_write_com(0x80+x);
          else
          lcd_write_com(0xc0+x);
          s=num/10;// 数据分离显示
          lcd_write_data(0x30+s);
          g=num%10;//数据分离显示
          lcd_write_data(0x30+g);





}

ucharwrite_byte1() //读一个字节
{
           uchar i,comdata,temp1;
       for(i=0;i<8;i++)          
          {
                     FLAG=2;       
                   while((!dat)&&FLAG++);//判断数据位是0还是1
                        Delay_10us();
                  Delay_10us();
                        Delay_10us();
                          temp1=0;
             if(dat)temp1=1;        // 如果高电平高过预定0高电平值则数据位为 1
                  FLAG=2;
               while((dat)&&FLAG++);//flag先与后加1 如果dat一直为1   uchar型变量 flag溢出变为0再自加1
                     
                  if(FLAG==1)break;                //超时则跳出for循环       
                          
                     
       
                   comdata<<=1;//左移一位   高位在前低位在后
                      comdata|=temp1;
             }
               return (comdata);
}
void DHT11_5() //读5个字节数据两个字节为温度数据两个字节为湿度数据 最后一个字节为校验
{
          uchar i,temp;
          //主机拉低18ms
       dat=0;
           Delay_t(180);
           dat=1;
       //总线由上拉电阻拉高 主机延时20us
           Delay_10us();
           Delay_10us();
           Delay_10us();
           Delay_10us();
       //主机设为输入 判断从机响应信号
           dat=1;
       //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行          
           if(!dat)               //T !          
           {
                FLAG=2;           //超时标志位
                               
                while((!dat)&&FLAG++);//判断从机是否发出 80us 的低电平响应信号是否结束
                        FLAG=2;
                       
                while((dat)&&FLAG++); //判断从机拉高80us是否结束
                        for(i=0;i<5;i++)//数据接收状态
                        {
                                DHT11=write_byte1();       
                        }               
                        dat=1;        //释放数据总线为下一次读取做好准备
               
                        temp=(DHT11+DHT11+DHT11+DHT11);
                        if(temp==DHT11)        //数据校验        
                        {                     
                                RTflag=1;                  
                        }
                        if(RTflag==1) //如果RTflag=1 说明读取到得数据正确
                   {                       
                                RTflag=0;
                        //        tm=DATARHT/10;
                        //        tm=DATARHT%10;
                        //        tm=DATARHT/10; //湿度
                          
                        //        tm=DATARHT/10;
                        //        tm=DATARHT%10;
                        //        tm=DATARHT/10; //温度       
                          if(DHT11>set1|DHT11<11)
                           {
                           AlarmTemperatureFlag_Light = 0;
                           }
                           else if(        DHT11<set0|DHT11>60)
                           {
                                AlarmTemperatureFlag_Light = 0;
                                   }
                          else        
                          { AlarmTemperatureFlag_Light = 1;
                          }
                                write_str(0,0,"measurement ");//第一行显示湿度
                                write_shu(12,0,DHT11);
                                write_str(14,0,"RH");
                                write_str(0,1,"Temperature ");//第二行为显示温度       
                          write_shu(12,1,DHT11);
                          write_str(14,1,"^C");                               
                   }

                }

}


void DisplayDh11()
{
lcd_init();//1602初始化
delay(500); //等待DHT11温湿度传感器数据稳定开始激活DHT11

while(1)//循环读取并更新数据显示
{

           delay(1000);//等待DHT11温湿度传感器数据稳定开始激活DHT11
           write_byte1();//读一个字节
           DHT11_5(); //读数据
        delay(1000); //延时等待
        break;
}
}

/***DH11显示********************************/
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

void LcdStar_Co()
{
        unsigned char str[] = "Co";
        unsigned char tab[]="Conentration ";
        InitLcd1602();/* 初始化 1602 液晶 */
        LcdShowStr(0, 0, str);
        LcdShowStr(3, 0, tab);
        LcdShowStr(0, 1, "Measure");
        LcdShowStr(13, 1, "ppm");//添加V电压
       
               
}
//CO 检测初始化;
void LcdStar_Ch2o()
{
        unsigned char str[] = "Ch2o";
        unsigned char tab[]="Conentration ";
//        InitLcd1602();/* 初始化 1602 液晶 */
        LcdShowStr(0, 0, str);
        LcdShowStr(4, 0, tab);
        LcdShowStr(0, 1, "Measure");
        LcdShowStr(13, 1, "ppm");//添加V电压
       
               
}
/* 等待液晶准备好 */
void LcdWaitReady()
{
        unsigned char sta;
        LCD1602_DB = 0xFF;
        LCD1602_RS = 0;
        LCD1602_RW = 1;
        do {
                LCD1602_EN = 1;
                sta = LCD1602_DB; //读取状态字
                LCD1602_EN = 0;
        } while (sta & 0x80); //bit7 等于 1 表示液晶正忙,重复检测直到其等于 0 为止
}
/* 向 LCD1602 液晶写入一字节命令, cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
        LcdWaitReady();
        LCD1602_RS = 0;
        LCD1602_RW = 0;
        LCD1602_DB = cmd;
        LCD1602_EN = 1;
        LCD1602_EN = 0;
}
/* 向 LCD1602 液晶写入一字节数据, dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
        LcdWaitReady();
        LCD1602_RS = 1;
        LCD1602_RW = 0;
        LCD1602_DB = dat;
        LCD1602_EN = 1;
        LCD1602_EN = 0;
}
/* 设置显示 RAM 起始地址,亦即光标位置, (x,y)-对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x, unsigned char y)
{
        unsigned char addr;
        if (y == 0) //由输入的屏幕坐标计算显示 RAM 的地址
                addr = 0x00 + x; //第一行字符地址从 0x00 起始
        else
                addr = 0x40 + x; //第二行字符地址从 0x40 起始
        LcdWriteCmd(addr | 0x80); //设置 RAM 地址
}
/* 在液晶上显示字符串, (x,y)-对应屏幕上的起始坐标, str-字符串指针 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
        LcdSetCursor(x, y); //设置起始地址
        while (*str != '\0') //连续写入字符串数据,直到检测到结束符
        {
                LcdWriteDat(*str++); //先取 str 指向的数据,然后 str 自加 1
        }
}
/* 初始化 1602 液晶 */
void InitLcd1602()
{
        LcdWriteCmd(0x38); //16*2 显示, 5*7 点阵, 8 位数据接口
        LcdWriteCmd(0x0C); //显示器开,光标关闭
        LcdWriteCmd(0x06); //文字不动,地址自动+1
        LcdWriteCmd(0x01); //清屏
}
#include <reg52.h>
#include <intrins.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
//ADC0832
sbit CS = P1^1;
sbit CLK = P1^2;
sbit DIO = P1^3;
uchar len;
int channel;
//5位整数,CO浓度显示;
uchar DisplayCo_Buffer;
//2位小数,CH20浓度显示;
uchar DisplayCh2o_Buffer;
//延时
void DelayMS(uint ms)
{
        uchar t;
        while(ms--)
        {
                for(t=0;t<120;t++);
        }
}

//获取AD转换结果
uchar Get_AD_Result(int channel)
{
        uchar i,dat1 = 0,dat2 = 0;
        //起始控制位
        CS = 0;
        CLK = 0;
        DIO = 1;   _nop_(); _nop_();
        CLK = 1;   _nop_(); _nop_();
        //第一个下降沿之前 设DI=1/0       
        //选择单端/差分(SGL/DIF)模式中的单端输入模式
        CLK = 0; DIO=1; _nop_();_nop_();
        CLK = 1; ;      _nop_();_nop_();
        //第二个下降沿之前 设DI=0/1 选择CH0/CH1
        CLK = 0;DIO = channel; _nop_();_nop_();
        CLK = 1;DIO = 1; _nop_();_nop_();
        //第三个下降沿之前 DI=1
        CLK = 0; DIO = 1; _nop_();_nop_();
        //4-11,共8个下降沿读取数据(MSB->LSB)
        for(i=0;i<8;i++)
        {
                CLK = 1;_nop_();_nop_();
                CLK = 0;_nop_();_nop_();
                dat1 = dat1<<1|DIO;
        }
        //11-18 共8个下降沿读取数据(LSB->MSB)
        for(i=0;i<8;i++)
        {
                dat2 = dat2|((uchar)(DIO)<<i);
                CLK = 1;_nop_();_nop_();
                CLK = 0;_nop_();_nop_();
        }
        CS = 1;
        //如果MSB->LSB和LSB->MSB读取数据结果相同,返回读取结果,否者0
        return (dat1==dat2) ? dat1 : 0 ;
        DelayMS(10);       
}

void DispalyCo()
{
        uint Data;
        InitLcd1602(); //LCD初始化
        LcdStar_Co();
        DelayMS(10);
                //获取AD转换值 最大值255对应最高电压5.00V
                //显示三个数 使用500
        channel=0;
        Data = Get_AD_Result(channel)*5/255;
                // 数据分解
        Data = pow(2.718,1.0006*Data)*92.442;
        if(Data>set2)
        {
        AlarmCoFlag_Wind =0;
        AlarmCoFlag_Walve=1;
        }
        else
        {
        AlarmCoFlag_Wind =1;
        AlarmCoFlag_Light=1;
        AlarmCoFlag_Walve=0;
        }
        DelayMS(1000);
        DisplayCo_Buffer= Data /10000%10+'0';
        DisplayCo_Buffer = Data/1000%10+'0';
        DisplayCo_Buffer = Data /100%10+'0';
        DisplayCo_Buffer = Data /10%10+'0';
        DisplayCo_Buffer = Data /1%10+'0';
        LcdShowStr(8, 1,DisplayCo_Buffer);

}

void DisplayCh2o()
{
        uint Data;
        unsigned char str[] = "Ch2o";
        unsigned char tab[]="Conentration ";
        InitLcd1602(); //LCD初始化
        DelayMS(10);
                //获取AD转换值 最大值255对应最高电压5.00V
                //显示三个数 使用500
        channel=1;
        Data = Get_AD_Result(channel)*5/255;
        // 数据分解
        Data = Data*333;
        if (Data>set3)
        {
              AlarmCh2oFlag_Light = 0;;
        }
        else
        {
                AlarmCh2oFlag_Light= 1;
        }       
        DisplayCh2o_Buffer= Data /1000%10+'0';
        DisplayCh2o_Buffer= Data /100%10+'0';
        DisplayCh2o_Buffer = '.';
        DisplayCh2o_Buffer = Data /10%10+'0';
        DisplayCh2o_Buffer = Data %10+'0';
        LcdShowStr(8, 1,DisplayCh2o_Buffer);
        LcdStar_Ch2o();
        DelayMS(1000);
}
void DisplayAir()
{
        InitLcd1602();
        while(1)
        {
                DispalyCo();
                DelayMS(1000);
                DisplayCh2o();
                DelayMS(1000);
                break;
       
       
        }

}
/*************报警*************/
void AlarmInit()
{       

        set0 = 40;   //湿度40%-60%
        set1 = 32;        //温度11-32
        set2 = 2500;
        set3 = 5.71;

}
voidAlarm()
{        int b,c,d,trouble={1,1,1};
        b=AlarmTemperatureFlag_Light;
        c=AlarmCoFlag_Wind;
        d=AlarmCh2oFlag_Light;
        trouble=b;
        trouble=c;
        trouble=d;
        if(trouble&&trouble&&trouble== 1)
        AlarmSystemVoice=1;
        else
        {
        AlarmSystemVoice=0;
        ALarmSystemLight=0;
        if(trouble== 0)                //独立报警提示
        AlarmCoFlag_Light=0;
        if(trouble== 0)
        AlarmCh2oFlag_Light=0;
        AlarmCoFlag_Wind =0;
        }

        }
       
//主函数

void main()
{       
       AlarmInit();
       InitLcd1602();
       DisplayDh11();
       delay(1000);
       DisplayAir();
       Alarm();
       CommSend();
       
       
}
各子程序均有说明,如还有其他问题可回复本帖咨询
页: [1]
查看完整版本: 基于单片机的室内环境监测系统参考例程