#include
#include"intrins.h"
#define uchar unsigned char
#define uint unsigned int
void UART_Send_Byte(unsigned char mydata);
sbit lcdrs=P0^7; //1602液晶的RS脚接在P0.7口上
sbit lcdrw=P0^6; //1602液晶的RW脚接在P0.6口上
sbit lcden=P0^5; //1602液晶的E脚接在P0.5口上
sbit SCL=P1^7; //PCF8591T的 SCL 引脚接于单片机的P1^7引脚上
sbit SDA=P1^6; //PCF8591T的 SDA 引脚接于单片机的P1^6引脚上
sbit beep=P1^0;
sbit ds=P0^1; //温度传感器信号线
sbit dat=P1^5; //湿度
uchar DHT11[5],RTflag=0;
uchar FLAG; //超时标志位
uint temp,num=0;
float f_temp;
uchar code table[]={'0','1','2','3','4','5','6','7','8','9',':','-','B',' ','M','F','S','R','Y','N','\'','C'};
uchar code table1[]={'1','5','7','0','1','7','5','1','1','9','0'};
uchar code table2[]="T:";
uchar code table3[]="H:";
uchar code table4[]="YW:";
unsigned char UART_data; //定义串口接收数据变量
uint count=0; /////////////定时器计数
uchar wendu1,wendu2,yanwu1,yanwu2,yanwu3; ///串口发送温度,光照值暂存
unsigned char ADbuf;//设置8位的寄存器用来暂存A/D转换结果
///////////////////////////////////延时函数//////////////////////////////////////
void delay(uint z)
{
uint i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
void Delay_t(uint j)
{
uchar i;
for(;j>0;j--)
{
for(i=0;i<27;i++);
}
}
///////////////////////////////////10us延时函数///////////////////////////////////
void Delay_10us(void) //10us延时函数
{
uchar i;
i--;
i--;
i--;
i--;
i--;
i--;
}
////////////////////////////////写命令函数///////////////////////////////////
void write_com(uchar com)
{
lcdrs=0;
P2=com; //读命令
delay(1);
lcden=1; //启动脉冲
delay(1);
lcden=0;
}
///////////////////////////////写数据函数////////////////////////////////////
void write_data(uchar date)
{
lcdrs=1;
P2=date; //写命令
delay(1);
lcden=1; //启动脉冲
delay(1);
lcden=0;
}
///////////////////////////////LCD初始化////////////////////////////////////
void init_1602()
{
lcden=0;
write_com(0x38); //设置16*2显示;5*7点阵;8位数据接口
write_com(0x0c); //设置开显示,不显示光标
write_com(0x06); //写一个字符后地址指针自动加1
write_com(0x01); //设置清0,数据指针清零
}
///////////////////////////////////1602数据显示数字函数///////////////////////////////////
void write_shu(uchar x,uchar y,uchar num)
{
uchar s,g;
if(y==0)
write_com(0x80+x);
else
write_com(0xc0+x);
s=num/10;// 数据分离显示
write_data(0x30+s);
g=num%10;//数据分离显示
write_data(0x30+g);
}
///////////////////////////////初始显示////////////////////////////////////
void name()
{
uchar a,b,c;
write_com(0x80+0x00);
for(a=0;a
{
write_data(table2[a]);
delay(1);
}
write_com(0x80+0x08);
for(b=0;b
{
write_data(table3[b]);
delay(1);
}
write_com(0x80+0x40);
for(c=0;c
{
write_data(table4[c]);
delay(1);
}
}
/////////////////////////////////18B20复位,初始化函数////////////////////////////////////
void dsreset(void)
{
uint i;
ds=0;
i=103;
while(i>0)i--;
ds=1;
i=4;
while(i>0)i--;
}
/////////////////////////////////18B20读1位函数////////////////////////////////////
bit tempreadbit(void)
{
uint i;
bit dat;
ds=0;i++; //i++ 起延时作用
ds=1;i++;i++;
dat=ds;
i=8;while(i>0)i--;
return (dat);
}
/////////////////////////////////18B20读1个字节////////////////////////////////////
uchar tempread(void)
{
uchar i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tempreadbit();
dat=(j<>1); //读出的数据最低位在最前面,这样刚好一个字节在DAT里
}
return(dat);
}
/////////////////////////////////向18B20写一个字节数据////////////////////////////////////
void tempwritebyte(uchar dat)
{
uint i;
uchar j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb) //写 1
{
ds=0;
i++;i++;
ds=1;
i=8;while(i>0)i--;
}
else
{
ds=0; //写 0
i=8;while(i>0)i--;
ds=1;
i++;i++;
}
}
}
//////////////////////////////DS18B20 开始获取温度并转换////////////////////////////////////
void tempchange(void)
{
dsreset();
delay(1);
tempwritebyte(0xcc); // 写跳过读ROM指令
tempwritebyte(0x44); // 写温度转换指令
}
////////////////////////////////读取寄存器中存储的温度数据////////////////////////////////////
uint get_temp()
{
uchar f,g;
dsreset();
delay(1);
tempwritebyte(0xcc);
tempwritebyte(0xbe);
f=tempread(); //读低8位
g=tempread(); //读高8位
temp=g;
temp<<=8; //两个字节组合为1个字
temp=temp|f;
f_temp=temp*0.0625; //温度在寄存器中为12位 分辨率位0.0625°
temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入
f_temp=f_temp+0.05;
return temp; //temp是整型
}
////////////////////////////////1602显示温度数据h和温度报警程序////////////////////////////////////
void dis_temp(uint t)
{
uchar i;
i=t/100;
write_com(0x80+0x02); //显示温度十位
write_data(table[i]);
wendu1=table[i];
i=t%100/10;
write_com(0x80+0x03); //显示温度个位
write_data(table[i]);
write_com(0x80+0x04); //显示'C
write_data(table[20]);
write_com(0x80+0x05); //显示'C
write_data(table[21]);
wendu2=table[i];
}
////////////////////////////////1602显示烟雾和烟雾报警////////////////////////////////////
void dis_yanwu(uint t)
{
uchar i;
t=t*100/255;
i=t/100;
write_com(0x80+0x43); //显示烟雾百位
write_data(table[i]);
yanwu1=table[i];
i=t%100/10;
write_com(0x80+0x44); //显示烟雾十位
write_data(table[i]);
yanwu2=table[i];
i=t%100%10;
write_com(0x80+0x45); //显示烟雾个位
write_data(table[i]);
yanwu3=table[i];
if(t>52)
beep=0;
else
beep=1;
}
void IICstart(void)
{
SDA=1; //先将SDA=1,以准备在SCL=1时,将SDA=0
SCL=1; //时钟总线拉高
nop(); //略做延时
nop(); //略做延时
SDA=0; //SCL=1时,将SDA拉低即产生启动信号
nop(); //略做延时
nop(); //略做延时
SCL=0; //将SCL=0,完成启动信号操作
}
void IICstop(void)
{
SDA=0; //先将SDA=0,以准备在SCL=1时,将SDA=1
SCL=1; //时钟总线拉高
nop(); //略做延时
nop(); //略做延时
SDA=1; //SCL=1时,将SDA拉高即产生停止信号
nop(); //略做延时
nop(); //略做延时
SCL=0; //将SCL=0,完成启动信号操作
}
void Write1Byte(unsigned char Buf1)
{
unsigned char k; //1个字节要分8次写入,需要定义一个寄存器用来计数
for(k=0;k<8;k++) //做一个8次的循环,每次写入1位,需要写8次
{
if(Buf1&0x80) //从最高位开始写
{
SDA=1; //如果欲写入数据为1,就将数据线置1
}
else
{
SDA=0; //如果欲写入数据为0,就将数据线写0
}
nop(); //略做延时
nop(); //略做延时
SCL=1; //时钟线做一个上升沿,将一位数据写入
Buf1=Buf1<<1; //数据左移一位,将下次要写入的位数据移到最高位
nop(); //略做延时
SCL=0; //将SCL=0,以准备通过上升沿将数据写入
nop(); //略做延时
}
SDA=1; //将SDA=1,准备读应答信号
nop(); //略做延时
SCL=1; //将SCL=1,做个上升沿准备读应答信号
nop(); //略做延时
nop(); //略做延时
SCL=0; //将SCL=0,结束应答信号读操作
}
unsigned char Read1Byte(void)
{
unsigned char k; //1个字节要分8次读出,需要定义一个寄存器用来计数
unsigned char t=0; //定义一个寄存器用保存读出数据
for(k=0;k<8;k++) //做一个8次的循环,每次读入1位,需要读8次
{
t=t<<1; //数据左移一位,空出最低位以准备保存读入的一位数据
SDA=1; //将SDA写1准备读
SCL=1; //将SCL=1,做个上升沿准备读一位数据
nop(); //略做延时
nop(); //略做延时
if(SDA==1) //读一位数据,并判断
{
t=t|0x01; //如果读入数据为1,就将接收缓冲区最低一位置1
}
else
{
t=t&0xfe; //如果读入数据为0,就将接收缓冲区最低一位写0
}
SCL=0; //SCL恢复为0,结束一位数据读操作
nop(); //略做延时
nop(); //略做延时
}
return t; //将读入的一个字节返回
}
void WritePCF8591(unsigned char Databuf)
{ //直接调用本函数即可启动PCF8591的D/A转换
IICstart(); //IIC启动信号
Write1Byte(0x90); //发送PCF8591的器件地址和写信号
Write1Byte(0x40); //发送器件子地址
Write1Byte(Databuf); //发送数据
IICstop(); //产生IIC停止信号
}
unsigned ReadPCF8591(unsigned char Ch)
{ //直接调用本函数即可从PCF8591的Ch通道读出数据返回
unsigned char buf; //定义一个寄存器用来暂存读出的数据
IICstart(); //IIC启动信号
Write1Byte(0x90); //发送PCF8591的器件地址和写信号
Write1Byte(0x40|Ch); //发送器件通道参数Ch=0-3
IICstart(); //IIC启动信号
Write1Byte(0x91); //发送PCF8591的器件地址和读信号
buf=Read1Byte();//读一个字节数据
IICstop(); //产生IIC停止信号
return(buf); //将读出数据返回
}
/************************************DHT11读一个字节********************************/
uchar write_byte1() //读一个字节
{
uchar i,comdata,temp1;
for(i=0;i<8;i++)
{
FLAG=2;
while((!dat)&&FLAG++);//判断数据位是0还是1
Delay_10us();
Delay_10us();
Delay_10us();
temp1=0;
if(dat)temp1=1; // 如果高电平高过预定0高电平值则数据位为 1
FLAG=2;
while((dat)&&FLAG++);//flag先与后加1 如果dat一直为1 uchar型变量 flag 溢出变为0 再自加1
if(FLAG==1)break; //超时则跳出for循环
comdata<<=1;//左移一位 高位在前 低位在后
comdata|=temp1;
}
return (comdata);
}
///////////////////////////////////DHT11读5个字节数据///////////////////////////////////
void DHT11_5() //两个字节为温度数据 两个字节为湿度数据 最后一个字节为校验
{
uchar i,temp;
//主机拉低18ms
dat=0;
Delay_t(180);
dat=1;
//总线由上拉电阻拉高 主机延时20us
Delay_10us();
Delay_10us();
Delay_10us();
Delay_10us();
//主机设为输入 判断从机响应信号
dat=1;
//判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
if(!dat) //T !
{
FLAG=2; //超时标志位
while((!dat)&&FLAG++);//判断从机是否发出 80us 的低电平响应信号是否结束
FLAG=2;
while(
(dat)&&FLAG++); //判断从机拉高80us是否结束
for(i=0;i<5;i++)//数据接收状态
{
DHT11[i]=write_byte1();
}
dat=1; //释放数据总线 为下一次读取做好准备
temp=(DHT11[0]+DHT11[1]+DHT11[2]+DHT11[3]);
if(temp==DHT11[4]) //数据校验
{
RTflag=1;
}
}
}
///////////////////////////////////湿度显示函数///////////////////////////////////
void display_RH()
{
DHT11_5(); //读数据
if(RTflag==1) //如果RTflag=1 说明读取到得数据正确
{
RTflag=0;
write_shu(10,0,DHT11[0]);
}
}
//////////////////////////////串口初始化////////////////////////////////
void UARTinit()
{
TMOD=0X21;
SCON=0X40;
TH1=0XFD;
TL1=0XFD;
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
TR1=1;
TR0=1;
EA=1;
ES=1;
ET0=1;
}
///////////////////////////////主函数////////////////////////////////////
void main()
{
uint wendu;
beep=1;
UARTinit();
lcdrw=0; //确定读操作
init_1602(); //初始化LCD1602
delay(5);
name();
delay(500);
while(1)
{
write_byte1();//读一个字节
display_RH();
tempchange();
wendu=get_temp();
dis_temp(wendu);
ADbuf=ReadPCF8591(0); //将AIN0通道A/D转换结果暂存在ADbuf
dis_yanwu(ADbuf);
}
}