基于STM32F030驱动SHT10温湿度传感器

目的

了解温湿度传感器SHT10的驱动原理,通过配置 STM32F030 的GPIO来采集温湿度传感器的温度、湿度和露点的值。

原理

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下降沿之后改变。

传感器的通讯如下:

  • 启动传感器:首先,选择供电电压后将传感器通电,上电速率不能低于1V/ms。通电后传感器需要11ms 进入休眠状态,在此之前不允许对传感器发送任何命令。
  • 发送命令:用一组“启动传输”时序,来完成数据传输的初始化。它包括当SCK 时钟高电平时DATA 翻转为低电平,紧接着SCK变为低电平,随后是在SCK时钟高电平时DATA 翻转为高电平。启动时序如下图:

 后续命令包含三个地址位(目前只支持“000”),和五个命令位。SHT1x会以下述方式表示已正确地接收到指令:在第8个SCK时钟的下降沿之后,将DATA下拉为低电平(ACK 位)。在第9个SCK时钟的下降沿之后,释放DATA(恢复高电平)。命令集如下:

  •  温湿度测量:发布一组测量命令(‘00000101’表示相对湿度RH,‘00000011’表示温度T)后,控制器要等待测量结束。这个过程需要大约20/80/320ms,分别对应8/12/14bit测量。SHT1x 通过下拉DATA至低电平并进入空闲模式,表示测量的结束。控制器在再次触发SCK 时钟前,必须等待这个“数据备妥”信号来读出数据。接着传输2个字节的测量数据和1个字节的CRC 奇偶校验(可选择读取)。控制器需要通过下拉DATA为低电平,以确认每个字节。所有的数据从MSB开始,右值有效(例如:对于12bit 数据,从第5个SCK时钟起算作MSB;而对于8bit 数据,首字节则无意义。默认分辨率:14bit (温度) 和 12bit (湿度)可以被降低为12和8bit. 尤其适用于要求测量速度极高或者功耗极低的应用)。在收到CRC的确认位之后,表明通讯结束。如果不使用CRC-8校验,控制器可以在测量值LSB后,通过保持ACK高电平终止通讯。在测量和通讯完成后,SHT1x自动转入休眠模式。
  • 通讯复位时序:如果与SHT1x通讯中断,可通过下列信号时序复位:当DATA保持高电平时,触发SCK时钟9次或更多,接着发送一个“传输启动”时序。复位时序如下:

 

  1. 测量时序:传感器的通讯过程为:发送开始时序,启动传感器 -> 发送命令 -> 等待传感器应答及测量结束 -> 接收传感器数据值 -> 接收CRC校验数据 -> 休眠,等待下一次传输开始。

  信号转换:

  • 相对湿度的转换:为获得精确的测量数据,建议用以下公式进行信号转换。

RHlinear = C1 + C2 * SORH + C3 * SORH2(%RH)

公式参数如下:

  •  湿度信号的温度补偿:由于实际温度与测试参考温度25℃ (~77℉)的显著不同, 湿度信号需要温度补偿。

RHtrue = (T℃ - 25) *(t1 + t2 * SORH) + RHlinear

公式参数如下:

  • 温度值转换:可用如下公式将数字输出 (SO T ) 转换为温度值。

T = d1+d2 * SOT

公式参数如下:

  •  露点的定义:露点温度指空气在此温度下能保持最多的水汽,当温度冷却到露点,空气变得饱和,就会出现雾、露或霜。SHT1x并不直接进行露点测量,但露点可以通过温度和湿度读数计算得到。由于温度和湿度在同一块集成电路上测量,所以SHT1x可测量露点。露点计算公式如下:

步骤

  • 在工程中新建两个文件分别命名为sensor_humidity.c和sensor_humidity.h,并将sensor_humidity.c文件保存在该工程文件夹中,并添加sensor_humidity.h文件路径。
  • 在sensor_humidity.h文件中,引用相关头文件,定义1微秒延时函数和操作指令相关宏定义(因传感器时序比较严格,而滴答定时器延时在短时间存在些误差,所以需要定义一个1us的机器周期延时函数,供程序使用),最后进行函数声明。
#ifndef _SENSOR_HUMIDITY_H_
#define _SENSOR_HUMIDITY_H_

#include "stm32f0xx.h"
#include "bsp_systick.h"
#include <stdbool.h>
#include <math.h>
	
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
  • 在sensor_humidity.c文件中添加相应头文件。
  • 在sensor_humidity.c文件中定义SHT10_Init()函数,函数中初始化了传感器使用到GPIO引脚,最后对传感器进行复位。
// 引脚初始化
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(); // 传感器复位
}
  • 在sensor_humidity.c文件中添加SHT10_Start()函数,通过这个函数发送开始传输信号。
// 开始传输信号
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(); 
}
  • 在sensor_humidity.c文件中添加SHT10_Reset()函数,用于通讯复位。
// 通讯复位
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();
	}
}
  • 在sensor_humidity.c文件中添加SHT10_WriteByte()函数,实现向传感器写一个字节的操作。
// 向传感器写1字节
bool 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;
}
  • 在sensor_humidity.c文件中添加SHT10_ReadByte()函数,用来从传感器中读取一个字节数据。
// 从传感器中读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;   
}
  • 在sensor_humidity.c文件中添加SHT10_Measure()函数,从传感器中读取温湿度。

第一步:发送开始传输信号,紧接着发送测量命令。

第二步:等待转换是否完成,如果等待超时则退出函数,否则读取传感器数据并计算,最后返回读取的值。

// 从温湿度传感器读取温湿度
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;
}
  • 在sensor_humidity.c文件中添加SHT10_Calculate()函数,通过这个函数实现校准温度和湿度的值。
// 计算温湿度的值
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; // 湿度的温度补偿,计算实际的湿度值
}
  • sensor_humidity.c文件中添加SHT10_CalcuDewPoint()函数,通过这个函数实现计算露点的值。
// 计算露点
void SHT10_CalDewPoint(float T, float RH, float* Td)
{
	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);
}
  • 在sensor_humidity.c文件中添加SHT10_GetMessure()函数,函数中首先使用SHT10_Measure()函数测量并计算传感器的温湿度值,然后通过SHT10_CalcuDewPoint()函数计算露点的值,最后通过return返回测量的状态。
// 测量温湿度及露点
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;
}
  •  在main.c文件的main()函数中实现测量温度、湿度以及露点值功能。

第一步:引用相应头文件。

第二步:定义存储温度、湿度、露点值的变量。

第三步:在主函数中初始化滴答定时器、传感器和串口。

第四步:在主函数的while循环中调用SHT10_GetMessure测量温度、湿度和露点值,最后使用printf函数通过串口打印。

#include "Sensor_Humidity.h"
#include "bsp_usart.h" 
#include <stdio.h>

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);
	}
}

现象

将程序下载到开发板中,等待传感器初始化后,看到串口调试助手打印出温度、湿度和露点的值。

 更多交流欢迎关注作者抖音号:81849645041​​​​​​

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ST官方并没有提供SHT40的标准库驱动,但是可以根据SHT40的通信协议自行编写驱动代码。以下是一份基于STM32标准库的SHT40驱动代码,仅供参考: ```c #include "stm32f10x.h" #include "delay.h" #include "i2c.h" #include "sht40.h" #define SHT40_ADDRESS 0x44 void SHT40_Init(void) { I2C_Init(); } float SHT40_GetTemperature(void) { uint8_t txBuffer[2]; uint8_t rxBuffer[6]; txBuffer[0] = 0x24; txBuffer[1] = 0x00; I2C_Start(); I2C_SendByte(SHT40_ADDRESS << 1); if(I2C_WaitAck() != 0) { I2C_Stop(); return 0; } I2C_SendByte(txBuffer[0]); I2C_WaitAck(); I2C_SendByte(txBuffer[1]); I2C_WaitAck(); I2C_Stop(); delay_ms(10); I2C_Start(); I2C_SendByte(SHT40_ADDRESS << 1 | 0x01); if(I2C_WaitAck() != 0) { I2C_Stop(); return 0; } for(int i = 0; i < 5; i++) { rxBuffer[i] = I2C_RecvByte(); I2C_Ack(); } rxBuffer[5] = I2C_RecvByte(); I2C_NAck(); I2C_Stop(); uint16_t rawTemp = (rxBuffer[0] << 8) | rxBuffer[1]; float temp = -45 + 175 * ((float)rawTemp / (float)0xFFFF); return temp; } float SHT40_GetHumidity(void) { uint8_t txBuffer[2]; uint8_t rxBuffer[6]; txBuffer[0] = 0x24; txBuffer[1] = 0x00; I2C_Start(); I2C_SendByte(SHT40_ADDRESS << 1); if(I2C_WaitAck() != 0) { I2C_Stop(); return 0; } I2C_SendByte(txBuffer[0]); I2C_WaitAck(); I2C_SendByte(txBuffer[1]); I2C_WaitAck(); I2C_Stop(); delay_ms(10); I2C_Start(); I2C_SendByte(SHT40_ADDRESS << 1 | 0x01); if(I2C_WaitAck() != 0) { I2C_Stop(); return 0; } for(int i = 0; i < 5; i++) { rxBuffer[i] = I2C_RecvByte(); I2C_Ack(); } rxBuffer[5] = I2C_RecvByte(); I2C_NAck(); I2C_Stop(); uint16_t rawHumidity = (rxBuffer[3] << 8) | rxBuffer[4]; float humidity = 100 * ((float)rawHumidity / (float)0xFFFF); return humidity; } ``` 以上代码中,SHT40_Init函数用于初始化I2C接口,SHT40_GetTemperature函数用于获取度值,SHT40_GetHumidity函数用于获取湿度值。注意在使用之前需要先调用SHT40_Init函数初始化I2C接口。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

奚海蛟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值