5021-单片机温湿度检测(仿真+程序)

功能描述

1、51+Proteus8.10;

2、学习SHT11温湿度传感器驱动程序、1602显示驱动程序;

仿真设计

单片机管脚说明:

P0端口(P0.0-P0.7):P0口为一个8位漏极开路双向I/O口,每个引脚可吸收8TTL门电流。当P1口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它可以被定义为数据/地址的第八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。

P1端口(P1.0-P1.7):P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高电平,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为第八位地址接收。

P2端口(P2.0-P2.7):P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口,用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。

P3端口(P3.0-P3.7):P3口管脚是一个带有内部上拉电阻的8位的双向I/O端口,可接收输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入端时,由于外部下拉为低电平,P3口将输出电流(ILL)。P3口同时为闪烁编程和编程校验接收一些控制信号。

VCC(40):供电电压,其工作电压为5V。
GND(20):接地。

RST(9):复位输入。在振荡器运行时,有两个机器周期(24个振荡周期)以上的高电平出现在此引脚时,将使单片机复位,只要这个引脚保持高电平,51芯片便循环复位。复位后P3.0-P3.7口均置1,引脚表现为高电平,程序计数器和特殊功能寄存器SFR全部清零。当复位脚由高电平变为低电平时,芯片为ROM的00H处开始运行程序。复位操作不会对内部RAM有所影响。

ALE/PROG (30):当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地低位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE脉冲。如果想禁止ALE的输出可在SFR8EH地址上置0。此时, ALE只有在执行MOVX,MOVC指令是ALE才起作用。另外,该引脚被略微拉高。如果微处理器在外部执行状态ALE禁止,则置位无效。

PSEN(29):外部程序存储器的选通信号。在由外部程序存储器取指令期间,每个机器周期两次PSEN有效。但在访问外部数据存储器时,这两次有效的PSEN信号将不出现。

XTAL1(19):来自反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2(18):来自反向振荡器的输出。

EA/VPP(31):当EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。注意加密方式1时,EA将内部锁定为RESET;当EA端保持高电平时,此间内部程序存储器。在FLASH编程期间,此引脚也用于施加12V的编程电源(VPP)。

 

程序设计

#include <reg52.h>
#include <intrins.h>

#define uchar unsigned char	 //宏定义方便以后用
#define uint unsigned int  
#define ulong unsigned long

//SHT11接口
sbit DATA = P2^5;
sbit SCK = P2^4;

typedef union		   //定义共同类型
{ 
  unsigned int i;	 //i表示测量得到的温湿度数据(int 形式保存的数据) 
  float f;			   //f表示测量得到的温湿度数据(float 形式保存的数据)
} value;

enum {TEMP,HUMI};

uchar TEMP_BUF[7];		//用于记录温度
uchar HUMI_BUF[5];		//用于记录湿度
 
int real_tempure=0;		//实际温度
uchar real_humi=0;


//LCD port
sbit LcdRs= P2^0;
sbit LcdRw= P2^1;
sbit LcdEn= P2^2;
sfr  DBPort= 0x80;		//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口


//向LCD写入命令或数据************************************************************
#define LCD_COMMAND			0      // Command
#define LCD_DATA			1      // Data
#define LCD_CLEAR_SCREEN	0x01      // 清屏
#define LCD_HOMING  		0x02      // 光标返回原点


//设置显示模式************************************************************
#define LCD_SHOW			0x04    //显示开
#define LCD_HIDE			0x00    //显示关	  

#define LCD_CURSOR			0x02 	//显示光标
#define LCD_NO_CURSOR		0x00    //无光标		     

#define LCD_FLASH			0x01    //光标闪动
#define LCD_NO_FLASH		0x00    //光标不闪动
//内部等待函数**************************************************************************
unsigned char LCD_Wait(void)
{
	LcdRs=0;
	LcdRw=1;	_nop_();
	LcdEn=1;	_nop_();
	_nop_();
	_nop_();
	_nop_();
	LcdEn=0;
	return DBPort;		
}

void LCD_Write(bit style, unsigned char input)
{
	LcdEn=0;
	LcdRs=style;
	LcdRw=0;		_nop_();
	DBPort=input;	_nop_();//注意顺序
	LcdEn=1;		_nop_();//注意顺序
	LcdEn=0;		_nop_();
	LCD_Wait();	
}

void LCD_SetDisplay(unsigned char DisplayMode)
{
	LCD_Write(LCD_COMMAND, 0x08|DisplayMode);	
}

//设置输入模式************************************************************
#define LCD_AC_UP			0x02
#define LCD_AC_DOWN			0x00      // default

#define LCD_MOVE			0x01      // 画面可平移
#define LCD_NO_MOVE			0x00      //default

void LCD_SetInput(unsigned char InputMode)
{
	LCD_Write(LCD_COMMAND, 0x04|InputMode);
}


//初始化LCD************************************************************
void LCD_Initial()
{
	LcdEn=0;
	LCD_Write(LCD_COMMAND,0x38);           //8位数据端口,2行显示,5*7点阵
	LCD_Write(LCD_COMMAND,0x38);
	LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR);    //开启显示, 无光标
	LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);   //清屏
	LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE);       //AC递增, 画面不动
}

//************************************************************************
void GotoXY(unsigned char x, unsigned char y)
{
	if(y==0)
		LCD_Write(LCD_COMMAND,0x80|x);
	if(y==1)
		LCD_Write(LCD_COMMAND,0x80|(x-0x40));
}

void Print(unsigned char *str)	 //在LCD上显示数据,内部调用
{
	while(*str!='\0')
	{
		LCD_Write(LCD_DATA,*str);
		str++;
	}
}

void LCD_Print(unsigned char x, unsigned char y, unsigned char *str) //指定的位置打印指定数据
{
  GotoXY(x,y);
  Print(str);
}

/********************************************************************
* 名称 : Delay_1ms()
* 功能 : 延时子程序
* 输入 : x 
* 输出 : 无
***********************************************************************/
void Delay(uint i)//延时
{
	uint x,j;
	for(j=0;j<i;j++)
	for(x=0;x<=148;x++);	
}


/***********************************************************************************************************************************************************/

//SHT11程序


#define noACK 0				//继续传输数据,用于判断是否结束通讯
#define ACK   1             //结束数据传输;
							//地址  命令  读/写
#define STATUS_REG_W 0x06   //000   0011    0
#define STATUS_REG_R 0x07   //000   0011    1
#define MEASURE_TEMP 0x03   //000   0001    1
#define MEASURE_HUMI 0x05   //000   0010    1
#define RESET        0x1e   //000   1111    0


//写字节程序
char SHTXX_write_byte(unsigned char value)   
{ 
	unsigned char i,error=0; 
	for (i=0x80;i>0;i/=2)             //shift bit for masking 高位为1,循环右移
	{ 
		if (i&value) DATA=1;          //和要发送的数相与,结果为发送的位
    	else DATA=0;                        
    	SCK=1;                          
    	_nop_();_nop_();_nop_();        //延时3us 
    	SCK=0;
	}
	DATA=1;                           //释放数据线
	SCK=1;                            
	error=DATA;                       //检查应答信号,确认通讯正常
	_nop_();_nop_();_nop_();
	SCK=0;        
	DATA=1;
	return error;                     //error=1 通讯错误
}

//读字节程序
char SHTXX_read_byte(unsigned char ack)
//----------------------------------------------------------------------------------
{ 
	unsigned char i,val=0;
	DATA=1;                           //释放数据线
	for(i=0x80;i>0;i>>=1)             //高位为1,循环右移
	{ 
		SCK=1;                         
    	if(DATA) val=(val|i);        //读一位数据线的值 
    	SCK=0;       
	}
	DATA=!ack;                        //如果是校验,读取完后结束通讯;
	SCK=1;                            
	_nop_();_nop_();_nop_();          //延时3us 
	SCK=0;   
	_nop_();_nop_();_nop_();       
	DATA=1;                           //释放数据线
	return val;
}

//启动传输
void SHTXX_transstart(void)
// generates a transmission start 
//       _____         ________
// DATA:      |_______|
//           ___     ___
// SCK : ___|   |___|   |______
{ 
   	DATA=1; SCK=0;                   //准备
   	_nop_();
  	SCK=1;
   	_nop_();
   	DATA=0;
   	_nop_();
  	SCK=0; 
  	 _nop_();_nop_();_nop_();
   	SCK=1;
   	_nop_();
  	DATA=1;     
  	_nop_();
   	SCK=0;     
}


//连接复位
void SHTXX_Init(void)
// communication reset: DATA-line=1 and at least 9 SCK cycles followed by transstart
//       _____________________________________________________         ________
// DATA:                                                      |_______|
//          _    _    _    _    _    _    _    _    _        ___     ___
// SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |______
{ 
	unsigned char i; 
	DATA=1; SCK=0;                    //准备
	for(i=0;i<9;i++)                  //DATA保持高,SCK时钟触发9次,发送启动传输,通迅即复位
	{ 
		SCK=1;
    	SCK=0;
	}
	SHTXX_transstart();                   //启动传输
}

 /*
//软复位程序
char SHTXX_softreset(void)
// resets the sensor by a softreset 
{ 
	unsigned char error=0; 
	SHTXX_Init();              //启动连接复位
	error+=SHTXX_write_byte(RESET);       //发送复位命令
	return error;                     //error=1 通讯错误
}
  */


           
//温湿度测量
char SHTXX_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode)
// 进行温度或者湿度转换,由参数mode决定转换内容;
{ 
//	enum {TEMP,HUMI};		 //已经在头文件中定义
	unsigned error=0;
	unsigned int i;

	SHTXX_transstart();                   //启动传输
	switch(mode)                     //选择发送命令
    {	
		case TEMP : error+=SHTXX_write_byte(MEASURE_TEMP); break;		   //测量温度
    	case HUMI : error+=SHTXX_write_byte(MEASURE_HUMI); break;		   //测量湿度
    	default     : break; 
	}
	for (i=0;i<65535;i++) if(DATA==0) break; //等待测量结束
	if(DATA) error+=1;                // 如果长时间数据线没有拉低,说明测量错误 
	*(p_value) =SHTXX_read_byte(ACK);    //读第一个字节,高字节 (MSB)
	*(p_value+1)=SHTXX_read_byte(ACK);    //读第二个字节,低字节 (LSB)
	*p_checksum =SHTXX_read_byte(noACK); //read CRC校验码
	return error;					 // error=1 通讯错误
}

//温湿度值标度变换及温度补偿
void SHTXX_calc(float *p_humidity ,float *p_temperature)
{ 

	float rh=*p_humidity;             // rh:      12位 湿度 
	float t=*p_temperature;           // t:       14位 温度
	float rh_lin;                     // rh_lin: 湿度 linear值
	float rh_true;                    // rh_true: 湿度 ture值
	float t_C;                        // t_C   : 温度 ℃

	t_C=t*0.01 - 40;                  //补偿温度
	rh_lin=-0.0000028*rh*rh + 0.0405*rh - 4;     //相对湿度非线性补偿
	rh_true=rh/33;   
	if(rh_true>26)
		rh_true=rh/33+1;
	if(rh_true>33)
		rh_true=rh/33+1.5;
	if(rh_true>40)
		rh_true=rh/33+3;	
	if(rh_true>50)
		rh_true=rh/33+3.7;	
	if(rh_true>70)
		rh_true=rh/33+3;	
	if(rh_true>90)
		rh_true=rh/33+1.6;	

    //rh_true=(t_C-25)*(0.01+0.00008*rh)+rh_lin;   //相对湿度对于温度依赖性补偿	,仿真的时候去掉补偿

		
	if(rh_true>100)rh_true=100;       //湿度最大修正
	if(rh_true<0.1)rh_true=0.1;       //湿度最小修正

	*p_temperature=t_C;               //返回温度结果
	*p_humidity=rh_true;              //返回湿度结果


}


void Covert_HT()
{
	value humi_val,temp_val;		//定义两个共同体,一个用于湿度,一个用于温度
	uchar checksum;			//CRC	 
	uchar error=0;
	error=0;					   //初始化error=0,即没有错误
	error+=SHTXX_measure((unsigned char*)&temp_val.i,&checksum,TEMP); //温度测量
	error+=SHTXX_measure((unsigned char*)&humi_val.i,&checksum,HUMI); //湿度测量
	if(error!=0) SHTXX_Init();                 如果发生错误,系统复位
	else
	{ 
		humi_val.f=(float)humi_val.i;                   //转换为浮点数
 		temp_val.f=(float)temp_val.i;                   //转换为浮点数
 		SHTXX_calc(&humi_val.f,&temp_val.f);            //修正相对湿度及温度
		
		real_tempure =temp_val.f+1;	   //修正一下偏
		real_humi    = humi_val.f-1;

		if(real_tempure>=0)
		{
  		TEMP_BUF[0]=real_tempure/100+'0';     		//温度百位
		
		if (TEMP_BUF[0]==0x30) TEMP_BUF[0]=0x20;
		TEMP_BUF[1]=real_tempure%100/10+'0';     	//温度十位	
		if (TEMP_BUF[1]==0x30 && TEMP_BUF[0]==0x30) TEMP_BUF[1]=0x20;
		TEMP_BUF[2]=real_tempure%10+'0';			//温度个位 
		
		}
		else  //负温度
		{
			TEMP_BUF[0]	='-';
			TEMP_BUF[1]=(real_tempure*(-1))%100/10+'0';     	//温度十位	
			if (TEMP_BUF[1]==0x30 && TEMP_BUF[0]==0x30) TEMP_BUF[1]=0x20;
			TEMP_BUF[2]=(real_tempure*(-1))%10+'0';			//温度个位
			
		}		
		TEMP_BUF[3]=0xdf;
		TEMP_BUF[4]=0x43;
		HUMI_BUF[0]=real_humi/100+'0';     		//湿度百位
  		if (HUMI_BUF[0]==0x30) HUMI_BUF[0]=0x20;
		HUMI_BUF[1]=real_humi%100/10+'0';     	//湿度十位	
		if (HUMI_BUF[1]==0x30 && HUMI_BUF[0]==0x30) HUMI_BUF[1]=0X20;  
		HUMI_BUF[2]=real_humi%10+'0';			//湿度个位
		HUMI_BUF[3]= '%';

	}
}

void main()
{
	LCD_Initial();
    SHTXX_Init();			   //启动连接复位
	LCD_Print(0,0,"HUMI:        "); 
	LCD_Print(0,1,"TEMP:    C   "); 

	while(1)
	{	
		Covert_HT();
	  LCD_Print(5,1,TEMP_BUF);
		LCD_Print(5,0,HUMI_BUF);
		Delay(10);

	} 
} 



关注公众号 👇👇👇 获取更多设计资料 

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: DHT11温湿度检测器是一款常见的温湿度传感器,可以用于测量环境中的温度和湿度。基于51单片机的Proteus仿真代码是指通过使用51单片机(一种微控制器)和Proteus(一种电路仿真软件)来模拟DHT11温湿度检测器的工作原理和功能。 在Proteus中仿真DHT11温湿度检测器,首先需要将51单片机与DHT11传感器进行连接。通常,DHT11传感器具有三个引脚:VCC、DATA和GND。其中,VCC用于供电,DATA用于数据传输,GND用于接地。将这些引脚与51单片机的相应引脚进行连接。 接下来,需要编写51单片机的代码,使其能够通过DATA引脚与DHT11传感器进行通信,并读取温湿度信息。具体的代码实现可以使用C语言来编写。代码的主要思路是通过51单片机发送特定的信号给DHT11传感器,并读取传感器返回的温湿度数据。 在代码中,需要定义相应的引脚和变量,以及编写相关的函数,如发送信号函数、读取数据函数等。这些函数将帮助实现与DHT11传感器的通信,并将获取的温湿度数据存储到变量中。 最后,在Proteus中运行该代码,并观察仿真结果。可以通过监测51单片机输出的温湿度数据是否正确来验证代码的正确性。如果仿真结果符合预期,则说明基于51单片机的Proteus仿真代码成功模拟了DHT11温湿度检测器的工作原理和功能。 总而言之,基于51单片机的Proteus仿真代码可以通过在Proteus中连接DHT11传感器并编写相应的代码来模拟DHT11温湿度检测器的工作原理和功能,并通过观察仿真结果来验证代码的正确性。 ### 回答2: DHT11温湿度检测器是一种常见的传感器,用于测量周围环境的温度和湿度。在基于51单片机的Proteus仿真中,我们可以通过编写相应的代码来模拟这个过程。 首先,我们需要添加51单片机和DHT11传感器模块到Proteus的电路设计中。然后,我们可以开始编写代码。 首先,我们需要定义引脚的连接关系,即将数据线连接到51单片机的相应引脚上。通过查询DHT11的规格手册,我们可以确定数据线连接到单片机的哪个引脚上。 接下来,我们可以编写主程序来获取温湿度数据。程序首先需要对DHT11进行初始化,然后通过发送开始信号来触发温湿度测量。然后,程序读取传感器发送的数据,解析温度和湿度数值。最后,将获取的温湿度数据显示出来。 在编程过程中,我们需要使用51单片机的相应的端口设置输入和输出,并使用基本的串行通信协议(如UART)来与DHT11传感器进行通信。 在Proteus仿真中,我们可以通过编写代码并连接相应的电路组件来模拟整个过程。我们可以进行仿真运行,并观察在仿真界面上显示的温湿度数值,以验证代码的正确性。 综上所述,基于51单片机的Proteus仿真中,可以通过编写相应的代码来模拟DHT11温湿度检测器的工作过程。使用合适的引脚连接和相应的数据交互协议,我们可以获取并显示温湿度数据。 ### 回答3: DHT11温湿度检测器是一款常用的温湿度传感器,可用于测量周围环境的温度和湿度。在这个仿真实验中,我们采用Proteus软件来模拟51单片机的工作,并使用DHT11传感器来实时测量温湿度。 首先,我们需要在Proteus中搭建51单片机仿真环境。选择一个适合的51单片机模型,并连接相应的外部晶振和电源电压。然后,在引脚配置中将DHT11的数据引脚连接到51单片机的某一个IO口上。 接下来,我们需要编写51单片机的代码。首先,定义相应的宏和引入头文件,如下所示: #include <reg51.h> #define DHT11_IO P1 然后,我们需要编写相应的函数来控制DHT11传感器。首先是发送开始信号的函数: void send_start_signal() { DHT11_IO = 0; // 将数据引脚置低 delay_ms(18); // 延时18ms DHT11_IO = 1; // 将数据引脚置高 delay_us(30); // 延时30us while(DHT11_IO); // 等待DHT11响应 while(!DHT11_IO); // 等待DHT11开始信号 } 然后是读取传感器数据的函数: unsigned char read_data() { unsigned char i, j, data = 0; for(i = 0; i < 8; i++) { while(!DHT11_IO); // 等待数据位开始 delay_us(40); // 延时40us if(DHT11_IO) { j = 1; while(DHT11_IO); // 等待1的结束 } else { j = 0; while(!DHT11_IO); // 等待0的结束 } data = (data << 1) | j; // 将数据添加到data变量中 } return data; } 最后,我们需要在主函数中调用相应的函数来实现温湿度的测量。首先发送开始信号,然后读取湿度和温度数据,并将其保存到相应的变量中,如下所示: void main() { unsigned char temp, humi; send_start_signal(); // 发送开始信号 humi = read_data(); // 读取湿度数据 temp = read_data(); // 读取温度数据 // 在这里可以对温湿度数据进行处理和显示 } 通过上述代码,我们可以实现在Proteus中对DHT11温湿度检测器进行仿真。当仿真运行时,可以通过读取温湿度数据,并进行相应的处理和显示。这样,我们就可以仿真出DHT11温湿度检测器的基于51单片机的工作原理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

电子开发圈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值