#include<reg52.h> //包含單片機寄存器的頭文件
#include <intrins.h> //包含_nop_()函數定義的頭文件
#define uchar unsigned char
#define uint unsigned int
sfr ADC_CONTR=0X0BC; //AD寄存器設置
sfr ADC_RES=0x0BD;
sfr ADC_RESL=0x0BE;
sfr P1ASF=0x09D;
uchar a,q,t;
uchar FlagStart;
uchar VALUE;
uint num,DUST_Value,DUST;
long int s1,d0,b,c,d,biao,biao1,biao2;
uchar code qw[]={1,1,1};
uchar qs[4]={0,0,9,0};
uchar key_buffer[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};//2013-01-03
sbit rs=P2^5; //將rS位定義為P2.5引腳
sbit e=P2^7; //將e位定義為P2.7引腳
sbit rw=P2^6; //將rw位定義為P2.6引腳
sbit k1=P1^4;
sbit k2=P1^5;
sbit k3=P1^6;
sbit k4=P1^7;
sbit D1=P2^1; //正常指示燈(綠燈)
sbit D2=P2^0; //警情指示燈(紅燈)
sbit LED=P1^1; // 傳感器led
sbit beep=P1^3;//蜂鳴器
sbit fuli=P2^2;//負離子發生器
sbit fan=P2^3;//風扇
uchar code tad[]="value:0000ppm";
uchar code tad1[]="Alarm:0760ppm";
uchar ADC_Get[10]={0}; //定義AD采樣數組
uchar str[5]={0};
/*****************************************************
函數功能:延時若干毫秒
入口參數:x
***************************************************/
void delay(uchar x)
{
uint a,b;
for(a=x;a>0;a--)
for(b=100;b>0;b--);
}
/*****************************************************
函數功能:ad數據轉換
***************************************************/
uchar ADC( uchar ch) //ch為幾通道 ,返回結果
{ uchar i;
uint temp1;
P1ASF|=1<<ch;
ADC_CONTR=0x88+ch;
for(i=100;i>0;i--);
while(( ADC_CONTR&0x10)==0);//判斷AD是否轉換完
ADC_CONTR&=~0x10;
temp1=(ADC_RES<<2)+ADC_RESL;
return temp1;
}
/*****************************************************
液晶顯示器LED1602
******************************************************/
void write_date(uchar date)
{
rs=1;
P0=date;
delay(5);
e=1;
delay(5);
e=0;
}
void write_com(uchar com)
{
rs=0;
P0=com;
delay(5);
e=1;
delay(5);
e=0;
}
void init()
{
uchar num;
e=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
for(num=0;num<14;num++)
{
write_date(tad[num]);
delay(2);
}
write_com(0x80+0x40);
for(num=0;num<14;num++)
{
write_date(tad1[num]);
delay(2);
}
}
void write_sfm(uint date)//向1602送顯示
{
uint qian,bai,shi,ge;
bai=date%10000%1000/100;
shi=date%10000%1000%100/10;
ge=date%10000%1000%100%10;
write_com(0x80+6);
write_date(0x30+qian);
write_date(0x30+bai);
write_date(0x30+shi);
write_date(0x30+ge);
}
/*****************************************************
中值濾波/算法:先進行排序,然后將數組的中間值作為當前值返回。*/
uchar Error_Correct(uchar *str,uchar num)
{
unsigned char i=0;
unsigned char j=0;
uchar Temp=0;
//排序
for(i=0;i<num-1;i++)
{
for(j=i+1;j<num;j++)
{
if(str[i]<str[j])
{
Temp=str[i];
str[i]=str[j];
str[j]=Temp;
}
}
}
//去除誤差,取中間值
return str[num/2];
}
/*****************************************************
函數功能:報警子程序
*****************************************************/
void zx()//控制
{
long int sa;
sa=(qs[3]*1000+(qs[2]*100)+(qs[1]*10)+qs[0]); //報警設定值
if(DUST>sa) //煙霧檢測值大于設定值
{
D1=1; //正常指示綠燈滅
D2=0; //報警紅燈亮
fuli=0;
fan=0;
biao2=1;//蜂鳴器報警
}
else
{
D1=0; //正常指示綠燈亮
D2=1; //報警紅燈滅
fuli=1;
fan=1;
biao2=0;
beep=1; //蜂鳴器不響
}
}
/*****************************************************
函數功能:按鍵識別
******************************************************/
void key_scan()//按鍵識別
{
uchar i;
static uchar key_value,key_state=0;
P1=0xf0;//設置P1口高4位為輸入口
if((P1&0xf0)!=0xf0)//有鍵按下
{
delay(2); //延時消抖
key_state =P1&0xf0;
if(key_state!=0xf0) //再判有鍵按下
{
switch(key_state)
{
case 0xe0: //S1按下
key_value=1;
break;
case 0xd0://S2按下
key_value=2;
break;
case 0xb0: //S3按下
key_value=3;
break;
case 0x70: //S4按下
key_value=4;
break;
}
for(i=0;i<7;i++) //按鍵隊列FIFO處理
{
key_buffer[i]=key_buffer[i+1];
}
key_buffer[7]=key_value; //最新按鍵值存入緩沖隊列
}
while((P1&0xf0)!=0xf0); //等待按鍵釋放
}
}
/*****************************************************
函數功能:按鍵處理
******************************************************/
void key_do() // 按鍵處理
{
uchar d,i;
while((key_buffer[0]!=0xff)||(key_buffer[1]!=0xff)||(key_buffer[2]!=0xff)||(key_buffer[3]!=0xff)||(key_buffer[4]!=0xff)||
(key_buffer[5]!=0xff)||(key_buffer[6]!=0xff)||(key_buffer[7]!=0xff))//有鍵按下
{
switch(key_buffer[0])
{
case 1: //S1按下
biao++;
TR0=0;
write_com(0x80+0x40+9);//定位光標閃爍的位置
write_com(0x0f); //打開光標閃爍
if(biao==5)
{
TR0=1;
biao=0;
write_com(0x0f); //打開光標閃爍
}
biao1=0;
break;
case 2://S2按下
if(biao==1)
{
if(biao1==0)
{
write_com(0x80+0x40+9);//定位光標閃爍的位置
write_com(0x0f); //打開光標閃爍
}
d=qs[0];
d++;
if(d==10) d=0;
write_com(0x80+0x40+9);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+9);//重新定位光標閃爍的位置
qs[0]=d;
//biao1=1;
}
if(biao==2)
{
if(biao1==0)
write_com(0x80+0x40+8);//定位光標閃爍的位置
d=qs[1];
d++;
if(d==10) d=0;
write_com(0x80+0x40+8);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+8);//重新定位光標閃爍的位置
qs[1]=d;
//biao1=1;
}
if(biao==3)
{
if(biao1==0)
write_com(0x80+0x40+7);//定位光標閃爍的位置
d=qs[2];
d++;
if(d==10) d=0;
write_com(0x80+0x40+7);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+7);//重新定位光標閃爍的位置
qs[2]=d;
}
if(biao==4)
{
if(biao1==0)
write_com(0x80+0x40+6);//定位光標閃爍的位置
d=qs[3];
d++;
if(d==10) d=0;
write_com(0x80+0x40+6);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+6);//重新定位光標閃爍的位置
qs[3]=d;
}
biao1=1;
break;
case 3: //S3按下
if(biao==1)
{
if(biao1==0)
{
write_com(0x80+0x40+9);//定位光標閃爍的位置
write_com(0x0f); //打開光標閃爍
}
d=qs[0];
d--;
if(d==-1) d=9;
write_com(0x80+0x40+9);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+9);//重新定位光標閃爍的位置
qs[0]=d;
// biao1=1;
}
if(biao==2)
{
if(biao1==0)
write_com(0x80+0x40+8);//定位光標閃爍的位置
d=qs[1];
d--;
if(d==-1) d=9;
write_com(0x80+0x40+8);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+8);//重新定位光標閃爍的位置
qs[1]=d;
}
if(biao==3)
{
if(biao1==0)
write_com(0x80+0x40+7);//定位光標閃爍的位置
d=qs[2];
d--;
if(d==-1) d=9;
write_com(0x80+0x40+7);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+7);//重新定位光標閃爍的位置
qs[2]=d;
}
if(biao==4)
{
if(biao1==0)
write_com(0x80+0x40+6);//定位光標閃爍的位置
d=qs[3];
d--;
if(d==-1) d=9;
write_com(0x80+0x40+6);
write_date(0x30+d);//送顯示
write_com(0x80+0x40+6);//重新定位光標閃爍的位置
qs[3]=d;
}
biao1=1;
break;
case 4: //S4按下
TR0=1;
biao=0;
write_com(0x0c);//關閉光標閃爍
break;
default: break;
}
for(i=0;i<7;i++) //按鍵隊列FIFO處理
{
key_buffer[i]=key_buffer[i+1];
}
key_buffer[7]=0xff; //緩沖隊列單元恢復無鍵按下標志
}
}
void init1()
{
biao=0;
biao1=0;
biao2=0;
beep=1;
rw=0;
FlagStart=0;
DUST_Value=0;
LED=0;
EA=1;
ET0=1;
TMOD = 0x11;
TL0 = (65536-10000)/256; //定時10ms
TH0 = (65536-10000)%256;
TH1=(65536-600000)/256;//重賦初值
TL1=(65535-60000)%256;
ET1=1;
TR1=1;
TR0=1;
D1=0;//綠色燈
D2=1;//紅色燈
init();
}
/**************************************
/*****定時器0中斷服務程序*****/
void Timer0_ISR (void) interrupt 1 using 0
{
uint j;
TL0 = (65536-10000)/256;
TH0 = (65536-10000)%256;
LED=1;
//開啟傳感器的LED
for (j=0;j<222;j++); //0.28ms //延時0.28ms
ADC_Get[num]=ADC(0x00); //開啟ADC采集
num++;
if(num>9)
{
FlagStart=1;
num=0;
TR0 = 0; //先關閉定時器0
EA = 0;
}
// for (j=0;j<25;j++); //采集10次,關閉定時器0,進行數據處理
//for (j=0;j<25;j++);
//關閉傳感器LED
LED=0;
}
/*****************************************************
函數功能:主函數
***************************************************/
main()
{
init1();
while(1)
{
if(FlagStart==1) //10次采集完成
{
DUST=Error_Correct(ADC_Get,10); //求取10次AD采樣的值
DUST_Value=(DUST/1024.0)*5000; //轉化成電壓值MV
DUST_Value=DUST_Value*0.172-100.0; //DUST_Value=((DUST)*38)/4-202;// //固體懸浮顆粒濃度計算 Y=0.172*X-0.0999 X--采樣電壓V
if(DUST_Value<0) DUST_Value=0;
if(DUST_Value>760) DUST_Value=760; //限位
DUST=(uint)DUST_Value; //
write_sfm(DUST);//顯示粉塵濃度值
TL0 = (65536-10000)/256;
TH0 = (65536-10000)%256;
TR0 = 1; //開啟定時器0
EA = 1;
FlagStart=0;
zx();//濃度判斷啟動警報
key_scan();
key_do();
delay(100);
}
}
}
void as() interrupt 3 //定時器T1中斷函數 ,定時啟動數據轉換和AD轉換,并根據情況進行蜂鳴器報警
{
TH1=(65536-50000)/256;//重賦初值
TL1=(65535-50000)%256;
t++; //時間計數加1
if(t==4) //50ms*4=0.2s,0.2s時間到
{ t=0;
if(biao2==1)
beep=!beep; //蜂鳴器報警
}
}
|