SHT30温湿度传感器全解析——概况,性能,MCU连接,样例代码

SHT30温湿度传感器全解析——概况,性能,MCU连接,样例代码数据 SHT30 是一款完全校准的线性化的温湿度数字传感器 增强了数字信号

大家好,欢迎来到IT知识分享网。

常见温湿度传感器测量范围:(价格仅供参考,具体性能要看折线图)

型号 DHT11 DHT20 AHT10 AHT20 AHT30 SHT20
价格 ¥ 2.49 ¥3.04 ¥ 1.9 ¥1.4 ¥ 1.3 ¥5.5
温度测量范围 20—90%RH 0—100%RH 0—100%RH 0—100%RH 0—100%RH 0—100%RH
湿度测量精度 ±5%RH ±3%RH ±2%RH ±2%RH ±2%RH ±2%RH
温度测量范围 0—50℃ -40—80℃ -40—85℃ -40—85℃ -40—85℃ -40—125℃
温度测量精度 ±2℃ ±0.5℃ ±0.3℃ ±0.3℃ ±0.3℃ ±0.3℃
工作电压 DC5V/3.3V DC5V/3.3V DC3.3V DC5V/3.3V DC5V/3.3V DC5V/3.3V
型号 SHT30 SHT31 SHT35 SHT40 SHT41 SHT45
价格 ¥ 3.9 ¥ 6.9 ¥ 18.5 ¥ 3.25 ¥6.6 ¥ 19
温度测量范围 0—100%RH 0—100%RH 0—100%RH 0—100%RH 0—100%RH 0—100%RH
湿度测量精度 ±2%RH ±2%RH ±1.5%RH ±1.8%RH ±1.8%RH ±1.5%RH
温度测量范围 -40—125℃ -40—125℃ -40—125℃ -40—125℃ -40—125℃ -40—125℃
温度测量精度 ±0.2℃ ±0.2℃ ±0.1℃ ±0.2℃ ±0.2℃ ±0.1℃
工作电压 DC5V/3.3V DC5V/3.3V DC5V/3.3V DC3.3V DC3.3V DC3.3V

SHT30概述

在这里插入图片描述
数据:
SHT30是一款完全校准的线性化的温湿度数字传感器,增强了数字信号。I2C通讯频率达1MHz。具有高可靠性及高稳定性。

SHT30引脚说明

在这里插入图片描述

引脚 名称 功能
1 SDA 数据信号
2 ADDR 连接到高电平或低电平,不可以悬空
3 ALERT 报警引脚,不用必须悬空
4 SCL 时钟信号
5 VDD 电源正极
6 nRESET 低电平复位;如果不使用,建议悬空;也可以使用大于2Ω电阻连接到VDD
7 R 无功能,请连到电源地
8 VSS 电源地
9 pad 中间引脚与电源地相通,散热引脚

SHT30电气特性

在这里插入图片描述
温度误差:
在这里插入图片描述
湿度误差:
在这里插入图片描述



SHT30 MCU连接

在这里插入图片描述
Rp是I2C上拉电阻,I2C总线上只连接一个设备时,推荐阻值为10K,其他视情况而定,该数值不能太小也不能太大。

SDA,SCL接上拉电阻后再接MCU,用于数据读取。

SHT30通信协议

SHT30的通讯协议是基于I2C的,这里主要理解I2C通讯协议。

SHT30写命令顺序:

1、设置I2C Start。此时I2C状态为0x08:已发送起始条件
2、发送SHT30的I2C写地址。(注意,上图中ADDR接地,则设备地址为0x44;若ADDR接高电平,则设备地址为0x45。同时该地址为7位,再加读写标志位1位才凑够8byte,写时读写标志位为零,则该byte为0x44<<1。)
3、等待收到SHT30的确认ACK。 此时I2C状态为0x18:已发送设备地址和写命令,已接收到ACK
4、发送控制命令高字节。
5、等待收到SHT30的确认ACK。 此时I2C状态为0x28:已发送1byte数据,已接收到ACK
6、发送控制命令低字节。
7、等待收到SHT30的确认ACK。 此时I2C状态为0x28:已发送1byte数据,已接收到ACK
8、如无后续数据,设置I2C Stop。(SHT30写命令只有这一种)






如周期性数据测量模式命令(Command 0x2220)

在这里插入图片描述

SHT30读命令顺序:(先和写命令一样,写入一个命令数据,再读取温湿度数据)

1、设置I2C Start。此时I2C状态为0x08:已发送起始条件
2、发送SHT30的I2C写地址。(注意,上图中ADDR接地,则设备地址为0x44;若ADDR接高电平,则设备地址为0x45。同时该地址为7位,再加读写标志位1位才凑够8byte,写时读写标志位为零,则该byte为0x44<<1。)
3、等待收到SHT30的确认ACK。 此时I2C状态为0x18:已发送设备地址和写命令,已接收到ACK
4、发送控制命令高字节。
5、等待收到SHT30的确认ACK。 此时I2C状态为0x28:已发送1byte数据,已接收到ACK
6、发送控制命令低字节。
7、等待收到SHT30的确认ACK。 此时I2C状态为0x28:已发送1byte数据,已接收到ACK





8、如使用周期性测量命令设定过SHT30,则无需等待,重新设置I2C Start。 此时I2C状态为0x08:已发送起始条件
9、发送SHT30的I2C读地址。(注意,上图中ADDR接地,则设备地址为0x44;若ADDR接高电平,则设备地址为0x45。同时该地址为7位,再加读写标志位1位才凑够8byte,读时读写标志位为1,则该byte为0x44<<1|0x01。)
10、等待收到SHT30的确认ACK。 此时I2C状态为0x40:已发送设备地址和读命令,已接收到ACK
11、设置使能主机应答功能,即主机进行接收数据后发送ACK确认。
12、接收温度高字节。 此时I2C状态为0x50:已接收数据字节,并已返回ACK信号
13、接收温度低字节。 此时I2C状态为0x50:已接收数据字节,并已返回ACK信号
14、接收温度CRC字节。 此时I2C状态为0x50:已接收数据字节,并已返回ACK信号
15、接收湿度高字节。 此时I2C状态为0x50:已接收数据字节,并已返回ACK信号
16、接收湿度低字节。 此时I2C状态为0x50:已接收数据字节,并已返回ACK信号
17、设置关闭主机应答功能,最后一个数据不需要ACK。
17、接收湿度CRC字节。 此时I2C状态为0x58:已接收到最后一个数据,NACK已返回
18、设置I2C Stop.










如读取周期性数据测量数据命令(Command 0xE000)

在这里插入图片描述

SHT30命令说明

SHT30校验和计算

uint8_t CheckCrc8(uint8_t* const message, uint8_t initial_value) { uint8_t remainder; //余数 uint8_t i = 0, j = 0; //循环变量 /* 初始化 */ remainder = initial_value; for(j = 0; j < 2;j++) { remainder ^= message[j]; /* 从最高位开始依次计算 */ for (i = 0; i < 8; i++) { if (remainder & 0x80) { remainder = (remainder << 1)^CRC8_POLYNOMIAL; } else { remainder = (remainder << 1); } } } /* 返回计算的CRC码 */ return remainder; } 

计算温度:(ST 传感器温度返回值)
在这里插入图片描述
计算湿度:(SRH 传感器湿度返回值)
在这里插入图片描述
代码说明:



 /* 转换温度数据 */ recv_temperature = ((uint16_t)dat[0]<<8)|dat[1]; *temperature = -45 + 175*((float)recv_temperature / 65535); /* 转换湿度数据 */ recv_humidity = ((uint16_t)dat[3]<<8)|dat[4]; *humidity = 100 * ((float)recv_humidity / 65535); 

SHT30 样例代码(基于HC32L130)

#ifndef __SHT3X_H__ #define __SHT3X_H__ #include "gpio.h" /* //ADDR Pin Conect to VSS #define SHT30_ADDR_WRITE 0x44<<1 // #define SHT30_ADDR_READ (0x44<<1)+1 // */ //SHT30 I2C地址 #define I2C_DEVADDR 0x44 //CRC-8多项式 #define CRC8_POLYNOMIAL 0x31 typedef enum { /* 软件复位命令 */ SOFT_RESET_CMD = 0x30A2, /* 单次测量模式 命名格式:Repeatability_CS_CMD CS:Clock stretching */ HIGH_ENABLED_CMD = 0x2C06, MEDIUM_ENABLED_CMD = 0x2C0D, LOW_ENABLED_CMD = 0x2C10, HIGH_DISABLED_CMD = 0x2400, MEDIUM_DISABLED_CMD = 0x240B, LOW_DISABLED_CMD = 0x2416, /* 周期测量模式 命名格式:Repeatability_MPS_CMD MPS:measurement per second */ HIGH_0_5_CMD = 0x2032, MEDIUM_0_5_CMD = 0x2024, LOW_0_5_CMD = 0x202F, HIGH_1_CMD = 0x2130, MEDIUM_1_CMD = 0x2126, LOW_1_CMD = 0x212D, HIGH_2_CMD = 0x2236, MEDIUM_2_CMD = 0x2220, LOW_2_CMD = 0x222B, HIGH_4_CMD = 0x2334, MEDIUM_4_CMD = 0x2322, LOW_4_CMD = 0x2329, HIGH_10_CMD = 0x2737, MEDIUM_10_CMD = 0x2721, LOW_10_CMD = 0x272A, /* 周期测量模式读取数据命令 */ READOUT_FOR_PERIODIC_MODE = 0xE000, } SHT30_CMD; void I2C_Port_Init(void); void I2C_Cfg_Init(void); void SHT30_reset(void); uint8_t SHT30_Init(void); uint8_t SHT30_Send_Cmd(SHT30_CMD cmd); uint8_t SHT30_Read_Dat(uint8_t* dat); uint8_t SHT30_Dat_To_Float(uint8_t* const dat, float* temperature, float* humidity); #endif /* __SHT3X_H__ */ 

sht3x.c文件

#include "sht3x.h" #include "gpio.h" #include "i2c.h" // I2C端口配置 void I2C_Port_Init(void) { stc_gpio_cfg_t stcGpioCfg; DDL_ZERO_STRUCT(stcGpioCfg); Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); //开启GPIO时钟门控 stcGpioCfg.enDir = GpioDirOut; ///< 端口方向配置->输出 stcGpioCfg.enOD = GpioOdEnable; ///< 开漏输出 stcGpioCfg.enPu = GpioPuEnable; ///< 端口上拉配置->使能 stcGpioCfg.enPd = GpioPdDisable; ///< 端口下拉配置->禁止 stcGpioCfg.bOutputVal = TRUE; Gpio_Init(GpioPortB,GpioPin13,&stcGpioCfg); ///< 端口初始化 Gpio_Init(GpioPortB,GpioPin14,&stcGpioCfg); Gpio_SetAfMode(GpioPortB,GpioPin13,GpioAf2); ///< 配置PB13为SCL Gpio_SetAfMode(GpioPortB,GpioPin14,GpioAf2); ///< 配置PB14为SDA } // I2C 模块配置 void I2C_Cfg_Init(void) { stc_i2c_cfg_t stcI2cCfg; DDL_ZERO_STRUCT(stcI2cCfg); ///< 初始化结构体变量的值为0 Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c1,TRUE); ///< 开启I2C0时钟门控 stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq(); ///< 获取PCLK时钟 stcI2cCfg.u32Baud = ; ///< 100kHz,SHT30最大支持1MHz,但要I2C fast mode,且硬件设计过关 stcI2cCfg.enMode = I2cMasterMode; ///< 主机模式 stcI2cCfg.u8SlaveAddr = 0x55; ///< 从地址,主模式无效 stcI2cCfg.bGc = FALSE; ///< 广播地址应答使能关闭 I2C_Init(M0P_I2C1,&stcI2cCfg); ///< 模块初始化 } // CRC-8校验 uint8_t CheckCrc8(uint8_t* const message, uint8_t initial_value) { uint8_t remainder; //余数 uint8_t i = 0, j = 0; //循环变量 /* 初始化 */ remainder = initial_value; for(j = 0; j < 2;j++) { remainder ^= message[j]; /* 从最高位开始依次计算 */ for (i = 0; i < 8; i++) { if (remainder & 0x80) { remainder = (remainder << 1)^CRC8_POLYNOMIAL; } else { remainder = (remainder << 1); } } } /* 返回计算的CRC码 */ return remainder; } // SHT30写命令函数,只进行写命令操作 en_result_t I2C_SHT30WriteCmd(M0P_I2C_TypeDef* I2CX,uint8_t *pu8Data) { en_result_t enRet = Error; uint8_t sendCount=0,u8State; I2C_SetFunc(I2CX,I2cStart_En); ///发送起始条件 while(1) { while(0 == I2C_GetIrq(I2CX)) {;} u8State = I2C_GetState(I2CX); switch(u8State) { case 0x08: ///已发送起始条件 I2C_ClearFunc(I2CX, I2cStart_En); I2C_WriteByte(I2CX,(I2C_DEVADDR<<1)); ///发送设备地址+W写标志0 break; case 0x18: ///已发送SLW+W,已接收ACK case 0x28: ///已发送I2Cx_DATA中的数据,已接收ACK if(sendCount<2) { I2C_WriteByte(I2CX,pu8Data[sendCount++]); ///发送数据 }else { //发送两字节命令后收到ACK,退出 sendCount++; } break; case 0x20: ///已发送SLW+W,已接收非ACK case 0x38: ///上一次在SLA+写数据时丢失仲裁 I2C_SetFunc(I2CX,I2cStart_En); ///当I2C总线空闲时发送起始条件 break; case 0x30: ///已发送I2Cx_DATA中的数据,已接收非ACK,将传输一个STOP条件 I2C_SetFunc(I2CX,I2cStop_En); ///发送停止条件 break; default: break; } if(sendCount>2) { I2C_SetFunc(I2CX,I2cStop_En); ///此顺序不能调换,出停止条件 I2C_ClearIrq(I2CX); break; } I2C_ClearIrq(I2CX); ///清除中断状态标志位 } enRet = Ok; return enRet; } // 主机读取数据函数,只进行读数据操作 en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint16_t u8Cmd,uint8_t *pu8Data,uint32_t u32Len) { en_result_t enRet = Error; uint8_t u8State=0; uint8_t receiveCount=0; uint8_t sendAddrCount=0; uint8_t sendCmdCount=0; I2C_SetFunc(I2CX,I2cStart_En); while(1) { while(0 == I2C_GetIrq(I2CX)) {;} u8State = I2C_GetState(I2CX); switch(u8State) { case 0x08: ///< 已发送起始条件,将发送SLA+W sendAddrCount++; if(sendAddrCount<=1) { I2C_ClearFunc(I2CX,I2cStart_En); I2C_WriteByte(I2CX,I2C_DEVADDR<<1); } if(sendAddrCount>1) { I2C_ClearFunc(I2CX,I2cStart_En); I2C_WriteByte(I2CX,I2C_DEVADDR<<1|0x01);///< 发送SLA+R,开始从从机读取数据 } break; case 0x18: ///< 已发送SLA+W,并接收到ACK I2C_WriteByte(I2CX,(uint8_t)(u8Cmd>>8)); ///<命令高8位 break; case 0x28: ///< 已发送数据,接收到ACK, 此处是已发送从机内存地址u8Addr并接收到ACK sendCmdCount++; I2C_WriteByte(I2CX,(uint8_t)u8Cmd); ///<命令低8位 if(sendCmdCount>1) I2C_SetFunc(I2CX,I2cStart_En); ///< 发送重复起始条件 break; case 0x10: ///< 已发送重复起始条件 I2C_ClearFunc(I2CX,I2cStart_En); I2C_WriteByte(I2CX,I2C_DEVADDR|0x01); ///< 发送SLA+R,开始从从机读取数据 break; case 0x40: ///< 已发送SLA+R,并接收到ACK if(u32Len>1) { I2C_SetFunc(I2CX,I2cAck_En); ///< 使能主机应答功能 } break; case 0x50: ///< 已接收数据字节,并已返回ACK信号 pu8Data[receiveCount++] = I2C_ReadByte(I2CX); if(receiveCount==u32Len-1) { I2C_ClearFunc(I2CX,I2cAck_En); ///< 已接收到倒数第二个字节,关闭ACK应答功能 } break; case 0x58: ///< 已接收到最后一个数据,NACK已返回 pu8Data[receiveCount++] = I2C_ReadByte(I2CX); I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件 break; case 0x38: ///< 在发送地址或数据时,仲裁丢失 I2C_SetFunc(I2CX,I2cStart_En); ///< 当总线空闲时发起起始条件 break; case 0x48: ///< 发送SLA+R后,收到一个NACK I2C_SetFunc(I2CX,I2cStop_En); ///< 发送停止条件 I2C_SetFunc(I2CX,I2cStart_En); ///< 发送起始条件 break; default: I2C_SetFunc(I2CX,I2cStart_En); ///< 其他错误状态,重新发送起始条件 break; } I2C_ClearIrq(I2CX); ///< 清除中断状态标志位 if(receiveCount==u32Len) ///< 数据全部读取完成,跳出while循环 { break; } } enRet = Ok; return enRet; } // 向SHT30发送一条指令(16bit) uint8_t SHT30_Send_Cmd(SHT30_CMD cmd) { uint8_t cmd_buffer[2]; cmd_buffer[0] = cmd >> 8; cmd_buffer[1] = cmd; return I2C_SHT30WriteCmd(M0P_I2C1, cmd_buffer); } // 复位SHT30 void SHT30_reset(void) { SHT30_Send_Cmd(SOFT_RESET_CMD); delay1us(20); } // 初始化SHT30 周期测量模式0x2220 uint8_t SHT30_Init(void) { return SHT30_Send_Cmd(MEDIUM_2_CMD); } // 从SHT30读取一次数据 uint8_t SHT30_Read_Dat(uint8_t* dat) { return I2C_MasterReadData(M0P_I2C1,READOUT_FOR_PERIODIC_MODE, dat, 6); } // 将SHT30接收的6个字节数据进行CRC校验,并转换为温度值和湿度值 uint8_t SHT30_Dat_To_Float(uint8_t* const dat, float* temperature, float* humidity) { uint16_t recv_temperature = 0; uint16_t recv_humidity = 0; /* 校验温度数据和湿度数据是否接收正确 */ if(CheckCrc8(dat, 0xFF) != dat[2] || CheckCrc8(&dat[3], 0xFF) != dat[5]) return 1; /* 转换温度数据 */ recv_temperature = ((uint16_t)dat[0]<<8)|dat[1]; *temperature = -45 + 175*((float)recv_temperature/65535); /* 转换湿度数据 */ recv_humidity = ((uint16_t)dat[3]<<8)|dat[4]; *humidity = 100 * ((float)recv_humidity / 65535); return 0; } 

main.c文件

#include "sht3x.h" #include "gpio.h" #include "ddl.h" #include "i2c.h" uint8_t recv_dat[6] = {0}; float temperature = 0.0; float humidity = 0.0; int main(void) { I2C_Cfg_Init(); I2C_Port_Init(); ///< 向I2C总线发起开始信号 I2C_SetFunc(M0P_I2C1,I2cStart_En); SHT30_Init(); while (1) { delay1ms(1000); if(SHT30_Read_Dat(recv_dat) == Ok) { SHT30_Dat_To_Float(recv_dat, &temperature, &humidity); } } } 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/113497.html

(0)
上一篇 2025-12-14 09:00
下一篇 2025-12-14 09:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信