基于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();
}
} |