系统提供2种工作模式,在显示模式中:1.显示温湿度2.超出温湿度限定的范围时蜂鸣器,LED实现报警3.加减温度时显示标志;在设置模式中:分别设置温湿度上下限

硬件:单片机AT89C52液晶LCD1602显示器温湿度传感器DHT11存储器AT24C02

else:I2C总线Time0定时器

目录

LCD1602

液晶判忙

液晶初始化,写入指令,数据

液晶显示行,列的位置

液晶数据转换成字符串,以及显示

温湿度传感器DHT11

DHT11采集数据​编辑

读取数字0​编辑

读取数字1​编辑

校验

I2C总线

存储器AT24C02

通过I2C总线来设置AT24C02

Time0定时器

主函数

proteus仿真图



LCD1602

液晶判忙

LCD 1602的响应速度相对于单片机的速度来说是偏慢的。
        举个简单的例子,把一桶油通过漏斗向一个瓶子里倒,倒油的速度,即流量必须维持在一定范围之内,倒得太快油会从漏斗顶部溢出来,这样就浪费掉了。我们通过眼睛可以判断并使油面保持在顶面以下,以漏斗的额定流量来倒油,这样效率最高。
        而对于单片机来说,1602好比那个瓶子漏斗,写入1602中要显示的数据好比油,如果以单片机的高运行速度向1602写数据就很可能造成上面所说的溢出,比如连续写入abc,结果只显示出了a,这是因为1602的显示芯片每次都要花时间来处理输入的ascii码数据,并把它显示出来。而我们却不容易主动地去控制写入数据的速度,所以1602使用忙信号就有必要了,每次单片机只有检测到忙信号为0,即不忙时,才向1602发数据。比如要显示abc,则这样操作,写a---判忙---写b---判忙---写c---判忙。这样就不会出错了。

/*等待液晶准备*/
void Lcdready()
{unsigned char sta;P0 = 0xFF;  //P0在使用时要规定置1RS = 0;     //数据/指令选择位 1为数据,0为指令RW = 1;     //读/写位 1为读,0为写do{EN = 1;  //使能位sta = P0;//读取状态字,即把P0口的数据赋值给staEN = 0;}while(sta & 0x80);//当sta最高位为0时则跳出循环;若为1时则继续循环,相当于单片机停止让液晶先工作
}

液晶初始化,写入指令,数据

/* 初始化 1602 液晶 */
void init1602()
{WriteCmd(0x38);WriteCmd(0x0C);WriteCmd(0x06);WriteCmd(0x01);
}/* 向 LCD1602 液晶写入命令,cmd-待写入命令值 */
void WriteCmd(unsigned char cmd)
{Lcdready();RS = 0;RW = 0;P0 = cmd;EN = 1;EN = 0;
}
/* 向 LCD1602 液晶写入数据,dat-待写入数据 */
void WriteData(unsigned char dat)
{Lcdready();RS = 1;RW = 0;P0 = dat;EN = 1;EN = 0;
}

液晶显示行,列的位置

/* 设置显示 RAM 起始地址(x,y)-对应屏幕上的字符坐标 */
void Lcdaddr(unsigned char x,unsigned char y)
{unsigned char m;if(y==0)m = 0x00+x;    //第一行字符地址从 0x00 起始else m = 0x40+x;    //第二行字符地址从 0x40 起始WriteCmd(m | 0x80);//设置 RAM 地址
} 

液晶数据转换成字符串,以及显示

/* 整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */
unsigned char IntToString(unsigned char *str, int dat)
{unsigned char i = 0;unsigned char len = 0;unsigned char buf[6];if (dat < 0)  //如果为负数,首先取绝对值,并在指针上添加负号{dat = -dat;*str++ = '-';len++;}do                //先转换为低位在前的十进制数组{         buf[i++] = dat % 10;  //取最低位dat /= 10;     } while (dat > 0);len += i;     //i最后的值就是有效字符的个数while (i-- > 0)   //将数组值转换为ASCII码反向拷贝到接收指针上{*str++ = buf[i] + '0';  //加0其实是加ASCII码中的0x30}*str = '\0';  //添加字符串结束符return len;   //返回字符串长度
}/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void Lcdshow(unsigned char x,unsigned char y,unsigned char *str)
{Lcdaddr(x,y);while(*str != '\0')      //表示一直循环到字符串结尾{WriteData(*str++);   //表示从高到低依次写入str数组的值}
}

注:ASCII码中,数字0地址为0x30,1为0x31,2为0x32......因此,在指针*str=buf[i]中,为了表示数字0,1,2.......要加上0x30的地址('0')。

温湿度传感器DHT11

DHT11采集数据

读取数字0

读取数字1

校验

"8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据"相加所得结果的末8位。

#ifndef _DHT11_H_
#define _DHT11_H_#define uchar unsigned char
#define uint unsigned intsbit DHT11_DB=P3^4;uchar Temp_H,Temp_L,Humi_H,Humi_L,Check_data;//温度整数位,小数位;湿度整数位,小数位,数据校验位
uchar U8FLAG;void Delay_ms(uint n);         //ms延时函数
void Delay_us(uchar n);     //us延时函数
uchar DHT11_receive(void);  //DHT11接收数据函数
void DHT11_read(void);      //DHT11读取温湿度函数
bit  DHT11_Check(void);     //DHT11校验函数,返回1:校验成功、返回0:校验失败void Delay_ms(uint n)
{unsigned char j; while(n--){for(j=0;j<125;j++);}
}void Delay_us(uchar n)
{n=n/2;while(--n);
}/接收DHT11传回来的数据
uchar DHT11_receive(void)
{uchar i,Data; for(i=0;i<8;i++){U8FLAG=2;  //延迟80nswhile(!DHT11_DB&&U8FLAG++);  //当DHT11_DB由低电平0拉到高电平1时,跳出延迟Delay_us(35);    Data<<=1; if(DHT11_DB)  //判断输出为1或0Data|=1;U8FLAG=2;while(DHT11_DB&&U8FLAG++);   //当DHT11_DB由高电平1拉到低电平0时,跳出延迟}return Data;
}/读取DHT11温湿度
void DHT11_read(void)
{DHT11_DB=0;Delay_ms(18);DHT11_DB=1;Delay_us(40);if(!DHT11_DB) //T !{U8FLAG=2;while(!DHT11_DB&&U8FLAG++);U8FLAG=2;while(DHT11_DB&&U8FLAG++);Humi_H=DHT11_receive();  //湿度整数Humi_L=DHT11_receive();  //湿度小数Temp_H=DHT11_receive();  //温度整数Temp_L=DHT11_receive();  //温度小数Check_data=DHT11_receive();  //校验DHT11_DB=1;    //最后拉高电平}
}/校验
bit DHT11_Check(void)
{if((Temp_H+Temp_L+Humi_H+Humi_L)==Check_data)  //判断校验和是否正确return 1;elsereturn 0;
}
#endif

I2C总线

#include <REGX52.H>
#include "I2C.h"void I2CStart()  //I2C开始
{I2C_SCL=1;I2C_SDA=1;I2C_SDA=0; I2C_SCL=0;
}void I2CStop()  //I2C结束
{I2C_SCL=0;I2C_SDA=0;I2C_SCL=1;I2C_SDA=1;
}bit I2CWrite(unsigned char dat) //I2C写操作,dat-代写数值,ack-返回应答值
{bit ack;  //用来暂存应答值unsigned char mask;  //用来暂存数据for(mask=0x80;mask!=0;mask>>=1){if((mask&dat))I2C_SDA=1;elseI2C_SDA=0;I2C_SCL=1;    //拉高SCLI2C_SCL=0;    //再拉低SCL,完成一个周期}I2C_SDA=1;    //主机释放SDAI2C_SCL=1;ack=I2C_SDA;  //读取SDA值,即为应答值I2C_SCL=0;return (~ack); //因为原本的I2C是0表示应答,1表示非应答,所以这里取反
}unsigned char I2CReadNAK()  //I2C总线读操作,发送非应答信号并继续读下去,返回值-读到的字节
{unsigned char mask; unsigned char dat;  //暂存数据I2C_SDA=1;  //确保主机释放SDAfor(mask=0x80;mask!=0;mask>>=1){I2C_SCL=1;if(I2C_SDA)dat|=mask;elsedat&=~mask;I2C_SCL=0;}I2C_SDA=1;  //拉高SDA,发送非应答信号I2C_SCL=1;  //拉高SCLI2C_SCL=0;  //再拉低SCL完成非应答return dat; //返回数据
}unsigned char I2CReadACK()  //I2C总线读操作,发送应答信号并不再读下去,返回值-读到的字节
{unsigned char mask;unsigned dat; //暂存数据I2C_SDA=1;    //确保主机释放SDAfor(mask=0x80;mask!=0;mask>>=1){I2C_SCL=1;if(I2C_SDA)dat|=mask;elsedat&=~mask;I2C_SCL=0;}I2C_SDA=0;  //拉高SDA,发送应答信号I2C_SCL=1;  //拉高SCLI2C_SCL=0;  //再拉低SCL完成应答return dat; //返回数据
}

存储器AT24C02

通过I2C总线来设置AT24C02

/*** @brief  AT24C02写入一个字节* @param  WordAddress 要写入字节的地址* @param  Data 要写入的数据* @retval 无*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_SendByte(Data);I2C_ReceiveAck();I2C_Stop();
}/*** @brief  AT24C02读取一个字节* @param  WordAddress 要读出字节的地址* @retval 读出的数据*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();I2C_SendByte(AT24C02_ADDRESS);I2C_ReceiveAck();I2C_SendByte(WordAddress);I2C_ReceiveAck();I2C_Start();I2C_SendByte(AT24C02_ADDRESS|0x01);I2C_ReceiveAck();Data=I2C_ReceiveByte();I2C_SendAck(1);I2C_Stop();return Data;
}

Time0定时器

用来在设置模式是,实现闪烁功能

#include <REGX52.H>/*** @brief  定时器0初始化,1毫秒@12.000MHz* @param  无* @retval 无*/
void Timer0Init(void)
{TMOD &= 0xF0;     //设置定时器模式TMOD |= 0x01;     //设置定时器模式TL0 = 0x18;       //设置定时初值TH0 = 0xFC;        //设置定时初值TF0 = 0;       //清除TF0标志TR0 = 1;      //定时器0开始计时ET0=1;EA=1;PT0=0;
}/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18;       //设置定时初值TH0 = 0xFC;        //设置定时初值T0Count++;if(T0Count>=1000){T0Count=0;}
}
*/

主函数

#include <REGX52.H>
#include "DHT11.h"
#include "AT24C02.h"
#include "LCD1602.h"
#include "Timer0.h"//灯、蜂鸣器、按键引脚定义
sbit led     = P3^7;  //超限指示灯
sbit led1    = P3^2;  //正常指示灯
sbit buzz    = P2^3;  //蜂鸣器
sbit key_set = P1^0;  //设置键
sbit key_jia = P1^3;  //加键
sbit key_jian= P1^6;  //减键//变量定义
uchar temp_old,humi_old;//存储上一次的温度、湿度
uchar temp_up,temp_down;//存储温度上、下限值
uchar humi_up,humi_down;//存储湿度上、下限值
uchar set_f;            //设置选择标记,=0非设置,=1设置湿度上限,=2设置湿度下限//              =3设置温度上限,=4设置温度下限。
uchar Flash;        //闪烁//显示固定内容
void fix_display()
{LCD_ShowString(1,1,"Humi:");LCD_ShowString(2,1,"Temp:");LCD_ShowString(1,12,"RH");LCD_ShowChar(2,12,'C');
}//显示当前测出的内容
void now_display()
{if(humi_old<Humi_H)  //判断湿度是否正在上升{LCD_ShowString(1,15,"UP");  //上升标志UPDelay_ms(50);humi_old=Humi_H;   //记录此时的湿度}else if(humi_old>Humi_H)  //判断湿度是否正在下降{LCD_ShowString(1,15,"DW");Delay_ms(50);humi_old=Humi_H;}if(temp_old<Temp_H){LCD_ShowString(1,15,"UP");Delay_ms(50);temp_old=Temp_H;}else if(temp_old>Temp_H){LCD_ShowString(1,15,"DW");Delay_ms(50);temp_old=Temp_H;}if(temp_up<Temp_H||temp_down>Temp_H||humi_up<Humi_H||humi_down>Humi_H)  //当温湿度超过界限时,LED和蜂鸣器报警{buzz=0;led=0;led1=1;}else  //LED1正常显示{buzz=1;led=1;led1=0;}LCD_ShowNum(1,6,Humi_H,2);  //显示实测的温湿度LCD_ShowChar(1,8,'.');LCD_ShowNum(1,9,Humi_L,2);LCD_ShowNum(2,6,Temp_H,2);LCD_ShowChar(2,8,'.');LCD_ShowNum(2,9,Temp_L,2);
}//显示设置时的内容
void set_display()
{LCD_ShowString(1,1,"Humi:Up");  LCD_ShowString(2,1,"Temp:Up");LCD_ShowString(1,10,"Down");LCD_ShowString(2,10,"Down");//利用定时器设置Flash闪烁值以达到闪烁效果if(Flash==1&&set_f==1){LCD_ShowString(1,8,"  ");}  //当Flash等于1则清零,等于0则显示else{LCD_ShowNum(1,8,humi_up,2);}                  //当set_f标记键分别等于1,2,3,4时,设置不同位置if(Flash==1&&set_f==2){LCD_ShowString(1,14,"  ");}else{LCD_ShowNum(1,14,humi_down,2);}if(Flash==1&&set_f==3){LCD_ShowString(2,8,"  ");}else{LCD_ShowNum(2,8,temp_up,2);}if(Flash==1&&set_f==4){LCD_ShowString(2,14,"  ");}else{LCD_ShowNum(2,14,temp_down,2);}
}//按键扫描
void scan()
{if(key_set==0)  //当设置键摁下时{Delay_ms(7);if(key_set==0){buzz=1;  //蜂鸣器关闭,所有LED熄灭led=1; led1=1;if(set_f==0) //进入设置模式{LCD_WriteCommand(0x01);  //清屏Delay_ms(10);}set_f++;     //每摁一次key_f设置键,set_f标记键便加1if(set_f==5) //当循环4次,即摁下key_set设置键4次时,把set_f标记键置0{set_f=0;AT24C02_WriteByte(0,humi_up);  //把设置好的温湿度上下限写入AT24C02AT24C02_WriteByte(1,humi_down);AT24C02_WriteByte(2,temp_up);AT24C02_WriteByte(3,temp_down);LCD_WriteCommand(0x01);  //清屏Delay_ms(10);fix_display();  //显示固定内容}}while(!key_set);  //当摁下key_sey设置键松手时,完成一次操作}if(key_jia==0&&set_f!=0)  //加法键{Delay_ms(7);if(set_f==1){humi_up++;}if(set_f==2){humi_down++;}if(set_f==3){temp_up++;}if(set_f==4){temp_down++;}}if(key_jian==0&&set_f!=0) //减法键{Delay_ms(7);if(set_f==1){humi_up--;}if(set_f==2){humi_down--;}if(set_f==3){temp_up--;}if(set_f==4){temp_down--;}}
}void main()
{Timer0Init();  //定时器初始化LCD_Init();    //LCD初始化fix_display(); //显示固定内容Delay_ms(100);AT24C02_WriteByte(0,75);  //在AT24C02中设置温湿度上下限AT24C02_WriteByte(0,45);AT24C02_WriteByte(0,30);AT24C02_WriteByte(0,15);humi_up=AT24C02_ReadByte(0);  //分别赋值给humi_up,humi_down,temp_up,temp_downhumi_down=AT24C02_ReadByte(1);temp_up=AT24C02_ReadByte(2);temp_down=AT24C02_ReadByte(3);while(1){scan();  //按键扫描if(set_f==0) //表示并未进入设置操作{EA=0;      //关闭中断DHT11_read();  //DHT11读取温湿度值now_display(); //显示实测内容EA=1;  //打开中断}elseset_display();   //显示设置内容}
}void Timer0_Routine() interrupt 1  //中断程序
{static unsigned int T0Count;TL0 = 0x18;  //设置初值TH0 = 0xFC;T0Count++;if(T0Count>=500)  //每隔500ms,即0.5秒{T0Count=0;Flash=!Flash;   //Flash翻转}
}

注意:定时器中断在实际应用中容易出现温度的读取数据出现乱码,原因在定时器的中断打断了温度的传输等待时间,使数据传输不完整。因此在读取DHT11前使EA=0关闭中断;读取后EA=1打开中断。

proteus仿真图

基于51单片机的DHT11温湿度检测相关推荐

  1. 基于51单片机的SHT11温湿度检测调节系统(LCD12864显示)

    目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现(protues8.7) 程序(Keil5) 全部资料(压缩文件) 具体实现功能 (1)实时检测温湿度值,LCD12864分别显示温度值 ...

  2. 51单片机控制DHT11温湿度传感器,并使用OLED屏幕显示

    目录 前言 一.MCU主控选型 二.DHT11温湿度传感器 1.模块介绍 2.软件实现 DHT11.c DHT11.h 三.OLED显示屏 1.模块介绍 2.软件实现 OLED.c OLED.h OL ...

  3. (含代码仿真)51单片机+DHT22+LCD1602温湿度检测计+温湿度达阈值控制用电器

    系列文章目录 (仿真模拟)51单片机+DHT22+LCD1602温湿度检测计+温湿度达阈值控制用电器 文章目录 系列文章目录 文章目录 制作要求 一.整体说明 二.电路仿真 三.使用介绍 四.部件说明 ...

  4. 51单片机计算器_基于51单片机的倒计时温度检测报警器

    基于51单片机的倒计时温度检测报警器 学习单片机断断续续半年了,在学长学姐的教学帮助下,完成了51单片机的入门学习,开始实践做项目,在一周时间内设计和制作出个人项目.起初,我设计和选择的是12864显 ...

  5. 基于51单片机的倒计时温度检测报警器

    广西河池学院 广西高校重点实验室培训基地 系统控制与信息处理重点实验室 本篇博客来自河池学院:OpenWRT无线路由组 写作时间:2020年8月12日16:00:03   基于51单片机的倒计时温度检 ...

  6. 基于51单片机的多路温度检测调节串口传输系统

    本设计基于51单片机的多路温度检测调节串口传输系统(仿真+源码+视频讲解) 仿真:proteus8.9 程序编译器:keil 4 编程语言:C语言 编号C0009 [腾讯文档]C0009 网盘链接 资 ...

  7. 水塔水位测量c语言程序,基于51单片机水塔水箱水位检测系统控制器设计(附程序代码)...

    基于51单片机水塔水箱水位检测系统控制器设计(附程序代码)(任务书,开题报告,外文翻译,论文18000字) 摘  要 为了能实现水位监测与控制,以STC89C52作为核心控制芯片,进行了水位检测系统控 ...

  8. 基于51单片机超声波测距液位检测-温度检测

    [毕设课设]基于51单片机超声波测距液位检测-温度检测 ​效果图 Proteus仿真: 功能简介: 文件内容: 程序框架: 网盘链接: ​效果图 更多内容请关注@WENJIE电子科技 ​ 基于51单片 ...

  9. 1430基于51单片机的管道压力检测及泄漏检测Proteus仿真

    [前言] hello 大家好,今天给大家讲一讲基于51单片机的管道压力检测及泄漏检测Proteus仿真. 该项目的功能如下: 1.LCD1602液晶实时显示当前始端和末端压力,压力阈值 2.按键启动/ ...

最新文章

  1. 《线性代数》概念定理大全!
  2. 2015年10月15日作业
  3. [Java基础] sort方法--------排序的那些事
  4. postgresql10.5安装
  5. CodeIgniter的快速操作
  6. 13.IDA-显示正确的函数名称(去掉c++后缀命名)
  7. java 抽象类与接口区别是什么_JAVA中抽象类与接口的区别,分别在什么情况下使用它们...
  8. 前端学习(564):margin计算规则
  9. 详解浏览器跨域访问的几种办法
  10. android程序逆向工程
  11. 开个坑,不定期更新OI段子
  12. viewpager中fragment的生命周期管理
  13. JWT的Java使用 (JJWT)
  14. axios与ajax对比,AjAX 步骤和对比fetch和axios
  15. Qcom 平台 camera 之 RAW+YUV图抓取
  16. Gnutella 及无结构化(非结构化)P2p的一些总结
  17. Android 9 (P)在user模式下无法使用fastboot烧录怎么破
  18. 基于PHP的酒店住宿管理系统毕业设计源码261455
  19. 邓白氏编码官方查询地址
  20. 每日一句:day06——From Zero To Hero

热门文章

  1. C#窗体控件简介_2
  2. Windows启动VM虚拟机和关闭VM虚拟机的bat脚本文件
  3. 魔兽争霸3地图(WarIII Maps):众神之战
  4. 完成智能查找阻力位的核心代码
  5. C#-正则基础 [0-9] 匹配数字
  6. 2022-2027年中国针织机械行业市场调研及未来发展趋势预测报告
  7. 学会提问 - 批判性思维指南概述
  8. KMP经典超简约模板
  9. MySQL数据库基础——基本操作
  10. FME实现dwg数据自动批量计算宗地红线内的建筑面积、附属建筑面积工具