现在空气污染很严重,尤其是北方地区,所以某一个宝买了一套PM2.5、光照、温湿度及时间一体的散件,自己做了成品。
时钟芯片DS1302,精度一般般,准备换DS3231了。
温湿度芯片DHT11,这个精度更差,准备换DHT22
光照芯片BH1750FVI。
单片机89C52
屏幕是串口并口通用的12864屏
PM2.5检测原理图:
单片机源程序:
- #include <reg52.h>
- #include <intrins.h>
- #include "12864.h"
- #include "ds1302.h"
- typedef unsigned char BYTE;
- typedef unsigned short WORD;
- uint wendu=0; //温度变量
- uint shidu=0; //湿度变量
- uint pm25=0; //pm2.5变量
- uint stwendu=30; //温度报警变量
- uint stguang=100; //光照报警变量
- uint stpm25=100; //pm2.5报警变量
- uchar hor,min,sec; //时分秒
- uchar initial_time[]={0x00,0x00,0x00}; //时分秒设定
- unsigned int guangzhao=0; //光照变量
- float xdata guang=0; //光照变量
- sbit DQ=P1^0; //DHT11 单片机引脚
- sbit SCL=P2^0; //IIC时钟引脚定义 读取光照用
- sbit SDA=P2^1; //IIC数据引脚定义
- sbit k1=P3^2; //+ 按键
- sbit k2=P3^3; //-
- sbit k3=P3^4; //设置
- sbit led1=P1^5; //wendu baojing
- sbit led2=P1^6; // guangzhao baojing
- sbit led3=P1^7; //pm2.5baojing
- sbit fmq=P0^0; //pm2.5baojing
- uchar BUF[8]; //接收数据缓存区
- unsigned char xdata dat[6]; //串口变量 用于读取pm2.5
- unsigned char k=0;
- unsigned char flagcom=0;
- unsigned char xdata ge,shi,bai,qian,wan; //显示变量
- #define SlaveAddress 0x46 //定义器件在IIC总线中的从地址,根据ALT ADDRESS地址引脚不同修改
- //ALT ADDRESS引脚接地时地址为0x46,接电源时地址为0x3A
- //*****************************************长延时*****************************************
- void Delay(unsigned int s)
- {
- unsigned int i;
- for(i=0; i<s; i++);
- for(i=0; i<s; i++);
- }
- void Delay5us()
- {
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- }
- void Delay5ms()
- {
- WORD n = 560;
- while (n--);
- }
- //**************************延时函数
- void delay_ms(unsigned int k)
- {
- unsigned int i,j;
- for(i=0;i<k;i++)
- {
- for(j=0;j<121;j++)
- {;}}
- }
- //温湿度读取
- //初始化DTH11
- bit Init_DTH11()
- {
- bit flag;
- uchar num;
- DQ=0;
- delay_ms(20); // >18ms
- DQ=1;
- for(num=0;num<10;num++); // 20-40us 34.7us
- for(num=0;num<12;num++);
- flag=DQ;
- for(num=0;num<11;num++); //DTH响应80us
- for(num=0;num<24;num++); //DTH拉高80us
- return flag;
- }
- //****************************读DTH11数据
- uchar DTH11_RD_CHAR()
- {
- uchar byte=0;
- uchar num;
- uchar num1;
- while(DQ==1);
- for(num1=0;num1<8;num1++)
- {
- while(DQ==0);
- byte<<=1; //高位在前
- for(num=0;DQ==1;num++);
- if(num<10)
- byte|=0x00;
- else
- byte|=0x01;
- }
- return byte;
- }
- //******************************读取DTH11温度和湿度
- void DTH11_DUSHU()
- {
- uchar num;
- if(Init_DTH11()==0)
- {
- shidu=DTH11_RD_CHAR(); //
- DTH11_RD_CHAR();
- wendu=DTH11_RD_CHAR();
- // tem=30;
- DTH11_RD_CHAR();
- DTH11_RD_CHAR();
- for(num=0;num<17;num++); //最后BIT输出后拉低总线50us
- DQ=1;
- }
- }
- //********************************iic 光照///////////////////////////////////////////
- //***************************************************************************************
- /**************************************
- 起始信号
- **************************************/
- void BH1750_Start()
- {
- SDA = 1; //拉高数据线
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SDA = 0; //产生下降沿
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- }
- /**************************************
- 停止信号
- **************************************/
- void BH1750_Stop()
- {
- SDA = 0; //拉低数据线
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SDA = 1; //产生上升沿
- Delay5us(); //延时
- }
- /**************************************
- 发送应答信号
- 入口参数:ack (0:ACK 1:NAK)
- **************************************/
- void BH1750_SendACK(bit ack)
- {
- SDA = ack; //写应答信号
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- /**************************************
- 接收应答信号
- **************************************/
- bit BH1750_RecvACK()
- {
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- CY = SDA; //读应答信号
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- return CY;
- }
- /**************************************
- 向IIC总线发送一个字节数据
- **************************************/
- void BH1750_SendByte(BYTE dat)
- {
- BYTE i;
- for (i=0; i<8; i++) //8位计数器
- {
- dat <<= 1; //移出数据的最高位
- SDA = CY; //送数据口
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- BH1750_RecvACK();
- }
- /**************************************
- 从IIC总线接收一个字节数据
- **************************************/
- BYTE BH1750_RecvByte()
- {
- BYTE i;
- BYTE dat = 0;
- SDA = 1; //使能内部上拉,准备读取数据,
- for (i=0; i<8; i++) //8位计数器
- {
- dat <<= 1;
- SCL = 1; //拉高时钟线
- Delay5us(); //延时
- dat |= SDA; //读数据
- SCL = 0; //拉低时钟线
- Delay5us(); //延时
- }
- return dat;
- }
- //*********************************
- void Single_Write_BH1750(uchar REG_Address)
- {
- BH1750_Start(); //起始信号
- BH1750_SendByte(SlaveAddress); //发送设备地址+写信号
- BH1750_SendByte(REG_Address); //内部寄存器地址,请参考中文pdf22页
- // BH1750_SendByte(REG_data); //内部寄存器数据,请参考中文pdf22页
- BH1750_Stop(); //发送停止信号
- }
- //********单字节读取*****************************************
- /*
- uchar Single_Read_BH1750(uchar REG_Address)
- { uchar REG_data;
- BH1750_Start(); //起始信号
- BH1750_SendByte(SlaveAddress); //发送设备地址+写信号
- BH1750_SendByte(REG_Address); //发送存储单元地址,从0开始
- BH1750_Start(); //起始信号
- BH1750_SendByte(SlaveAddress+1); //发送设备地址+读信号
- REG_data=BH1750_RecvByte(); //读出寄存器数据
- BH1750_SendACK(1);
- BH1750_Stop(); //停止信号
- return REG_data;
- }
- */
- //*********************************************************
- //
- //连续读出BH1750内部数据
- //
- //*********************************************************
- void Multiple_read_BH1750(void)
- { uchar i;
- BH1750_Start(); //起始信号
- BH1750_SendByte(SlaveAddress+1); //发送设备地址+读信号
-
- for (i=0; i<3; i++) //连续读取6个地址数据,存储中BUF
- {
- BUF[i] = BH1750_RecvByte(); //BUF[0]存储0x32地址中的数据
- if (i == 3)
- {
- BH1750_SendACK(1); //最后一个数据需要回NOACK
- }
- else
- {
- BH1750_SendACK(0); //回应ACK
- }
- }
- BH1750_Stop(); //停止信号
- Delay5ms();
- }
- //初始化BH1750,根据需要请参考pdf进行修改****
- void Init_BH1750()
- {
- Single_Write_BH1750(0x01);
- }
- void conversion(unsigned int temp_data) // 数据转换出 个,十,百,千,万
- {
- wan=temp_data/10000 ;
- qian=temp_data%10000/1000;
- bai=temp_data%1000/100;
- shi= temp_data%100/10;
- ge= temp_data%10;
- }
- /********************************************************************
- du1302 读取时间
- ***********************************************************************/
- void du_ds1302()
- {
- uchar k;
-
- // uchar taddr = 0x81;
- // for (k=0; k<3; k++)
- // {
- // now_time[k] = read_data_ds1302(taddr);/*格式为: 秒 分 时 日 月 星期 年 */
- // taddr+= 2;
- // }
- k= read_data_ds1302(0x81);
- k=bcd16(k);
- if(k<60) sec=k;
- if(k>=60){write_data_ds1302(0x8e,0x00); write_data_ds1302(0x80,0);write_data_ds1302(0x8e,0x80); }
- k= read_data_ds1302(0x83);
- k=bcd16(k);
- if(k<60)min=k;
- k=read_data_ds1302(0x85);
- k=bcd16(k);
- if(k<24) hor=k;
- }
- void xianshishijian() //显示时间
- {
-
- LCD_Setaddress(1,1);
- print("时间");
- LCD_write_dat(':');
- LCD_write_dat(hor/10+0x30);
- LCD_write_dat(hor%10+0x30);
- LCD_write_dat('-');
- LCD_write_dat(min/10+0x30);
- LCD_write_dat(min%10+0x30);
- LCD_write_dat('-');
- LCD_write_dat(sec/10+0x30);
- LCD_write_dat(sec%10+0x30);
-
- }
- xianshiwsd()//显示温湿度
- {
- LCD_Setaddress(2,1);
- //if(wendu>=99)wendu=99;
- print("温度");
- LCD_write_dat(':');
- LCD_write_dat(wendu/10+0x30);
- LCD_write_dat(wendu%10+0x30);
- LCD_write_dat(' ');
- LCD_Setaddress(2,5);
- print("湿度");
- LCD_write_dat(':');
- LCD_write_dat(shidu/10+0x30);
- LCD_write_dat(shidu%10+0x30);
- LCD_write_dat('%');
- // LCD_write_dat(' ');
- }
- void xianshipm() //显示pm2.5
- {
- if(pm25>=999)pm25=999;
- LCD_Setaddress(3,1);
- print("PM2.5");
- LCD_write_dat(':');
- LCD_write_dat(pm25/100+0x30);
- LCD_write_dat(pm25%100/10+0x30);
- LCD_write_dat(pm25%10+0x30);
- LCD_write_dat('u');
- LCD_write_dat('g');
- LCD_write_dat('/');
- LCD_write_dat('m');
- LCD_write_dat('3');
- LCD_write_dat(' ');
- LCD_write_dat(' ');
- }
- void xianshiguangzhao() //显示光照
- {
- LCD_Setaddress(4,1);
- print("光照");
- LCD_write_dat(':');
- LCD_write_dat(wan+0x30);
- LCD_write_dat(qian+0x30);
- LCD_write_dat(bai+0x30);
- LCD_write_dat(shi+0x30);
- LCD_write_dat(ge+0x30);
- LCD_write_dat(' ');
- LCD_write_dat('L');
- LCD_write_dat('X');
- }
- void baojing()
- {
- if(wendu>stwendu) led1=0;
- else led1=1;
- if(guang<stguang) led2=0;
- else led2=1;
- if(pm25>stpm25)
- {
- led3=0;
- fmq=0;
-
-
- }
- else
- {
- led3=1;
- fmq=1;
- }
- }
- //////////////////////串口、、、、、、、、、、、、、用来读取 pm2.5/////////////////////////////////////////////////
- void UartInit(void) //2400bps@11.0592MHz
- {
- SCON = 0x50; //8-bit variable UART
- PCON=0X00;
- TMOD = 0x20; //Set Timer1 as 8-bit auto reload mode
- TH1 = TL1 = 0XF4; //Set auto-reload vaule
- TR1 = 1; //Timer1 start run
- ES = 0; //Enable UART interrupt
- EA = 0; //Open master interrupt switch
- }
- void SendByte(unsigned char dat)
- {
- SBUF = dat;
- while(!TI);
- TI = 0;
- }
- void UART_SER (void) interrupt 4
- {
-
- uint aa;
- if (RI)
- {
- RI = 0; //Clear receive interrupt flag
-
- dat[k]= SBUF; //P0 show UART data
- if(dat[0]!=0xaa) k=0;
- else k++;
- if((dat[0]==0xaa)&&(k>5)) //读取pm2.5数据
- {
-
- ES=0;
- EA=0;
- aa=dat[1]*255+dat[2];
- if(aa!=0) pm25=aa;
- flagcom=0;
- Delay(2000);
-
- k=0;
- }
- }
- if (TI)
- {
- TI = 0; //Clear transmit interrupt flag
- }
- }
- //************************************主函数************************************************************
- void main(void)
- {
- uint flaga=0; //pm2.5传感器 串口无法读取时正常显示其它数据标志
- unsigned char aa; //按键切换标志
- //上电延时
- Delay(6000); //初始化时钟
- init_ds1302(); //时钟初始化
- LCD_draw_clr(); //屏幕复位
- k1=1; //按键引脚拉高
- k2=1;
- k3=1;
- Init_BH1750(); //初始化BH1750
- flagcom=0; //串口中断 标志
- UartInit() ;
- aa=0;
- while(1)
- {
-
- if(k3==0) //设置按键计数
- {
- Delay(10000);
- if(k3==0)
- {
-
- aa++;
- Delay(2000);
- }
-
- }
- if((flagcom==0)&(aa==0)) //循环读取数据 flagcom 串口中断标志 aa按键标志
- {
- Delay(500);
- du_ds1302() ; //读取1302时间
- Delay(500);
- xianshishijian(); //显示时间
-
-
- Delay(2000);
- DTH11_DUSHU(); //温度湿度读取
- Delay(100);
-
- xianshiwsd(); // 显示温度湿度
- Delay(1000);
- xianshipm(); //显示pm2.5
- Delay(1000);
- Single_Write_BH1750(0x01); // 读取 光照
- Single_Write_BH1750(0x10); // H- resolution mode
- Delay(180); //延时
- Multiple_Read_BH1750(); //连续读出数据,存储在BUF中
- guangzhao=BUF[0];
- guangzhao=(guangzhao<<8)+BUF[1];//合成数据
- guang=(float)guangzhao/1.2;
- conversion(guang) ;
- xianshiguangzhao(); //显示光照
- baojing(); //报警函数
-
- Delay(500);
- flaga=0;
- flagcom=1;
- ES=1;
- EA=1;
- Delay(500);
- }
- Delay(500);
- flaga++;
- if(flaga>=10)
- {
- flagcom=0;
- flaga=0;
-
- }
- //设置baojingzhi
-
-
- if(aa>5) aa=0;
- if(aa==1)
- {
- Delay(5000) ;
- LCD_Setaddress(1,1);
- print(" 设置 ");
- LCD_Setaddress(2,1);
- print("温度报警:");
-
- conversion(stwendu);
-
- LCD_write_dat(shi+0x30);
- LCD_write_dat(ge+0x30);
- LCD_write_dat(' ');
- LCD_write_dat(' ');
- LCD_write_dat(' ');
- LCD_write_dat(' ');
- LCD_write_dat(' ');
- LCD_Setaddress(3,1);
- print(" ");
- LCD_Setaddress(4,1);
- print(" ");
- if(k1==0)
- { Delay(500) ;
- if(k1==0)
- {
- stwendu++;
- }
- }
- if(k2==0)
- { Delay(500) ;
- if(k2==0)
- {
- stwendu--;
- }
- }
-
- }
- if(aa==2)
- {
- LCD_Setaddress(1,1);
- print(" 设置 ");
- LCD_Setaddress(2,1);
- print("光照报警:");
-
- conversion(stguang);
- LCD_write_dat(wan+0x30);
- LCD_write_dat(qian+0x30);
- LCD_write_dat(bai+0x30);
- LCD_write_dat(shi+0x30);
- LCD_write_dat(ge+0x30);
- LCD_write_dat(' ');
- LCD_Setaddress(3,1);
- print(" ");
- LCD_Setaddress(4,1);
- print(" ");
- if(k1==0)
- { Delay(500) ;
- if(k1==0)
- {
- stguang++;
- }
- }
- if(k2==0)
- { Delay(500) ;
- if(k2==0)
- {
- stguang--;
- }
- }
-
- }
- if(aa==3)
- {
- LCD_Setaddress(1,1);
- print(" 设置 ");
- LCD_Setaddress(2,1);
- print("PM2.5 ");
- LCD_Setaddress(2,4);
- print("报警:");
- …………余下代码请下载附件…………
复制代码
原理图等资料:
SHEET1.pdf
(289.29 KB, 下载次数: 151)
|