资讯详情

SHT11源程序分享及51单片机仿真实现

系列文章目录

51单片机SHT使用11温湿度传感器进行模拟


文章目录

  • 系列文章目录
  • 前言
  • 一、SHT11时序
    • 1.传输时序
    • 2.通信复位顺序
    • 发送一个字节
    • 接收一个字节
    • 5.测量温度和湿度
    • 6.温湿度补偿
  • 二、实现仿真
  • 三、代码
  • 四、总结


前言

首先,为了写作,声明SHT11.我走了很多弯路,看了时间序列,参考了在线程序。最后,我花了大约两天的时间来了解如何实现它。虽然有错误,但我还是收获了很多。网上关于这个芯片的代码太少,要么不完整,要么花钱。今天分享以下内容。练习如何通过时间序列图自己写程序真的很难。


一、SHT11时序

1.传输时序

在这里插入图片描述 首先,数据线上升,时钟线下降。然后时钟线上升,数据线下降,时钟线下降,时钟线上升,数据线上升,时钟线下降。

void I2C_Start() { 
          I2C_SDA=1;  I2C_SCL=0;  I2C_SCL=1;  I2C_SDA=0;  I2C_SCL=0;  I2C_SCL=1;  I2C_SDA=1;  I2C_SCL=0; } 

2.通信复位顺序

这也很容易理解

void Reset() { 
          unsigned char i;  I2C_SDA=1;  I2C_SCL=0;  for(i=0;i<9;i )  { 
           I2C_SCL=1;   I2C_SCL=0;  }  I2C_Start(); }  

发送一个字节

首先发送字节(8位数据),然后接收从机响应信号和通常I2C时间顺序相似,但最终响应不同。必须注意的是,当时钟线为低电时,数据线只能在平时更改,即当时钟线下降时,数据线准备数据(这里是主机准备数据)。当时钟线上升时,从机器上读取数据线上的数据

char I2C_SendByte(unsigned char byte) { 
          unsigned char i;  char error=0; I2C_SCL=0; //拉低时钟线,目的是让主机准备数据,数据线只能在时钟为低电平时变化 for(i=0;i<8;i++) { 
          if(byte&(0X80>>i))//主机准备数据 I2C_SDA=1; else I2C_SDA=0; I2C_SCL=1;//从机读取数据,只有在时钟为高电平时,才会读取数据 I2C_SCL=0; } I2C_SDA=1;//主机释放SDA //从机准备应答数据 I2C_SCL=1; error=I2C_SDA;//主机读取应答数据 I2C_SCL=0;//这一点最特殊,这是第9个时钟下降沿 I2C_SDA=1;//从机释放SDA return error; } 

4、接收一个字节

主机接收一个字节,然后主机发送应答信号。接收字节与发送同理。时钟线低电平时,从机准备数据,时钟线高电平时,主机读取数据。

unsigned char I2C_ReceiveByte(bit ACK)
{ 
        
	unsigned char i,byte=0X00;
	I2C_SCL=0;//可加可不加,加上容易理解
	I2C_SDA=1;//主机释放总线,从机准备好数据
	for(i=0;i<8;i++)
	{ 
        
		I2C_SCL=1;
		if(I2C_SDA)//主机读取从机数据
			byte|=(0X80>>i);
		I2C_SCL=0;
	}
	I2C_SDA=ACK;//主机准备好应答数据
	I2C_SCL=1;//从机读取应答数据
	I2C_SCL=0;
	I2C_SDA=1;//主机释放总线,可加可不加
	return byte;
}

5、测量温度湿度

参考前人程序

char s_measure(unsigned char *p_value,unsigned char mode) 
{ 
        
	char error=0;
	unsigned int i; 
	I2C_Start(); 
	 switch(mode)
	{ 
                             //选择发送命令 
    case 0  : error+=I2C_SendByte(0X03); break; 
    case 1  : error+=I2C_SendByte(0X05); break; 
    default     : break;    
    } 
	for (i=0;i<65535;i++) 
		if(I2C_SDA==0)
			break; //等待测量结束,测量温湿度需要时间
  if(I2C_SDA) 
	  error+=1;             // 如果长时间数据线没有拉低,说明测量错误
  *(p_value)  =I2C_ReceiveByte(0);    //读第一个字节,高字节 (MSB) 
  *(p_value+1)=I2C_ReceiveByte(1);    //读第二个字节,低字节 (LSB)
  //这里发送非应答信号,不用CRC校验
   return error; 		
}

6、温湿度补偿

传入两个指针,下面是数据手册公式

void calc_SHT11(float *p_humidity ,float *p_temperature)                                   //const表示常量,不允许修改里面的内容
{ 
         const float C1=-4.0;              // 12位湿度精度 修正公式
  const float C2=+0.0405;           // 12位湿度精度 修正公式
  const float C3=-0.0000028;        // 12位湿度精度 修正公式
  const float T1=+0.01;             // 14位温度精度 5V条件 修正公式
  const float T2=+0.00008;          // 14位温度精度 5V条件 修正公式

  float rh=*p_humidity;             // rh: Humidity 12 Bit 
  float t=*p_temperature;           // t: Temperature 14 Bit
  float rh_lin;                     // rh_lin: Humidity linear
  float rh_true;     // rh_true: Temperature compensated humidity
  float t_C;                   // t_C : Temperature [C]

  t_C=t*0.01 - 40;          //补偿温度,14位温度精度 5V条件 修正公式
  
  rh_lin=C3*rh*rh + C2*rh + C1;     //相对湿度非线性补偿
  rh_true=(t_C-25)*(T1+T2*rh)+rh_lin-3; //相对湿度对于温度依赖性补偿

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

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

二、仿真实现

三、代码

采用模块化编程 //…main.c…//

#include <regx52.h>
#include "LCD1602.h"
#include "I2C.h"
#include <intrins.h>
#include <math.h>
typedef union  		   //定义了两个共用体:如果没有typedef那么就是普通的定义了匿名联合的一个变量value.加了typedef后, 定义的就是类型别名, 当类型一样用
{ 
         
unsigned int i;      //i表示测量得到的温湿度数据(int 形式保存的数据)
  float f; 		//f表示测量得到的温湿度数据(float 形式保存的数据)
} value; 
void delay_n10us(unsigned int n)  //延时n个10us@12M晶振
{ 
               
        unsigned int i;           
        for(i=n;i>0;i--)    
        { 
        
        _nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); 
		}
}
void main(void)
{ 
        
	value humi_val,temp_val;				     //185行,定义两个共同体,一个用于湿度,一个用于温度
	unsigned char error; 			 //用于检验是否出现错误
	unsigned int wendu,shidu;				 //最终,一位小数温湿度的值
	LCD_Init();
	 Reset();  
	while(1)
	{ 
        //int为两个字节,这里没看懂,高字节赋给int低字节什么操作,其他都没问题,看到网上程序全是这么写的
		   error=0; 			 //初始化error=0,即没有错误
           error+=s_measure((unsigned char*) &humi_val.i,1);  //measure humidity 
           error+=s_measure((unsigned char*) &temp_val.i,0);  //measure temperature 
           if(error!=0) 
			   Reset();                 //in case of an error: connection reset 
           else 
            { 
         
             humi_val.f=(float)humi_val.i;                   //converts integer to float
             temp_val.f=(float)temp_val.i;                   //converts integer to float
             calc_SHT11(&humi_val.f,&temp_val.f);            //calculate humidity, temperature
			       
             LCD_ShowString(1,1,"TE:");
             LCD_ShowString(2,1,"RH:");
             LCD_ShowString(1,7,".");
             LCD_ShowString(2,7,".");
             LCD_ShowString(1,9,"C ");
             LCD_ShowString(2,9,"% ");

		     wendu=10*temp_val.f;                            //例如温度109.1→1091
			 
			 LCD_ShowChar(1,4,abs(wendu)/1000+'0');         //显示温度百位,加“0”是为了将字符的ASCII码大于48(即字符0的ASCII值),一般是将数字0,1,2……,9转换为字符“0”,“1”……,“9”; 
			 LCD_ShowChar(1,5,abs(wendu)%1000/100+'0');     //显示温度十位
             LCD_ShowChar(1,6,abs(wendu)%100/10+'0');       //显示温度个位
		     LCD_ShowChar(1,8,abs(wendu)%10+'0');           //显示温度小数点后第一位

			 shidu=10*humi_val.f;
			 LCD_ShowChar(2,4,shidu/1000+'0');               //显示湿度百位
             LCD_ShowChar(2,5,(shidu%1000)/100+'0');         //显示湿度十位
             LCD_ShowChar(2,6,(shidu%100)/10+'0');           //显示湿度个位
			 LCD_ShowChar(2,8,(shidu%10)+'0');               //显示湿度小数点后第一位
		 }
			delay_n10us(800); 
	}
}

//…LCD1602.c…//

#include <reg52.h>
#include <intrins.h>
#define LCD_Bus P0
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
//函数定义:
/** * @brief LCD1602延时函数,12MHz调用可延时1ms * @param 无 * @retval 无 */
void LCD_Delay()
{ 
        
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{ 
        
		while (--j);
	} while (--i);
}
void LCD_WriteCommand(unsigned char command)
{ 
        
	LCD_RS=0;
	LCD_RW=0;
	LCD_EN=0;
	LCD_Bus=command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}
void LCD_WriteData(unsigned char Data)
{ 
        
	LCD_RS=1;
	LCD_RW=0;
	LCD_EN=0;
	LCD_Bus=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}
void LCD_Init()
{ 
        
	LCD_WriteCommand(0x38);
	LCD_WriteCommand(0x06);
	LCD_WriteCommand(0x0c);
	LCD_WriteCommand(0x01);
}
void LCD_SetAddress(unsigned char line,unsigned char column)
{ 
        
	if(line==1)
		LCD_WriteCommand(0X80+column-1);
	else
		LCD_WriteCommand(0X80+0X40+column-1);
}
void LCD_ShowChar(unsigned char line,unsigned char column,char Char)
{ 
        
	LCD_SetAddress(line,column);
	LCD_WriteData(Char);
}
void LCD_ShowString(unsigned char line,unsigned char column,char*String)
{ 
        
	LCD_SetAddress(line,column);
	while(*String!='\0')
	{ 
        
	LCD_WriteData(*String++);
	}
}
int pow(int x,int y)
{ 
        
	int result=1;
	while(y-->0)
	{ 
        
		result*=x;
	}
	return result;
}
void LCD_ShowNumber(unsigned char line,unsigned char column,unsigned int number,unsigned char length)
{ 
        
	unsigned char i;
	LCD_SetAddress(line,column);
	for(i=length;i>0;i--)
	{ 
        
		LCD_WriteData(number/pow(10,i-1)%10+'0');
	}
}

//…LCD1602.h…//

#ifndef __LCD1602_H__
#define __LCD1602_H__
void LCD_Init();
void LCD_ShowChar(unsigned char line,unsigned char column,char Char);
void LCD_ShowString(unsigned char line,unsigned char column,char*String);
void LCD_ShowNumber(unsigned char line,unsigned char column,unsigned int number,unsigned char length);
#endif

//…I2C.c…//

#include <regx52.h>
#include <intrins.h>
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;
#define MEASURE_TEMP 0X03
#define MEASURE_HUMI 0X05
void I2C_Start()
{ 
        
	I2C_SDA=1;
	I2C_SCL=0;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
	I2C_SCL=1;
	I2C_SDA=1;
	I2C_SCL=0;
}
void Reset()
{ 
        
	unsigned char i;
	I2C_SDA=1;
	I2C_SCL=0;
	for(i=0;i<9;i++)
	{ 
        
		I2C_SCL=1;
		I2C_SCL=0;
	}
	I2C_Start();
}
char I2C_SendByte(unsigned char byte)
{ 
        
	unsigned char i;
	char error=0;
	I2C_SCL=0;
	for(i=0;i<8;i++)
	{ 
        
		
		if(byte&(0X80>>i))//主机准备数据
			I2C_SDA=1;
		else
			I2C_SDA=0;
		I2C_SCL=1;//从机读取数据
		I2C_SCL=0;
	}
	I2C_SDA=1;//主机释放SDA
			//从机准备应答数据
	I2C_SCL=1;
	error=I2C_SDA;//主机读取应答数据
	I2C_SCL=0;
	I2C_SDA=1;//从机释放SDA
	return error;
	
}
unsigned char I2C_ReceiveByte(bit ACK)
{ 
        
	unsigned char i,byte=0X00;
	I2C_SDA=1;//主机释放总线
	for(i=0;i<8;i++)
	{ 
        
		I2C_SCL=1;
		if(I2C_SDA
        标签: te511温度lcd显示传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司