|
基于51單片機的空氣質量監測系統
原理圖:
G@VDRW@D8~K3P23N@CW2~U0.png (71.04 KB, 下載次數: 92)
下載附件
2021-4-19 21:04 上傳
程序如下:
#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();
}
}
|
|