SHT11是瑞士Sensirion公司推出的基于CMOSensTM技术的新型温湿度传感器。该传感器将CMOS芯片技术与传感器技术结合起来,从而发挥出它们强大的优势互补作用。
一、SHT11温湿度传感器的主要特性如下:
●将温湿度传感器、信号放大调理、A/D转换、I2C总线接口全部集成于一芯片(CMOSensTM技术);
●可给出全校准相对湿度及温度值输出;
●带有工业标准的I2C总线数字输出接口;
●具有露点值计算输出功能;
●具有卓越的长期稳定性;
●湿度值输出分辨率为14位,温度值输出分辨率为12位,并可编程为12位和8位;
●小体积(7.65×5.08×23.5mm),可表面贴装;
●具有可靠的CRC数据传输校验功能;
●片内装载的校准系数可保证100%互换性;
●电源电压范围为2.4~5.5V;
●电流消耗,测量时为550μA,平均为28μA,休眠时为3μA。
二 SHT11温湿度传感器采用SMD(LCC)表面贴片封装形式,其引脚说明如下:(1)GND:接地端;(2)DATA:双向串行数据线;(3)SCK:串行时钟输入;(4)VDD电源端:0.4~5.5V电源
端;(5~8)NC:空管脚。
SHT11与LM8962开发板的连接图如下:
1脚接到GND上,2脚接到LM3S8962的I2CSDA上,即PB3管脚,3脚接到LM3S8962的I2CSCl上,即PB2管脚上,4管脚接到+3.3V电源上。
三、SHT11的内部结构和工作原理
温湿度传感器SHT11将温度感测、湿度感测、信号变换、A/D转换和加热器等功能集成到一个芯片上,其内部结构如图2所示。该芯片包括一个电容性聚合体湿度敏感元件和一个用能隙材料制成的温度敏感元件。这两个敏感元件分别将湿度和温度转换成电信号,该电信号首先进入微弱信号放大器进行放大;然后进入一个14位的A/D转换器;最后经过二线串行数字接口输出数字信号。SHT11在出厂前都会在恒湿或恒温环境巾进行校准,校准系数存储在校准寄存器中;在测量过程中,校准系数会自动校准来自传感器的信号。此外,SHT11内部还集成一个加热元件,加热元件接通后能将SHT11的温度升高5℃左右,同时功耗也会有所增加。此功能主要为了比较加热前后的温度和湿度值,能综合验证两个传感器元件的性能。在高湿(>95%RH)环境中,加热传感器可预防传感器结露,同时缩短响应时间,提高精度。加热后SHT11温度升高、相对湿度降低,较加热前,测量值会略有差异。
微处理器是通过二线串行数字接口和SHT11进行通信的。通信协议和通用的I2C总线协议是不兼容的,因此需要用通用微处理器I/O口模拟该通信时序。微处理器对SHT11的控制是通过5个5位命令代码来实现的,命令代码的含义如下表所列:
微处理器和温湿度传感器通信采用串行二线接口SCK和DATA,其中SCK为时钟线,DATA为数据线。该二线串行通信协议和I2C协议是不兼容的。在程式开始,微处理器需要用一组"启动传输"时序表示数据
传输的启动,如下图所示。当SCK时钟为高电平时,DATA翻转为低电平;紧接着SCK变为低电平,随后又变为高电平;在SCK时钟为高电平时,DATA再次翻转为高电平。
四、 SHT11驱动函数:
//1、宏定义,SDA接到PB3,SCL接到PB2上。
#define SHT1x_SDA_SYSCTL SYSCTL_PERIPH_GPIOB
#define SHT1x_SDA_GPIO_PORT GPIO_PORTA_BASE
#define SHT1x_SDA_PIN GPIO_PIN_3
#define SHT1x_SCL_SYSCTL SYSCTL_PERIPH_GPIOB
#define SHT1x_SCL_GPIO_PORT GPIO_PORTA_BASE
#define SHT1x_SCL_PIN GPIO_PIN_2
//控制命令,SHT1x地址位均为 000 地址位 命令 R/W
#define SHT1x_CMD_STATUS_REG_W 0x06 //000 0011 0
#define SHT1x_CMD_STATUS_REG_R 0x07 //000 0011 1
#define SHT1x_CMD_GET_TEMP 0x03 //000 0001 1
#define SHT1x_CMD_GET_HUMI 0x05 //000 0010 1
#define SHT1x_CMD_RESET 0x1E //000 1111 0
//ACK为低电平有效
#define SHT1x_ACK_YES 0x01
#define SHT1x_ACK_NO 0x00
#define SHT1x_CALC_TEMP 0x01
#define SHT1x_CALC_HUMI 0x02
2、GPIO口初始化函数
static void init_sht1x_dev_pin(void)
{
SysCtlPeripheralEnable(SHT1x_SDA_SYSCTL);
GPIODirModeSet(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, GPIO_DIR_MODE_OUT);
GPIOPadConfigSet(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
SysCtlPeripheralEnable(SHT1x_SCL_SYSCTL);
GPIODirModeSet(SHT1x_SCL_GPIO_PORT, SHT1x_SCL_PIN, GPIO_DIR_MODE_OUT);
GPIOPadConfigSet(SHT1x_SCL_GPIO_PORT, SHT1x_SCL_PIN, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
set_sht1x_sda_output();
}
//设置SCL为0或1
static void set_sht1x_scl(char flag)
{
if (0 == flag) {
GPIOPinWrite(SHT1x_SCL_GPIO_PORT, SHT1x_SCL_PIN, ~SHT1x_SCL_PIN);
} else if (1 == flag) {
GPIOPinWrite(SHT1x_SCL_GPIO_PORT, SHT1x_SCL_PIN, SHT1x_SCL_PIN);
}
}
//设置DSA为0或1
static void set_sht1x_sda(char flag)
{
if (0 == flag) {
GPIOPinWrite(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, ~SHT1x_SDA_PIN);
} else if (1 == flag) {
GPIOPinWrite(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, SHT1x_SDA_PIN);
}
}
读取SDA
static int read_sht1x_sda(void)
{
int proc_result = -1;
unsigned char tmp_data;
set_sht1x_sda_input();
tmp_data = GPIOPinRead(SHT1x_SDA_GPIO_PORT,SHT1x_SDA_PIN);
if (SHT1x_SDA_PIN == tmp_data) {
proc_result = 1;
} else {
proc_result = 0;
}
set_sht1x_sda_output();
return (proc_result);
}
static void set_sht1x_sda_output(void)
{
GPIODirModeSet(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, GPIO_DIR_MODE_OUT);
GPIOPadConfigSet(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
}
static void set_sht1x_sda_input(void)
{
GPIODirModeSet(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, GPIO_DIR_MODE_IN);
GPIOPadConfigSet(SHT1x_SDA_GPIO_PORT, SHT1x_SDA_PIN, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD);
}
//读SHT11状态
int read_sht1x_status(unsigned char *p_value,unsigned char *p_checksum)
{
int proc_result = -1;
unsigned char read_st,read_checksum;
//启动操作
start_sht1x_op();
//写入读取命令
proc_result = write_sht1x_byte(SHT1x_CMD_STATUS_REG_R);
//读取状态
proc_result = read_sht1x_byte(&read_st,SHT1x_ACK_YES);
//读取校验值
proc_result = read_sht1x_byte(&read_checksum,SHT1x_ACK_NO);
*p_value = read_st;
*p_checksum = read_checksum;
return (proc_result);
}
写SHT11状态
int write_sht1x_status(unsigned char value)
{
int proc_result = 0;
//启动操作
start_sht1x_op();
proc_result += write_sht1x_byte(SHT1x_CMD_STATUS_REG_W);
proc_result += write_sht1x_byte(value);
return (proc_result);
}
//SHT11复位
void reset_sht1x_connect(void)
{
int i;
set_sht1x_sda(1);delay_sht1x_bus(1);
set_sht1x_scl(0);delay_sht1x_bus(1);
for (i = 0; i < 9; i++) {
set_sht1x_scl(1);delay_sht1x_bus(1);
set_sht1x_scl(0);delay_sht1x_bus(1);
}
start_sht1x_op();
}
//软件复位
int reset_sht1x_software(void)
{
int proc_result = -1;
reset_sht1x_connect();
proc_result = write_sht1x_byte(SHT1x_CMD_RESET); //需要11ms
return (proc_result);
}
//写一字节
int write_sht1x_byte(unsigned char in_data)
{
int proc_result = -1;
int i;
for (i = 0; i < 8; i++) {
if (0x80 == (in_data & 0x80)) {
//High
set_sht1x_sda(1);
} else {
set_sht1x_sda(0);
}
delay_sht1x_bus(1);
in_data = (in_data << 1);
set_sht1x_scl(1);
delay_sht1x_bus(1);
set_sht1x_scl(0);
}
//释放总线
set_sht1x_sda(1);
//给出上升沿,读入ACK
set_sht1x_scl(1);
proc_result = read_sht1x_sda();
if (1 == proc_result) {
//无效ACK信号
proc_result = -1;
}
set_sht1x_scl(0);
return (proc_result);
}
//读一字节
int read_sht1x_byte(unsigned char *p_out_data,unsigned char ack)
{
int proc_result = -1;
int i;
unsigned char tmp_data;
tmp_data = 0x00;
for (i = 0; i < 8; i++) {
tmp_data = (tmp_data << 1);
set_sht1x_scl(1);
delay_sht1x_bus(1);
proc_result = read_sht1x_sda();
if (1 == proc_result) {
tmp_data |= 0x01;
}
set_sht1x_scl(0);
delay_sht1x_bus(1);
}
*p_out_data = tmp_data;
proc_result = read_sht1x_sda();
if (1 == proc_result) {
//没有ACK信号
proc_result = -1;
}
//释放总线
set_sht1x_scl(1);delay_sht1x_bus(1);
set_sht1x_scl(0);delay_sht1x_bus(1);
set_sht1x_sda(1);delay_sht1x_bus(1);
return (proc_result);
}
//启动SHT11
static void start_sht1x_op(void)
{
//初始状态
set_sht1x_sda(1); delay_sht1x_bus(1);
set_sht1x_scl(0); delay_sht1x_bus(1);
//第一个时钟上升沿后数据变为低
set_sht1x_scl(1); delay_sht1x_bus(1);
set_sht1x_sda(0); delay_sht1x_bus(1);
//时钟下降沿后时钟上升沿
set_sht1x_scl(0); delay_sht1x_bus(1);
set_sht1x_scl(1); delay_sht1x_bus(1);
//数据变为高,时钟下降沿
set_sht1x_sda(1); delay_sht1x_bus(1);
set_sht1x_scl(0); delay_sht1x_bus(1);
//计算温湿度
int calc_sht1x_value(int mode,t_dev_sht1x *p_this)
{
int proc_result = -1;
const float T1 = 0.01;
const float T2 = 0.00008;
float c1 = -4;
float c2 = 0.0405;
float c3 = -0.0000028;
float rh;
float t;
float rh_lin;
float rh_true;
float t_c;
float logex,dew_point;
//计算温湿度
rh = p_this->humi;
t = p_this->temp;
t_c = t*0.01 - 39.6; //12bit 0.04 14bit 0.01
rh_lin = c3*rh*rh + c2*rh + c1;
rh_true = (t_c - 25)*(T1 + T2*rh) + rh_lin;
if (rh_true > 100) {
rh_true = 100;
} else if (rh_true < 0.1) {
rh_true = 0.1;
}
p_this->temp_value = t_c;
p_this->humi_value = rh_true;
return (proc_result);
}
//读取结果
int get_sht1x_result(int mode,unsigned short *p_value,unsigned char *p_check_sum)
{
int proc_result = 0;
int i;
static unsigned char read1,read2; //optimize
static unsigned short result_value;
//启动操作
start_sht1x_op();
//获取传感器测量数值
switch (mode) {
case SHT1x_CALC_TEMP:
proc_result += write_sht1x_byte(SHT1x_CMD_GET_TEMP);
break;
case SHT1x_CALC_HUMI:
proc_result += write_sht1x_byte(SHT1x_CMD_GET_HUMI);
break;
default:
proc_result = -1;
break;
}
//等待测量完成
for(i = 0; i < 65535; i++) {
delay_sht1x_bus(1);
proc_result = read_sht1x_sda();
if (0 == proc_result) {
//得到传感器响应
break;
}
}
if (1 == proc_result) {
//超时后传感器仍未响应
proc_result = -1;
}
read1 = 0;
read2 = 0;
proc_result += read_sht1x_byte(&read1,SHT1x_ACK_YES); //MSB
//read1 = (read1 & 0x0F);
proc_result += read_sht1x_byte(&read2,SHT1x_ACK_YES); //LSB
result_value = read1;
result_value = (result_value << 8);
result_value = (result_value | read2);
*p_value = result_value;
proc_result += read_sht1x_byte(&read1,SHT1x_ACK_NO);
*p_check_sum = read1;
return (proc_result);
}