仿真所用的湿度传感器为SHT11。SHT11是瑞士Scnsirion公司推出的一款数字温湿度传感器芯片。该芯片广泛应用于暖通空调、汽车、消费电子、自动控制等领域。
其主要特点如下:
高度集成,将温度感测、湿度感测、信号变换、A/D转换和加热器等功能集成到一个芯片上;
提供二线数字串行接口SCK和DATA,接口简单,支持CRC传输校验,传输可靠性高;
测量精度可编程调节,内置A/D转换器(分辨率为8~12位,可以通过对芯片内部寄存器编程米选择);
引脚 | 名称 | 功能 |
1 | GND | 地线 |
2 | DATA | 串行数据线 |
3 | SCK | 串行时钟线 |
4 | VDD | 电源正 |
NC | NC | 悬空 |
传输启动
数据传输初始化:
当SCK时钟为高电平时,DATA翻转位低电平,紧接着SCK变为低电平,
随后在SCK时钟高电平时,DATA翻转为高电平。
void start_sht11(void) //启动
//--------------------------------------------------------
{
DATA=1; SCK=0; //数据为1,SCK=0
_nop_();
SCK=1; //第一个脉冲
_nop_();
DATA=0; //数据跌落
_nop_ ();
SCK=0; //完成一个脉冲
_nop_(); _nop_(); _nop_();
SCK=1; //再一个脉冲
_nop_();
DATA=1; //数据变为1
_nop_();
SCK=0; //完成该脉冲
}
读写数据
控制器向传感器发送命令的过程中,DATA在SCK上升沿有效,且在SCK高电平时必须保持稳定;DATA在SCK下降沿之后改变。(参考上图 DATA valid write 段)
从传感器读取数据读取数据的过程中,DATA Tv在SCK变低以后有效,且维持到下一个SCK的下降沿。(参考上图 DATA valid read 段)
char read(void) //读一个字节 返回应答信号
//----------------------------------------------------------------------------------
// reads a byte form the Sensibus and gives an acknowledge in case of "ack=1"
{
unsigned char i,val=0;
temp_LL=0;
temp_h=0;
DATA=1; //释放数据总线
for (i=0x80;i>0;i/=2) //位移8位
{
SCK=1; //上升沿读入
if (DATA) val=(val | i); //确定值
SCK=0;
}
DATA=0; //读应答信号,有应答为1,为应答为0 通过CPU下拉为应答
SCK=1; //第9个脉冲
_nop_(); _nop_(); _nop_(); //pulswith approx. 5 us
SCK=0;
DATA=1; //释放数据总线
temp_h=val;
val=0;
////低8位/////////////////////////////
DATA=1; //释放数据总线
for (i=0x80;i>0;i/=2) //位移8位
{
SCK=1; //上升沿读入
if (DATA) val=(val | i); //确定值
SCK=0;
}
DATA=1;//0; //不需要应答 通过CPU下拉为应答
SCK=1; //第9个脉冲
_nop_(); _nop_(); _nop_(); //pulswith approx. 5 us
SCK=0;
DATA=1; //释放数据总线
temp_LL=val;
return val ;
}
////////////
char write(unsigned char value) //写一个字节 返回应答信号
//---------------------------------------------------------
{
unsigned char i ;
ack=0;
for (i=0x80;i>0;i/=2) //释放数据总线
{ if (i & value) DATA=1; //写入值
else DATA=0;
SCK=1; //上升沿写入
_nop_(); _nop_(); _nop_(); //延时
SCK=0;
}
DATA=1; //释放数据总线
SCK=1; //第9个脉冲
if (DATA==1) ack=1; //读应答信号
SCK=0;
return ack; //error=1 表示没有应答
}
传感器复位
如果出现通讯中断,当DATA保持高电平时,触发SCK时钟9次或更多,然后发送“传输启动”时序就可以完成传感器的复位。
//////////////////////////////////
void sht_rest(void) //复位
{
unsigned char i;
DATA=1; SCK=0; //数据为1 时钟为0
for(i=0;i<9;i++) //9 个脉冲为 复位
{ SCK=1;
SCK=0;
}
start_sht11(); //启动
}
Proteus仿真如下图。主要功能是利用SHT11进行湿度的采集,并通过LCD1602显示。在仿真中通过SHT11上面的操作按钮就可以改变SHT11的温度和湿度数值。该仿真没有对温度数据进行采集和现实。
完整的程序如下
#include
#include
#define uint unsigned int
#define uchar unsigned char
/*------------------------------------------------
硬件端口定义
------------------------------------------------*/
sbit RS = P2^0; //定义端口
sbit RW = P2^1;
sbit EN = P2^2;
sbit LED = P2^4 ;
sbit RELAY = P1^0 ;
#define DataPort P0
sbit DATA =P2^6; //数据
sbit SCK=P2^7; //时钟
uchar cnt = 0 ;
unsigned char temp_h ; //全局应答变量
unsigned char temp_LL ;//全局应答变量
unsigned char error ; //全局错误变量
unsigned char ack ; //全局应答变量
#define RS_CLR RS=0
#define RS_SET RS=1
#define RW_CLR RW=0
#define RW_SET RW=1
#define EN_CLR EN=0
#define EN_SET EN=1
#define TEMP_ML 0x03 //000 0001 1 温度命令
#define HUMI_ML 0x05 //000 0010 1 温度命令
unsigned int xianzhi_h=0;//湿度显值
uchar key ;
uchar key_buf ;
uchar temp ;
uchar frq_cnt = 0;
bit updat = 0 ;
uchar delay_cnt = 0 ;
#define TH0_BUF 0x3c
#define TL0_BUF 0xaf
void text_jisuan_humi(void);
/*------------------------------------------------
uS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编,大致延时
长度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{
while(--t);
}
/*------------------------------------------------
mS延时函数,含有输入参数 unsigned char t,无返回值
unsigned char 是定义无符号字符变量,其值的范围是
0~255 这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void DelayMs(unsigned char t)
{
while(t--)
{
//大致延时1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
/*------------------------------------------------
判忙函数
------------------------------------------------*/
bit LCD_Check_Busy(void)
{
DataPort= 0xFF;
RS_CLR;
RW_SET;
EN_CLR;
_nop_();
EN_SET;
return (bit)(DataPort & 0x80);
}
/*------------------------------------------------
写入命令函数
------------------------------------------------*/
void LCD_Write_Com(unsigned char com)
{
// while(LCD_Check_Busy()); //忙则等待
DelayMs(5);
RS_CLR;
RW_CLR;
EN_SET;
DataPort= com;
_nop_();
EN_CLR;
}
/*------------------------------------------------
写入数据函数
------------------------------------------------*/
void LCD_Write_Data(unsigned char Data)
{
//while(LCD_Check_Busy()); //忙则等待
DelayMs(5);
RS_SET;
RW_CLR;
EN_SET;
DataPort= Data;
_nop_();
EN_CLR;
}
/*------------------------------------------------
清屏函数
------------------------------------------------*/
void LCD_Clear(void)
{
LCD_Write_Com(0x01);
DelayMs(5);
}
/*------------------------------------------------
写入字符串函数
------------------------------------------------*/
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0)
{
LCD_Write_Com(0x80 + x); //表示第一行
}
else
{
LCD_Write_Com(0xC0 + x); //表示第二行
}
while (*s)
{
LCD_Write_Data( *s);
s ++;
}
}
/*------------------------------------------------
写入字符函数
------------------------------------------------*/
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{