基于51单片机大气污染检测

功能实现

本次设计的空气质量检测系统主要有以下功能。

(1)单片机上电能够正常启动和复位,按键模块无异常。

(2)按下按键能够进行相应模式的报警阈值调整上限。

(3)能够对空气中PM2.5的浓度、环境温湿度、有害气体浓度进行实时数据采集。

(4)LCD1602可以实时显示检测到的粉尘浓度、温湿度、有害气体浓度的环境参数数值和设定的各项环境参数的报警值。

(5)检测环境参数值超设定值时进行声光报警。

硬件设计

        本次设计采用模块设计,51单片机最小系统模块,1602液晶显示模块,DHT11数字温湿度模块,ADC0832采集模块,PM2.5检测模块和MQ-135气体检测模块,4位独立按键模块,蜂鸣器模块。

软件设计

1602模块软件设计

        本次设计通过1602显示字符函数来显示所有数据。通过ADC0832模块AD采样数据标准转换显示PM2.5模块和MQ-135气体检测模块反馈数据;DHT11数字温湿度模块通过规定的通信协议来进行数据采集;最后通过主函数,来实现按键模块控制实现界面的跳转以及蜂鸣器模块的报警。下面展示的是各模块对应的.C文件。希望能帮到大家!

1.LCD1602.c文件

#include <reg52.h>
#include "LCD1602.H"


/* 等待液晶准备好 */
void LcdWaitReady()
{
    unsigned char sta;

    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;
        sta = LCD1602_DB; //读取状态字
        LCD1602_E = 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_E  = 1;
    LCD1602_E  = 0;
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 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++);
    }
}
/* 初始化1602液晶 */
void InitLcd1602()
{
    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
    LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}

delay.c文件

#include "delay.h"

/*****************************************************************************
延迟函数
/****************************************************************************/
void delay_ms(U16 ms)
{
    U16 i,j;
    for(i=ms;i>0;i--)
        for(j=110;j>0;j--);

}

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能         : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出         : 无
*******************************************************************************/
void delay_10us(U16 ten_us)
{
    while(ten_us--);    
}

 DHT11.c文件

#include "dht11.h"
#include "intrins.h"
#include "DELAY.h"



/************************************

DHT11初始化 

返回0:初始化成功,

返回1:失败
*******************************/
U8 DHT11_Init(void)
{
    DHT11_DQ=1;
    DHT11_Rst();      
    return DHT11_Check();    
}



//复位DHT11
void DHT11_Rst(void)       
{                 
    DHT11_DQ=1;
    delay_10us(1);
    DHT11_DQ=0;     //拉低DQ
    delay_ms(25);   //拉低至少18ms
    DHT11_DQ=1;     //DQ=1 
    delay_10us(3);  //主机拉高20~40us
}

//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
U8 DHT11_Check(void)        
{   
    U8 retry=0;
    
    while (!DHT11_DQ&&retry<100)//判断从机发出 80us 的低电平响应信号是否结束
    {
        retry++;
        _nop_();
    };
    if(retry>=100)return 1;
    else retry=0;
    while (DHT11_DQ&&retry<100)//判断从机发出 80us 的高电平是否结束如结束则主机进入数据接收状态
    {
        retry++;
        _nop_();
    };     
    if(retry>=100)return 1;        
    return 0;
}

//从DHT11读取一个字节
//返回值:读到的数据
U8 DHT11_Read_Byte(void)    
{        
    U8 i,temp;
    U8 data_byte=0; 
    U8 retry=0;

      for(i=0;i<8;i++)//接收8bit的数据 
      { 
//        while(!DHT11_DQ);//等待50us的低电平开始信号结束
        while (!DHT11_DQ&&retry<50)//等待50us的低电平开始信号结束
        {
            retry++;
            _nop_();
        };
        retry=0; 
        delay_10us(2);//等待40us (等待时间已改短)
        temp=0;//时间为26us-28us表示接收的为数据'0' 
        if(DHT11_DQ==1) 
            temp=1; //如果26us-28us之后还为高电平则表示接收的数据为'1' 
//        while(DHT11_DQ);//等待数据信号高电平'0'为26us-28us'1'为70us
        while (DHT11_DQ&&retry<100)//等待数据信号高电平'0'为26us-28us'1'为70us
        {
            retry++;
            _nop_();
        };
        data_byte<<=1;//接收的数据为高位在前右移 
        data_byte|=temp; 
      } 

      return data_byte;
}

//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
U8 DHT11_Read_Data(U8 *temp,U8 *humi)    
{        
     U8 buf[5];
    U8 i;
    DHT11_Rst();
    if(DHT11_Check()==0)
    {
        for(i=0;i<5;i++)//读取40位数据
        {
            buf[i]=DHT11_Read_Byte();
        }
        if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
        {
            *humi=buf[0];
            *temp=buf[2];
        }
        
    }else return 1;
    return 0;        
}

void WSDXS() //温湿度显示
{

        DHT11_Read_Data(&U8T_data_H,&U8RH_data_H);

        str_T[0]=U8T_data_H%100/10+0x30;    // 整数十位
        str_T[1]=U8T_data_H%10+0x30;        // 整数个位
        str_T[2] = '\0';

        str_H[0]=U8RH_data_H%100/10+0x30;   // 整数十位
        str_H[1]=U8RH_data_H%10+0x30;          // 整数个位
        str_H[2]= '\0';
                                
     LcdShowStr(2, 0, str_T);        //显示到液晶屏上
       LcdShowStr(2, 1, str_H);        //显示到液晶屏上
}

 3.ADC0832.c文件

#include "ADC0832.h"
/****************************************************************************
函数功能:ADC0832转换子程序(模块VCC:5V)
入口参数:CH通道选择
出口参数:dat
****************************************************************************/
U8 adc0832(U8 CH)
{
      U8 i,test,adval;
     adval = 0x00;
     test = 0x00;
     Clk = 0;       //初始化
     DATI = 1;
    _nop_();
    CS = 0;
    _nop_();
    Clk = 1;
   _nop_();


   if ( CH == 0x00 )      //通道选择
   {
       Clk = 0;
       DATI = 1;      //通道0的第一位
       _nop_();
      Clk = 1;
        _nop_();
        Clk = 0;
      DATI = 0;      //通道0的第二位
      _nop_();
      Clk = 1;
      _nop_();
    } 
    else
    {
       Clk = 0;
    DATI = 1;      //通道1的第一位
      _nop_();
      Clk = 1;
      _nop_();
      Clk = 0;
      DATI = 1;      //通道1的第二位
    _nop_();
     Clk = 1;
     _nop_();
   }

      Clk = 0;
      DATI = 1;
    for( i = 0;i < 8;i++ )      //读取前8位的值
    {
       _nop_();
       adval <<= 1;
       Clk = 1;
       _nop_();
       Clk = 0;
       if (DATO)
          adval |= 0x01;
      else
          adval |= 0x00;
    }
      for (i = 0; i < 8; i++)      //读取后8位的值
      {
           test >>= 1;
           if (DATO)
              test |= 0x80;
           else 
              test |= 0x00;
          _nop_();
          Clk = 1;
          _nop_();
          Clk = 0;
      }
      if(adval == test) //比较前8位与后8位的值,如果不相同舍去。若一直出现显示为零,请将该行去掉
       dat = test;
       nop_();
       CS = 1;        //释放ADC0832
       DATO = 1;
       Clk = 1;
       return dat;
}

 /* 整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */
U8 IntToString(U8 *str, int dat)
{
    signed char i = 0;
    U8 len = 0;
    U8 buf[6];
    
    if (dat < 0)  //如果为负数,首先
    
    {
        dat = -dat;
        *str++ = '-';
        len++;
    }
    do {          //先转换为低位在前的十进制数组
        buf[i++] = dat % 10;
        dat /= 10;
    } while (dat > 0);
    len += i;     //i最后的值就是有效字符的个数
    while (i-- > 0)   //将数组值转换为ASCII码反向拷贝到接收指针上
    {
        *str++ = buf[i] + '0';
    }

    *str = '\0';  //添加字符串结束符
    
    return len;   //返回字符串长度
}

KEY.C文件

#include "KEY.h"
/**************
按键扫描函数
*************/
void Key_set_scan()
{
          
    if(quxiao==0)
    {
       delay_ms(20);

        if(quxiao==0)
        {
           while(!quxiao);
          qx_flag =~ qx_flag;
        }
    }  
    if(shezhi==0)
    {
       delay_ms(20);
        if(shezhi==0)
        {  
           while(!shezhi);
           LcdWriteCmd(0x01);  //清屏
           LcdWriteCmd(0x01);  //清屏
           moshi++;
           if(moshi >= 5)moshi = 0;
           if(moshi == 0)
           { 
             LcdWriteCmd(0x01);  //清屏
             delay_ms(10);
                 LcdShowStr(0, 0,"T:  C");
             LcdShowStr(0, 1,"H:  %RH ");
             LcdShowStr(6, 0,"P:   ug/m3");
             LcdShowStr(8, 1,"C:   ppm");
           }
           else if(moshi == 1)
           {  
              LcdWriteCmd(0x01);LcdWriteCmd(0x01);LcdWriteCmd(0x01);  //清屏
              LcdWriteCmd(0x01);LcdWriteCmd(0x01);LcdWriteCmd(0x01);
              LcdShowStr(0, 1,"Set_T:   C      ");
           }
           else if(moshi == 2)
           {  LcdWriteCmd(0x01);  //清屏
              delay_ms(10);
              LcdShowStr(0, 0,"                ");
                 LcdShowStr(0, 1,"Set_H:   %RH    ");
           }
           else if(moshi == 3)
           {    LcdWriteCmd(0x01);  //清屏
                delay_ms(10);
               LcdShowStr(0, 0,"                ");
                  LcdShowStr(0, 1,"Set_P:    ug/m3 ");
           }
           else if(moshi == 4)
           {   LcdWriteCmd(0x01);  //清屏
               delay_ms(10);
               LcdShowStr(0, 0,"                ");
                  LcdShowStr(0, 1,"Set_C:    ppm   ");
           }
                          
        }
    }
    
    if(jia==0)
    {
       delay_ms(100);
        if(jia==0)
        {     
            if(moshi==1)
            {
             T_baojing++ ;
             if( T_baojing>=99 )T_baojing =99;
            }
            if(moshi==2)
            {
             H_baojing++ ;
             if( H_baojing>=99 )H_baojing =99;
            }
            if(moshi==3)
            {
             P_baojing++ ;
             if( P_baojing>=999 )P_baojing =999;
            }

            if(moshi==4)
            {
             C_baojing++ ;
             if( C_baojing>=999 )C_baojing =999;
            }

            
            
        
         }
     }
     if(jian == 0)
     {
        delay_ms(100);
       if(jian == 0)
       {
            if(moshi==1)
            {
             T_baojing-- ;
             if( T_baojing<=0 )T_baojing =0;
            }
            if(moshi==2)
            {
             H_baojing-- ;
             if( H_baojing<=0 )H_baojing =0;
            }
            if(moshi==3)
            {
             P_baojing-- ;
             if( P_baojing<=0 )P_baojing =0;
            }
            if(moshi==4)
            {
             C_baojing-- ;
             if( C_baojing<=0 )C_baojing =0;
            }
       }
     }
         
}

定时器配置,开启定时器,用于PM2.5模块中LED输入脉冲引脚

time.c文件

#include "time.h"

/*------------------------------------------------
                    定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
 TMOD |= 0x01;      //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响             
 TH0=(65536-3000)/256;          //重新赋值 30ms
 TL0=(65536-3000)%256;
 EA=1;            //总中断打开
 ET0=1;           //定时器中断打开
 TR0=1;           //定时器开关打开
 PT0=1;           //优先级打开
}

/*------------------------------------------------
    定时器中断子程序(定时1ms)
------------------------------------------------*/
void Timer0_isr(void) interrupt 1 
{
   TH0=(65536-3000)/256;     //重新赋值 10ms
   TL0=(65536-3000)%256;
    PM_LED=~PM_LED;//通过取反产生脉冲
     
}

最后就是main函数整体编译

main.c

#include <reg52.h>
#include <intrins.h>
#include "DHT11.h"
#include "KEY.h"
#include "LCD1602.h"
#include "ADC0832.h"
#include "time.h"

U8 str_T[6];         //温度值
U8 str_H[8];        //湿度值
U8 str_pm[5];        //pm2.5值
U8 str_co[5];        //有害气体浓度值

U8 T_baojing = 40;  //温度报警值
U8 H_baojing = 80;    //湿度报警值
U16 P_baojing = 80;    //PM2.5报警值
U16 C_baojing = 100;//有害气体报警值

U8 T_buff[3];        //报警缓存
U8 H_buff[3];        //报警缓存
U8 P_buff[4];        //报警缓存
U8 C_buff[4];        //报警缓存

U8 moshi=0;            //模式0~4
U8 data1;
float Value1,Value2; //AD采集转换后变量
U8 dat = 0x00;            //AD值
bit qx_flag = 1;                //报警开关 默认开

sbit  LED_H  = P1^4;//   温湿度报警指示灯
sbit  LED_P  = P1^5;//   PM2.5报警指示灯
sbit  LED_C  = P1^6;//           CO报警指示灯

sbit  BUZZER = P2^2;//        蜂鸣器信号脚
sbit  fengshan = P2^5;//        风扇信号脚


unsigned int sum=0;
U8  U8FLAG,k;
U8  U8count,U8temp;
U8     U8comdata;

U8 U8T_data_H=0;//温度值
U8 U8RH_data_H=0;//湿度值


/************主函数****************/
void main()
{        
       U16 len;//长度
       U8 m;
    
        Init_Timer0();    //定时器初始化
      InitLcd1602();     //初始化液晶
    
  while(DHT11_Init())    //检测DHT11是否存在
    {
            LcdShowStr(0,0,"Error");//显示提示报错信息
    }

    //显示提示字符信息
    LcdShowStr(0, 0,"T:  C");
    LcdShowStr(0, 1,"H:  %RH");
    LcdShowStr(6, 0,"P:   ug/m3");
    LcdShowStr(8, 1,"C:   ppm");
  while(1)
 {    
   Key_set_scan();//按键扫描
     if(moshi == 0)      //设置模式切换
 {
     
       WSDXS(); //温湿度显示

     for(m=0;m<50;m++)
    {
        Value1 = adc0832(0); //PM2.5检测
        delay_ms(4);
        sum=sum+Value1;
    }

    Value1=sum/50;
        sum=0; 
   Value1 =  Value1*(float)(Value1/5);//浓度校准
   if(Value1>999)Value1=999;

   len = IntToString(str_pm,Value1); //转换成字符串

    while (len < 3)                  //用空格补齐到5个字符长度
    {
        str_pm[len++] = ' ';
    }
            str_pm[len] = '\0';              //添加字符串结束符
            LcdShowStr(8, 0, str_pm); //烟雾浓度显示到液晶屏上  
  
            Value2 =  adc0832(1);   //CO检测
            Value2 =  (float)(Value2*1.5);//浓度校准
   len = IntToString(str_co,Value2); //转换成字符串
    while (len < 3)               //用空格补齐到3个字符长度
    {
        str_co[len++] = ' ';
    }
     str_co[len] = '\0';              //添加字符串结束符
        
   LcdShowStr(10, 1, str_co); //烟雾浓度显示到液晶屏上  
    
    if(qx_flag == 1)  //按键触发
   {
           if((U8T_data_H>T_baojing)||(U8RH_data_H>H_baojing)||(Value1>=P_baojing)||(Value2>=C_baojing)) 
           {BUZZER = 1;fengshan = 0;}
        else{BUZZER = 0;fengshan = 1;}
    }
   else {BUZZER = 0;fengshan = 1;}
   //if(U8T_data_H>T_baojing)  LED_T = 0;   else  LED_T = 1;    
   if((U8RH_data_H>H_baojing)||(U8T_data_H>T_baojing)) LED_H = 0;   else  LED_H = 1;  
   if(Value1>=P_baojing)     LED_P = 0;   else  LED_P = 1;    
   if(Value2>=C_baojing)     LED_C = 0;   else  LED_C = 1;    
  }
   else if(moshi == 1)    //设置温度上限模式
   {    
   T_buff[0] = T_baojing/10+0x30;
   T_buff[1] = T_baojing%10+0x30;
   T_buff[2] = '\0';
   LcdShowStr(6, 1,T_buff);
   }
   else if(moshi == 2)      //设置湿度上限模式
   {
   H_buff[0] = H_baojing/10+0x30;
   H_buff[1] = H_baojing%10+0x30;
   H_buff[2] = '\0';
   LcdShowStr(6, 1,H_buff);
   }
   else if(moshi == 3)     //设置PM2.5浓度上限模式
   {
   P_buff[0] = P_baojing/100+0x30;
   P_buff[1] = P_baojing%100/10+0x30;
   P_buff[2] = P_baojing%10+0x30;
   P_buff[3] = '\0';
   LcdShowStr(6, 1,P_buff);
   }
   else if(moshi == 4)     //设置CO浓度上限模式
   {
   C_buff[0] = C_baojing/100+0x30;
   C_buff[1] = C_baojing%100/10+0x30;
   C_buff[2] = C_baojing%10+0x30;
   C_buff[3] = '\0';
   LcdShowStr(6, 1,C_buff);
   }                                                                           
 }
}

        本次设计经过实物验证,功能正常实现,该次设计用于毕业设计,若有不足,希望指正交流学习。 

        下面是百度网盘资料分享下载链接:

提取码:52dqhttps://pan.baidu.com/s/1lxRK0Fbou0g55sJGVMDAdA

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值