单片机+温度检测+空气检测+PM2.5检测

基于51单片机的空气质量监测系统
原理图:

程序如下:
#include <reg52.h>
#include <intrins.h>
#include <absacc.h>
#include <math.h>
#include "0832.h"

#define uchar unsigned char
#define uint unsigned int

//定义LCD1602端口
sbit E=P2^6;                //1602使能引脚
sbit RS=P2^7;                //1602数据/命令选择引脚
sbit RW=P2^5;

sbit LED_RED=P2^2;
sbit LED_YELLOW=P2^1;
sbit LED_GREEN=P2^0;

sbit SET_KEY=P3^4;
sbit ADD_KEY=P3^5;
sbit SUB_KEY=P3^6;

sbit BUZZ=P3^7;
sbit jdq=P2^4;

volatile unsigned char BEEP_Cnt = 0;
                       
unsigned char PM_Waring = 50;
unsigned char Temp_Waring = 20;
unsigned char Smok_Waring = 50;

unsigned char Smok_Value = 125;

unsigned char PM_Waring;
unsigned char PM_Value;

bit FlagStartRH=0;
bit flag_BJ=0;

unsigned char a1,a2,a3;

extern volatile unsigned char KEY_Value;
#define KEY_NOP         0
#define KEY_SET                     1
#define KEY_UP                      2
#define KEY_DOWN                           3

void Delay_1ms(unsigned int n)                //@11.0592MHz
{
       
        unsigned char i, j;
        while(n--)
        {
                _nop_();
                i = 2;
                j = 199;
                do
                {
                        while (--j);
                } while (--i);
        }
}

volatile unsigned char KEY_Value = KEY_NOP;

void Key_Scan(void)        //按键检测
{
       
        static volatile unsigned char Trg = 0;
        static volatile unsigned char Cnt = 0;
        unsigned char KeyRead = 0;
       
        KeyRead = ((P3>>4) & 0X07) ^ 0X07;
        Trg = KeyRead ^ (KeyRead & Cnt);
  Cnt =        KeyRead;
       
        if(Trg)
        {
                switch(Trg)
                {
                        case 0x01: KEY_Value = KEY_SET; break;
                        case 0x02: KEY_Value = KEY_UP; break;
                        case 0x04: KEY_Value = KEY_DOWN; break;
                       
                        default:   KEY_Value = KEY_NOP;break;

}
               
               
        }
       
}

unsigned char Temp_Value = 0; //温度

/*********************************端口定义**********************************/
sbit DQ=P1^6;                                   //数据传输线接单片机的相应的引脚

/*********************************定义全局变量******************************/
bit TemperatureLessZero;
unsigned int Temperature = 850;           //温度值(整型变量)182表示18.2C
/****************************************************************************
函数功能:延时子程序
入口参数:k
出口参数:
****************************************************************************/
void DS18_delay(unsigned char useconds)                  //延迟17US.根据晶振调节
{
        unsigned char i;
        while(--useconds)
        {
                i = 3;
                while (--i);
        }
}

/***************************************************************************
函数功能:DS18B20初始化子程序
入口参数:
出口参数:
****************************************************************************/
unsigned char Init_DS18B20(void)
{
        unsigned char x=0;

DQ=0;                             //发送复位脉冲
          DS18_delay(29);                         //延时(>480us)
          DQ=1;                                  //拉高数据线
          DS18_delay(3);                       //等待(15~60us) 等待存在脉冲
    x=DQ;  //获得存在信号(用于判断是否有器件)
    DS18_delay(25);  // 等待时间隙结束
    return(x);  //返回存在信号,0 = 器件存在, 1 = 无器件
}

/****************************************************************************
函数功能:向DS18B20读一字节数据
入口参数:
出口参数:dat
****************************************************************************/
ReadOneChar(void)                         
{
        unsigned char i=0;                
        unsigned char dat=0;
    for (i=8;i>0;i--)                 
                {
                        DQ=1;
                           DS18_delay(1);
                    DQ=0;      
                    dat>>=1;//复合赋值运算,等效dat=dat>>1(dat=dat右移一位后的值)
                           DQ=1;
                    if(DQ)
                           dat|=0x80;
                    DS18_delay(4);
                }
    return(dat);
}

/****************************************************************************
函数功能:向DS18B20写一字节数据
入口参数:dat
出口参数:
****************************************************************************/
void WriteOneChar(unsigned char dat)//有参函数,功能是"写",而写的内容就是括号内的参数
{
        unsigned char i=0;                
        for(i=8;i>0;i--)         
        {
                DQ=0;           
                DQ=dat&0x01;
                DS18_delay(4);
                DQ=1;
                dat>>=1;//复合赋值运算,等效dat=dat>>1(dat=dat右移一位后的值)
        }
//        DS18_delay(4);
}
                       
/****************************************************************************
函数功能:向DS18B20读温度值
入口参数:
出口参数:temperature
****************************************************************************/
void ReadTemperature(void)
{  
        unsigned char tempL=0;                         //临时变量低位(无符号字符变量)
        unsigned char tempH=0;                        //临时变量高位
        bit flag = 0;
        EA = 0;
        Init_DS18B20();                                 //初始化,调用初始化函数
        WriteOneChar(0xcc);                  //跳过读序列号的操作,调用写函数,写0xcc指令码(跳过读序列号)
        WriteOneChar(0x44);                 //启动温度转换,调用写函数,写0x44指令码(启动温度转换)

//  Time = get_time();
//        DS18_delay(125);                           //转换需要一点时间,延时
        Init_DS18B20();                         //初始化,调用初始化函数
        WriteOneChar(0xcc);                  //跳过读序列号的操作,调用写函数,写0xcc指令码(跳过读序列号?
        WriteOneChar(0xbe);                 //调用写函数,写0xbe指令码,读温度寄存器(头两个值分别为温度的低位和高位)
        tempL=ReadOneChar();                 //读出温度的低位LSB
        tempH=ReadOneChar();                 //读出温度的高位MSB  
        TemperatureLessZero = (bit)(tempH&0x80);
  Temperature=((((tempH&0x7F)<<8)+tempL)*10)>>4;  //温度转换,把高低位做相应的运算转化为实际温度,使用DS18B20温度传感器手册规定的公式,结果是十进制数值
                                                  //这里使用*0.0625,直接增加500+字节代码
       
        EA = 1;
        Temp_Value = Temperature/10;
       
        if(Temp_Value > 125) Temp_Value =125;
        if(TemperatureLessZero)Temp_Value = 0;

//        DS18_delay(20);
//        return(tempa);//运算结果返回到函数 :ReadTemperature()调用时需要采用i=ReadTemperature(),然后再对i(任意uchar型变量)进行操作
}

void L1602_string(uchar hang,uchar lie,uchar *p);

//定时器0初始化
void Timer0_Init()
{
        //AUXR &= 0x7F;                //定时器时钟12T模式
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0xB0;                //设置定时初值
        TH0 = 0x3C;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
        ET0 = 1;
}

bit Time0_300ms_Flag = 1;

//定时器0中断
void Timer0_ISR (void) interrupt 1 using 0
{
        static uchar RHCounter;
        static uchar Time0_300ms_Cnt;
       
        TR0 = 0;
        TL0 = 0xb0;
        TH0 = 0x3c;     //定时器赋予初值
        TR0 = 1;
       
       
        Key_Scan();
       
        if(++Time0_300ms_Cnt>= 6)
        {
                Time0_300ms_Cnt = 0;
                Time0_300ms_Flag = 1;
        }

if(++RHCounter >= 20)
    {
                         RHCounter = 0;
                       
       FlagStartRH = 1;
                       
    }
               
        if(BEEP_Cnt)
        {
                BEEP_Cnt--;
                BUZZ = 0;
        }
        else
        {       
                BUZZ = 1;
        }
}

/********************************************************************
* 文件名  : 液晶1602显示.c
* 描述    :  该程序实现了对液晶1602的控制。
***********************************************************************/

/********************************************************************
* 名称 : delay()
* 功能 : 延时,延时时间大概为140US。
* 输入 : 无
* 输出 : 无
***********************************************************************/

void delay()
{
        int i,j;
        for(i=0; i<=10; i++)
        for(j=0; j<=2; j++);
}

void delay_ms(uint ms)
{
        uint i,j;
        for(i=0;i<ms;i++)
        for(j=0;j<110;j++);
}           
       
/********************************************************************
* 名称 : enable(uchar del)
* 功能 : 1602命令函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/

void enable(uchar del)
{
        P0 = del;
        RS = 0;
        E = 1;
        delay();
        E = 0;
        delay();
}

/********************************************************************
* 名称 : write(uchar del)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
***********************************************************************/

void write(uchar del)
{
        P0 = del;
        RS = 1;
        E = 1;
        delay();
        E = 0;
        delay();
}

/********************************************************************
* 名称 : L1602_init()
* 功能 : 1602初始化,请参考1602的资料
* 输入 : 无
* 输出 : 无
***********************************************************************/
void L1602_init(void)
{
        RW=0;
        enable(0x38);
        enable(0x0c);
        enable(0x06);
        enable(0x01); //清屏要放在最后
        enable(0x80);
        L1602_string(1,1," PM2.5:   0ug/m3");
        enable(0xc0+0x02);
        write(0xdf);
        L1602_string(2,4,"C");
        L1602_string(2,5," Smok:");
}

/********************************************************************
* 名称 : L1602_char(uchar hang,uchar lie,char sign)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下
                 L1602_char(1,5,'b')
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void L1602_char(uchar hang,uchar lie,char sign)
{
        uchar a;
        if(hang == 1) a = 0x80;
        if(hang == 2) a = 0xc0;
        a = a + lie - 1;
        enable(a);
        write(sign);
}

/********************************************************************
* 名称 : L1602_string(uchar hang,uchar lie,uchar *p)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
                  L1602_string(1,5,"ab cd ef;")
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void L1602_string(uchar hang,uchar lie,uchar *p)
{
        uchar a;
        if(hang == 1) a = 0x80;
        if(hang == 2) a = 0xc0;
        a = a + lie - 1;
        enable(a);
        while(1)
        {
                if(*p == '\0') break;
                write(*p);
                p++;
        }
}

void LCD1602_Write_String(bit x,unsigned char y,unsigned char *P)
{
       
        if(x)
        {
                enable(0x80 + 0x40 + y);
        }
        else
        {
                enable(0x80 + y);
        }
       
        while(*P)
        {
                write(*P++);
        }
       
}

void LCD1602_Write_8bit(unsigned int x,unsigned char SIZE)
{
        switch(SIZE)
        {
               
                case 3:
               
                                        write(0x30 + ((x/100)%10));
                                        write(0x30 + ((x/10)%10));
                                        write(0x30 + ((x)%10));
               
                                        break;
                case 4:
                       
                        break;
               
               
                default:  break;
               
        }
}

void display()
{

if(PM_Value%10000/1000!=0)
        L1602_char(1,8,PM_Value%10000/1000+0x30);
        else
        L1602_char(1,8,' ');
        if(PM_Value%10000/100!=0)
        L1602_char(1,9,PM_Value%1000/100+0x30);
        else
        L1602_char(1,9,' ');
        if(PM_Value%10000/10!=0)
        L1602_char(1,10,PM_Value%100/10+0x30);
        else
        L1602_char(1,10,' ');
        L1602_char(1,11,PM_Value%10+0x30);

a1=(Temp_Value/10)%10;
        a3=Temp_Value%10;

L1602_char(2,1,a1+0x30);
        L1602_char(2,2,a3+0x30);
       
       
        L1602_string(2,5," Smok:");
       
        LCD1602_Write_8bit(Smok_Value,3);
       
        BUZZ=1;         //蜂鸣器关
}

void ALARM()
{
       
        if((PM_Value >= PM_Waring)||(Smok_Value >= Smok_Waring)||(Temp_Value >= Temp_Waring))
        {
                BEEP_Cnt = 20;
               
                LED_RED=0;
                LED_YELLOW=1;
                LED_GREEN=1;
                jdq=0;
        }
        else
        {
                if((PM_Value < PM_Waring)  &&  (PM_Value >= PM_Waring/2) && (Smok_Value < Smok_Waring)&& (Temp_Value < Temp_Waring))
                {
                        LED_RED=1;
                        LED_YELLOW=0;
                        LED_GREEN=1;
                        jdq=1;
                }
                else
                {
                        LED_RED=1;
                        LED_YELLOW=1;
                        LED_GREEN=0;
                        jdq=1;
                }

}
}

bit LCD1602_Enable = 1;

volatile unsigned char Menu_States = 0;

void KEY_Processing(void)
{
       
        if(KEY_SET == KEY_Value)       
        {
                KEY_Value = KEY_NOP;

Menu_States = ++Menu_States % 4;
               
                enable(0x01);
                if(Menu_States == 0)
                {
                        L1602_init();
                }       
               
                LCD1602_Enable = 1;
        }
       
       
        if(KEY_UP==KEY_Value)        //下限加
        {
                KEY_Value = KEY_NOP;
                LCD1602_Enable = 1;
                switch(Menu_States)
                {
                        case 1:if(PM_Waring   < 255)PM_Waring++;   enable(0x01);  break;
                        case 2:if(Temp_Waring < 125)Temp_Waring++; enable(0x01); break;
                        case 3:if(Smok_Waring < 100)Smok_Waring++; enable(0x01); break;
                }
        }
       
       
        if(KEY_DOWN ==KEY_Value)        //上限减
        {
                KEY_Value = KEY_NOP;
                LCD1602_Enable = 1;
                switch(Menu_States)
                {
                        case 1:if(PM_Waring   > 0)PM_Waring--;   enable(0x01); break;
                        case 2:if(Temp_Waring > 0)Temp_Waring--; enable(0x01); break;
                        case 3:if(Smok_Waring > 0)Smok_Waring--; enable(0x01); break;
                       
                }
        }

}

void LCD1602_Processing(void)
{
       
        if(Time0_300ms_Flag || LCD1602_Enable)
        {
                Time0_300ms_Flag = 0;
                LCD1602_Enable = 0;
                switch(Menu_States)
                {
                        case 0:
                                                        display();
                                                        break;
                       
                        case 1:
                                                        enable(0x0c);  //不显示光标
                                                        LCD1602_Write_String(0,0,"PM_Waring:");
                       
                                                        enable(0xC0+4);
                                                        LCD1602_Write_8bit(PM_Waring,3);
                               
                                                        enable(0xC0+6);
                                                        enable(0x0F);  //显示光标
                       
                                                break;
                       
                        case 2:
                                                        enable(0x0c);  //不显示光标
                                                        LCD1602_Write_String(0,0,"Temp_Waring:");
                                                        enable(0xC0+4);
                                                        LCD1602_Write_8bit(Temp_Waring,3);
                               
                                                        enable(0xC0+6);
                                                        enable(0x0F);  //显示光标
                       
                                                break;
                       
                        case 3:
                                                        enable(0x0c);  //不显示光标
                                                        LCD1602_Write_String(0,0,"Smok_Waring:");
                       
                                                        enable(0xC0+4);
                                                        LCD1602_Write_8bit(Smok_Waring,3);
                                                        enable(0xC0+6);
                                                        enable(0x0F);  //显示光标
                                                break;
                       
                       
                        default:  break;
                       
                }                       
        }
}

/********************************************************************
* 名称 : Main()
* 功能 : 主函数
***********************************************************************/
void main()
{
        static bit CH;
        Timer0_Init();  //定时器0初始化

L1602_init();
       
        ReadTemperature();
        ReadTemperature();
        Delay_1ms(1000);
        ReadTemperature();
        Delay_1ms(1000);
  ReadTemperature();
        Delay_1ms(1000);
        ReadTemperature();
        Delay_1ms(1000);
        ReadTemperature();
       
        PM_Value = ADC0832_Read(0);
       
        Smok_Value = ADC0832_Read(1)/2.56;
       
        EA = 1;
        while(1)
        {
                if(FlagStartRH )         //温湿度转换标志检查
                {
                        FlagStartRH = 0;
                                 
                        CH = ~CH;
                       
                        if(CH)
                        {
                                PM_Value = ADC0832_Read(0);
                        }
                        else
                        {
                                Smok_Value = ADC0832_Read(1)/2.56;
                        }
               
                        ReadTemperature();

}
               
                LCD1602_Processing();
               
                KEY_Processing();
               
                ALARM();
        }
}

(0)

相关推荐