1、SHT1x (包括 SHT10, SHT11 和 SHT15) 属于Sensirion温湿度传感器家族中的贴片封装系列。传感器将传感元件和信号处理电路集成在一块微型电路板上,输出完全标定的数字信号。传感器具有体积小、响应速度快、接口简单、性价比高等特点。
传感器接口定义如下:
SHT10的供电电压范围为2.4v-5.5v,建议供电电压为3.3v。SHT1x的串行接口,在传感器信号的读取及电源损耗方面,都做了优化处理;传感器不能按照I2C协议编址,但是如果I2C总线上没有挂接别的元件,传感器可以连接到I2C总线上,但单片机必须按照传感器的协议工作。
串行时钟输入(SCK): SCK 用于单片机与SHT10之间的通讯同步。
串行数据(DATA):DATA引脚为三态结构,用于读取传感器数据。当向传感器发送命令时, DATA在SCK上升沿有效且在SCK高电平时必须保持稳定,DATA在SCK下降沿之后改变。
传感器的通讯如下:
后续命令包含三个地址位(目前只支持“000”),和五个命令位。SHT1x会以下述方式表示已正确地接收到指令:在第8个SCK时钟的下降沿之后,将DATA下拉为低电平(ACK 位)。在第9个SCK时钟的下降沿之后,释放DATA(恢复高电平)。命令集如下:
信号转换:
RHlinear = C1 + C2 * SORH + C3 * SORH2(%RH)
公式参数如下:
RHtrue = (T℃ - 25) *(t1 + t2 * SORH) + RHlinear
公式参数如下:
T = d1+d2 * SOT
公式参数如下:
4、 Sensor_Humidity.c
#include "sensor_humidity.h"
// 开始传输信号
static void SHT10_Start(void)
{
SHT10_SDA_H; // 将数据线拉高
SHT10_SCK_L; // 将信号线拉低
SHT10_DELAY_1US(); // 延时1us
SHT10_SCK_H;
SHT10_DELAY_1US();
SHT10_SDA_L;
SHT10_DELAY_1US();
SHT10_SCK_L;
SHT10_DELAY_1US();
SHT10_SCK_H;
SHT10_DELAY_1US();
SHT10_SDA_H;
SHT10_DELAY_1US();
SHT10_SCK_L;
SHT10_DELAY_1US();
}
// 通讯复位
static void SHT10_Reset(void)
{
SHT10_SDA_H;
SHT10_SCK_L;
for(uint8_t i=0; i<9; i++) // 触发SCK时钟9次
{
SHT10_SCK_H;
SHT10_DELAY_1US();
SHT10_SCK_L;
SHT10_DELAY_1US();
}
}
// 引脚初始化
void SHT10_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); // 使能时钟
GPIO_InitStructure.GPIO_Pin = Pin_SCK | Pin_SDA; // 传感器对应IO口
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; // 开漏模式
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3; // 50MHZ
GPIO_Init(SHT10_GPIOx, &GPIO_InitStructure); // 初始化GPIO
SHT10_Reset(); // 传感器复位
}
// 向传感器写1字节
uint8_t SHT10_WriteByte(uint8_t value)
{
uint8_t state = ERR_NONE;
for(uint8_t i=0; i<8; i++) // 写一个字节
{
if(value&0x80)
SHT10_SDA_H;
else
SHT10_SDA_L;
SHT10_DELAY_1US();
SHT10_SCK_H;
SHT10_DELAY_1US();
SHT10_DELAY_1US();
SHT10_SCK_L;
SHT10_DELAY_1US();
value <<= 1;
}
SHT10_SCK_H;
SHT10_DELAY_1US();
if(Read_SDA_Pin) // 读取SHT10的应答位
{
state = ERR_NO_ACK;
}
SHT10_SCK_L;
SHT10_DELAY_1US();
return state;
}
// 从传感器中读1字节数据
uint8_t SHT10_ReadByte(uint8_t Ack)
{
uint8_t val = 0;
for(uint8_t i=0; i<8; i++) // 读取1字节数据
{
val <<= 1;
SHT10_SCK_H;
SHT10_DELAY_1US();
if(Read_SDA_Pin)
val |= 1;
SHT10_SCK_L;
SHT10_DELAY_1US();
}
if(Ack)
SHT10_SDA_L;// 应答,则会接受后面的数据(校验数据)
else
SHT10_SDA_H; // 不应答
SHT10_DELAY_1US();
SHT10_SCK_H;
SHT10_DELAY_1US();
SHT10_SCK_L;
SHT10_DELAY_1US();
SHT10_SDA_H;
return val;
}
// 从温湿度传感器读取温湿度
uint8_t SHT10_Measure(uint8_t cmd, uint16_t *p_value)
{
uint8_t status = ERR_NONE;
// 开始传输
SHT10_Start();
// 写测量命令
if(SHT10_WriteByte(cmd) == ERR_NO_ACK)
{
SHT10_Reset();
status = ERR_NO_ACK;
return status;
}
// 等待DATA信号被拉低,正常应该在320ms内测量完成
for(uint32_t i = 0; i < 72000000; i++)
{
if(!(Read_SDA_Pin)) break; // 检测到DATA被拉低了,跳出循环
}
// 检查转换完成状态
if(Read_SDA_Pin) // 如果等待超时了
{
SHT10_Reset();
status = ERR_TIME_OUT;
return status;
}
else // 完成测量
{
uint8_t value_H = SHT10_ReadByte(ACK); // 读取高8位数据
uint8_t value_L = SHT10_ReadByte(ACK); // 读取低8位数据
uint8_t checksum = SHT10_ReadByte(NO_ACK); // 读取校验数据
// if(checksum) // 校验不正确
// {
// status = ERR_CHECK_NUM;
// }
*p_value = (value_H << 8) | value_L;
}
return status;
}
// 计算温湿度的值
void SHT10_Calculate(uint16_t SOt, uint16_t SOrh, float* T, float* RH)
{
const float C1=-2.0468f; // 12 Bit
const float C2= 0.0367f; // 12 Bit
const float C3=-1.5955e-6f; // 12 Bit
const float t1=0.01f; // 12 Bit
const float t2=0.00008f; // 12 Bit
const float d1=-39.6f; // for 3v
const float d2= 0.01f; // for 14 Bit
*T = d1 + d2 * SOt; // 计算温度值
float RH_Linear = C1 + C2 * SOrh + C3 * SOrh * SOrh; // 计算湿度值
*RH = (*T - 25) * (t1 + t2 * SOrh) + RH_Linear; // 湿度的温度补偿,计算实际的湿度值
}
// 计算露点
void SHT10_CalDewPoint(float T, float RH, float* Td)
{
// RH = 10^((7.45*td)/(235+td)) / 10^((7.45*t)/(235+t))
// float x = log10(pow(10, (7.45f * T) / (235 + T)) * RH*0.01f);
// *Td = x * 235 / (7.45f - x);
float Tn = T>=0 ? 243.12f : 272.62;
float m = T>=0 ? 17.62f : 22.46;
float a = log(RH / 100.f);
float b = (m * T) / (Tn + T);
*Td = Tn * (a + b) / (m - a -b);
}
// 测量温湿度及露点
uint8_t SHT10_GetMessure(float *T , float *RH, float* Td)
{
uint16_t SOt, SOrh;
uint8_t status_temp = SHT10_Measure(MEASURE_TEMP, &SOt);
uint8_t status_humi = SHT10_Measure(MEASURE_HUMI, &SOrh);
if(status_temp == ERR_NONE && status_humi == ERR_NONE)
{
SHT10_Calculate(SOt, SOrh, T, RH); // 计算得到温度、湿度
SHT10_CalDewPoint(*T, *RH, Td); // 计算出露点值,并且返回
}
return status_temp | status_humi;
}
5、Sensor_Humidity.h
#ifndef _SENSOR_HUMIDITY_H_
#define _SENSOR_HUMIDITY_H_
#include "stm32f0xx.h"
#include "bsp_systick.h"
#include
#include
enum {TEMP, HUMI};
// 定义内联延时函数
static inline void SHT10_DELAY_1US(void)
{
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}
#define SHT10_GPIOx GPIOB
#define Pin_SCK GPIO_Pin_10
#define Pin_SDA GPIO_Pin_11
#define SHT10_SCK_L SHT10_GPIOx->ODR &= ~Pin_SCK
#define SHT10_SCK_H SHT10_GPIOx->ODR |= Pin_SCK
#define SHT10_SDA_L SHT10_GPIOx->ODR &= ~Pin_SDA
#define SHT10_SDA_H SHT10_GPIOx->ODR |= Pin_SDA
#define Read_SDA_Pin SHT10_GPIOx->IDR & Pin_SDA
#define NO_ACK 0
#define ACK 1
#define ERR_NONE 0
#define ERR_TIME_OUT 1
#define ERR_NO_ACK 2
#define ERR_CHECK_NUM 4
#define STATUS_REG_W 0x06 // 写状态寄存器
#define STATUS_REG_R 0x07 // 读状态寄存器
#define MEASURE_TEMP 0x03 // 测量温度
#define MEASURE_HUMI 0x05 // 测量湿度
#define SOFTRESET 0x1E // 复位
void SHT10_Init(void);
uint8_t SHT10_GetMessure(float *T , float *RH, float* Td);
#endif
5、主函数
float RH; // 湿度值变量
float T; // 温度值变量
float Td; // 露点值变量
int main()
{
SYSTICK_Init(1); // 滴答定时器初始化
SHT10_Init(); // 传感器初始化
USART1_Init(); // 串口初始化
while(1)
{
if(SHT10_GetMessure(&T ,&RH, &Td) == ERR_NONE) //读取露点
{
printf("T: %.2f RH: %.2f Td: %.2f \r\n",T, RH, Td);
}
SYSTICK_DelayMs(500);
}
}