基于51单片机,传感器使用dht11和ds18b20,dht11测温度精度有限,18b20可以弥补。第一行显示dht11采集到的湿度和温度,以及继电器状态。第二行显示18b20采集到温度和THI。THi是畜牧业衡量动物热应激指数的标准,不需要的删除掉。继电器是通过THI指数高低控制的。
单片机源程序如下:
- /*********************************************************************************************
- 程序名: DHT11-1602
- 编写人: fby
- 编写时间: 2019年3月21日
- 硬件支持: STC89C52RC DHT11 LCD1602
- 接口说明: DHT11:VCC DATA NC GND
- *********************************************************************************************
- 说明:1、单片机是STC89C52RC,晶振频率11.0592MHz,实验成功。
- 2、好东西要共享,大家随意折腾~~
- *********************************************************************************************/
- #include "reg52.h"
- #include<intrins.h> //此文件中定义了单片机的一些特殊功能寄存器
- #include<stdio.h>
- #include"temp.h"
-
- #define uchar unsigned char //无符号字符型类型数据
- #define uint unsigned int //无符号整型数据
- #define ulong unsigned long //无符号整型数据
- #define xiao float //xiaoshu
- #define IODATA P0
-
- uchar dat_r[10]; //用于存放从DHT11读取到的数值
- uchar sData[10];
- sbit DATA=P2^0; //定义数据线
- sbit RS=P2^6; //定义rs端口
- sbit RW=P2^5; //定义rw端口
- sbit E=P2^7;
- sbit jidian=P3^7; //定义继电器
-
- static uint i;
- extern uint zheng;
-
-
-
-
- void delay200ms(void) //误差 0us
- {
- unsigned char a,b,c;
- for(c=4;c>0;c--)
- for(b=116;b>0;b--)
- for(a=214;a>0;a--);
- _nop_(); //if Keil,require use intrins.h
- }
- /*******************************************************************************
- * 函 数 名 : datapros()
- * 函数功能 : 温度读取处理转换函数
- * 输 入 : temp
- * 输 出 : 无
- *******************************************************************************/
- void datapros(int temp)
- {
- float tp;
- if(temp< 0) //当温度值为负数
- {
- sData[0]=0;
- //因为读取的温度是实际温度的补码,所以减1,再取反求出原码
- temp=temp-1;
- temp=~temp;
- tp=temp;
- temp=tp*0.0625*100+0.5;
- //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
- //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
- //算加上0.5,还是在小数点后面。
-
- }
- else
- {
- sData[0]=1;
- tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
- //如果温度是正的那么,那么正数的原码就是补码它本身
- temp=tp*0.0625*100+0.5;
- //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
- //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
- //算加上0.5,还是在小数点后面。
- }
- //显示数据处理
- sData[1] = '0'+(temp / 10000);
- sData[2] = '0'+(temp % 10000 / 1000);
- sData[3] = '0'+(temp % 1000 / 100) ;
- sData[4] = '0'+(temp % 100 / 10);
- sData[5] = '0'+(temp % 10);
- //真实数据
- sData[7] = temp / 10000;
- sData[8] = temp % 10000 / 1000;
- sData[9] = temp % 1000 / 100 ;
- sData[10] =temp % 100 / 10;
- }
- /*******************************************************************************
- * 函 数 名 : Timer1Init
- * 函数功能 : 定时器1初始化
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- void Timer1Init()
- {
- TMOD|=0X10;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
- TH1=0XFC; //给定时器赋初值,定时1ms
- TL1=0X18;
- ET1=1;//打开定时器1中断允许
- EA=1;//打开总中断
- TR1=1;//打开定时器
- }
- /*********************************************************************************************
- 函数名:延时函数
- 调 用:Delay30us();/Delay20ms();/Delay1s();
- 参 数:无
- 返回值:无
- 结 果:延时相应时间
- 备 注:振荡晶体为11.0592MHz(所有延时函数Copy自STC-ISP(v6.85).exe)
- **********************************************************************************************/
- void Delay30us() //@11.0592MHz-40
- {
- unsigned char i;
- i = 11;
- while (--i);
- }
- void Delay20ms() //@11.0592MHz
- {
- unsigned char i, j;
- i = 36;
- j = 217;
- do
- {
- while (--j);
- } while (--i);
- }
- void Delay1s() //@11.0592MHz
- {
- unsigned char i, j, k;
- _nop_();
- i = 8;
- j = 1;
- k = 243;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
- /*********************************************************************************************
- 函数名:DHT11启动函数
- 调 用:无
- 参 数:无
- 返回值:无
- 结 果:DHT11开始工作
- 备 注:
- **********************************************************************************************/
- void DHT11_start() // 主机控制DHT11开始工作
- {
- DATA=1; // 主线空闲状态
- _nop_();
- _nop_();
- DATA=0; // 主机发送开始工作信号
- Delay20ms(); //延时18ms以上
- DATA=1; // 拉高并延时等待DHT11响应
- Delay30us();
- }
- /*********************************************************************************************
- 函数名:DHT11读数据函数
- 调 用:? = DHT11_rec_byte();
- 参 数:无
- 返回值:
- 结 果:读DHT11数据并保存到dat
- 备 注:
- **********************************************************************************************/
- uchar DHT11_rec_byte() //接收一个字节
- {
- uchar i,dat=0;
- for(i=0;i<8;i++) //从高到低依次接收8位数据
- {
- while(!DATA); ////等待50us低电平过去
- Delay30us();
- Delay30us(); //延时60us,如果还为高则数据为1,否则为0
- dat<<=1; //左移位使正确接收8位数据,数据为0时直接移位
- if(DATA==1) //数据为1时,使dat加1来接收数据1
- dat+=1;
- while(DATA); //等待数据线拉低
- }
- return dat;
- }
- /*********************************************************************************************
- 函数名:接收DHT11的40位的数据并校验
- 调 用:? = DHT11_receive();
- 参 数:无
- 返回值:无
- 结 果:结果保存到dat_r[i]中
- 备 注:
- **********************************************************************************************/
- void DHT11_receive() //接收40位的数据
- {
- uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise;
- //xiao thi;
- //uint zheng;
- DHT11_start(); // 主机控制DHT11开始工作
- if(DATA==0)
- {
- while(DATA==0); //等待拉高
- Delay30us();
- Delay30us();
- Delay30us(); //拉高后延时80us
- R_H=DHT11_rec_byte(); //接收湿度高八位
- R_L=DHT11_rec_byte(); //接收湿度低八位
- T_H=DHT11_rec_byte(); //接收温度高八位
- T_L=DHT11_rec_byte(); //接收温度低八位
- revise=DHT11_rec_byte(); //接收校正位
- Delay30us(); //结束
- if((R_H+R_L+T_H+T_L)==revise) //校正
- {
- RH=R_H;
- RL=R_L;
- TH=T_H;
- TL=T_L;
-
- }
- /*数据处理,方便显示*/
- dat_r[0]='0'+(RH/10);
- dat_r[1]='0'+(RH%10);
- dat_r[2]='0'+(TH/10);
- dat_r[3]='0'+(TH%10);
-
- dat_r[4]=RH;
-
-
- //dat_r[4]='0'+(zheng/100);
- //dat_r[5]='0'+(zheng%100/10);
- //dat_r[6]='0'+(zheng%10);
- //dat_r[7]='0'+(zheng/10);
- //dat_r[8]=Thi;
- //dat_r[7]='0'+(h);
- //dat_r[7]='0'+(zheng);
-
- }
- }
- /********************************************************************
- * 名称 : bit Busy(void)
- * 功能 : 这个是一个读状态函数,读出函数是否处在忙状态
- * 输入 : 输入的命令值
- * 输出 : 无
- ***********************************************************************/
- void Busy(void)
- {
- bit busy_flag = 1;
- IODATA = 0xff;
- RS = 0; //指令关
- Delay30us();
- RW = 1; //读状态
- Delay30us();
- E = 1; //使能高电平
- while(1)
- {
- busy_flag = (bit)(IODATA & 0x80); //强制取最高位
- if(busy_flag == 0)
- {
- break;
- }
- }
- E = 0; //E 1->0,rs=0,rw=1,
- //将数据寄存器内的数据读到DB0~DB7,分别将状态标志BF和地址计数器(AC)内容读到DB7和DB6~DB0。
- }
- /********************************************************************
- * 名称 : lcd1602_write_cmd(uchar del)
- * 功能 : 1602命令函数
- * 输入 : 输入的命令值
- * 输出 : 无
- ***********************************************************************/
- void lcd1602_write_cmd(uchar del)
- {
- RS = 0;
- Delay30us();
- RW = 0;
- Delay30us();
- E = 0;
- Delay30us();
- IODATA = del;
- Delay30us();
- E = 1;
- Delay30us();
- E = 0; //E 1->0,rs=0,rw=0, 将指令代码写入指令寄存器中
- }
- /********************************************************************
- * 名称 : lcd1602_write_data(uchar del)
- * 功能 : 1602写数据函数
- * 输入 : 需要写入1602的数据
- * 输出 : 无
- ***********************************************************************/
- void lcd1602_write_data(uchar del)
- {
- Busy();
- Delay30us();
- RS = 1;
- Delay30us();
- RW = 0;
- Delay30us();
- E = 0;
- Delay30us();
- IODATA = del;
- Delay30us();
- E = 1;
- Delay30us();
- E = 0; //E 1->0,rs=1,rw=0, 数据写入数据寄存器中
- }
- /********************************************************************
- * 名称 : lcd1602_init()
- * 功能 : 1602初始化,请参考1602的资料
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void lcd1602_init(void)
- {
- Delay20ms();
- lcd1602_write_cmd(0x38); //8位数据,双列,5*7字形
- Delay20ms();
- lcd1602_write_cmd(0x38);
- Delay20ms();
- lcd1602_write_cmd(0x38);
- Busy();
- lcd1602_write_cmd(0x08);// 只开显示
- Busy();
- lcd1602_write_cmd(0x01); //清屏
- Busy();
- lcd1602_write_cmd(0x06);//显示地址递增,即写一个数据后,显示位置右移一位
- Busy();
- lcd1602_write_cmd(0x0c); //开启显示屏,关光标,光标不闪烁
- }
- /********************************************************************
- * 名称 : lcd1602_char(uchar hang,uchar lie,char sign)
- * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下
- L1602_char(1,5,'b')
- * 输入 : 行,列,需要输入1602的数据
- * 输出 : 无
- ***********************************************************************/
- void lcd1602_char(uchar hang,uchar lie,char sign)
- {
- uchar a;
- if(hang == 1)
- {
- a = 0x80;
- }
- if(hang == 2)
- {
- a = 0xc0;
- }
- a = a + lie - 1;
- Busy();
- lcd1602_write_cmd(a); //置数据存贮器地址
- Busy();
- lcd1602_write_data(sign);
- }
- /********************************************************************
- * 名称 : lcd1602_string(uchar hang,uchar lie,uchar *p)
- * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
- L1602_string(1,5,"ab cd ef;")
- * 输入 : 行,列,需要输入1602的数据
- * 输出 : 无
- ***********************************************************************/
- void lcd1602_string(uchar hang,uchar lie,uchar *p)
- {
- uchar a;
- if(hang == 1)
- {
- a = 0x80;
- }
- if(hang == 2)
- {
- a = 0xc0;
- }
- a = a + lie - 1;
- while(1)
- {
- Busy();
- lcd1602_write_cmd(a);
- Busy();
- lcd1602_write_data(*p);
- a++;
- p++;
- if((*p == '\0')||(a==0x90)||(a==0xd0)) //字符结束或每行最后一个字符
- {
- break;
- }
- }
- }
- void kongzhi() //控制函数
- {
- if(dat_r[8]>78) {jidian=0;lcd1602_string(1,16,"K");} // 上限74
- else if(dat_r[8]<77) {jidian=1;lcd1602_string(1,16,"G");} // 下限72
- else {lcd1602_string(1,16,"L");}
- }
- //thi计算函数
- void thisuan()
- {
- xiao th;
- uint thi,shi,wen;
- shi=dat_r[4] ;
- wen=sData[7]*100+sData[8]*10+sData[9]+sData[10]/10 ;
- th=wen*0.81+(0.99*wen-14.3)*shi/100+46.3+0.5;
- thi=th*10;
- dat_r[5]='0'+(thi/100);
- dat_r[6]='0'+(thi%100/10);
- dat_r[7]='0'+(thi%10);
- dat_r[8]=th;
- }
- /*********************************************************************************************
- 函数名:主函数
- 调 用:无
- 参 数:无
- 返回值:无
- 结 果:读DHT11数据并送到1602显示
- 备 注:
- **********************************************************************************************/
- void main (void)
- {
-
- Delay20ms();
- lcd1602_init(); //LCD初始化
-
- while(1)
- {
- datapros(Ds18b20ReadTemp());
- delay200ms; //经测试,两次连读要至少延时80ms
- DHT11_receive();//接受数据
- thisuan();
-
-
-
-
- lcd1602_string(1,1,"S:");
- lcd1602_char(1,3,dat_r[0]);
- lcd1602_char(1,4,dat_r[1]);
- lcd1602_string(1,5,"%");
-
- lcd1602_string(1,7,"W:");
- lcd1602_char(1,8,dat_r[2]);
- lcd1602_char(1,9,dat_r[3]);
- lcd1602_char(1,10,0XDF);
- lcd1602_string(1,11,"C");
-
- lcd1602_string(2,1,"T:");
- lcd1602_char(2,3,dat_r[5]);
- lcd1602_char(2,4,dat_r[6]);
- lcd1602_string(2,5,".");
- lcd1602_char(2,6,dat_r[7]);
-
-
- if(sData[0]==0)
- {
- lcd1602_string(2,8,"-");
- }
-
- if(sData[7]>0)
- {
- lcd1602_char(2,9,sData[1]);
- }
-
- lcd1602_char(2,10,sData[2]);
- lcd1602_char(2,11,sData[3]);
- lcd1602_string(2,12,".");
- lcd1602_char(2,13,sData[4]);
- //lcd1602_char(2,14,sData[5]);
-
-
- lcd1602_string(1,13,"ji:");
-
- kongzhi();
-
-
-
- }}
-
-
- //void Timer0() interrupt 3 //定时器中断
- //{
-
-
- //TH0=0XFC; //给定时器赋初值,定时1ms
- //TL0=0X18;
- //i++;
-
- //}
复制代码
所有资料51hei提供下载:
THI dht11 18b20.zip
(78.98 KB, 下载次数: 90)
|