1. 背景
工作中,需要使用到SHT21温湿度传感器。相关手册:SHT21
由于焊接的问题,部分芯片存在通信异常初始化失败的问题。因而在代码中采用了极端的异常处理。(不断复位初始化)
1.1 芯片简易资料
SHT21
湿度和温度传感器IC
包含:
(1)电容式相对湿度传感器
(2)带隙温度传感器
-------------------------
包括,一个放大器,AD转换器,OTP存储器和一个数字处理单元
解析度,12位 0.04
8位 0.7
传感器建议在正常范围内工作,长期暴露在正常条件之外,尤其是在湿度大于80%RH的环境中,可能会暂时抵消RH信号,且加速老化。
对光不敏感,但长期暴露在阳光或者强烈的紫外线辐射下可能会使传感器老化。
注意:
如果SCL和SDA并行走线,且超过10cm以上,可能会导致串扰和通信中断。
可以通过在信号之间路由VDD 和/或 VSS 和/或 使用屏蔽电缆线来解决。
此外 降低SCL频率可能会改善信号。
电源引脚(VDD和VSS)必须使用100nf的去耦电容。
为了避免信号竞争,MCU需要仅将SDA、SCL驱动为低电平。需要外部上拉电阻(10K)。
1.2 关于使用
第一步,将传感器上电至 VDD(2.1V~3.6V)
上电后,传感器在SCL为高电平时,最多需要15ms才能进入空闲状态,即准备好接收来自主机MCU的命令
1.3 IIC通信
(1)每次的通信传输 需要以 起始条件 开始,以 结束条件 结束。
(2)在发送一个起始条件之后,需要发送 设备地址(0x81/0x80 读写)
(3)发出测量命令,温度为 1110 0011 相对湿度为 1110 0101 。
(4)等待测量完成
基本命令:
触发温度测量(hold master) 1110 0011 0xe3
触发相对湿度测量(hold master) 1110 0101 0xe5
触发温度测量(no hold master) 1111 0011 0xf3
触发相对湿度测量(no hold master) 1111 0101 0xf5
写用户寄存器
读用户寄存器
软件复位
1.4 关于保持主机模式和不保持主机模式
保持:
不保持:
1.5 注意事项
转换时间:
测量持续时间 为ms级 (默认)
12位的相对湿度,22~29ms
14位的温度测量,66~85ms
2. 代码实现
2.1 初始化和测量的函数
测量时,启动测量,等待转换完成,读出数据,停止测量。
SHT21_Measurement函数,每10ms进一次。第9次进入(经过90ms),第12次经过(120-90=30ms)
#include "main.h"
#define CNT_NUM 50
/*----------------------------------------------------------------------------*/
extern void SHT2x_SoftReset(void);
extern void SHT2x_SetResolution(SHT2x_Resolution res);
extern uint8_t SHT2x_ReadUserReg(void);
extern uint16_t SHT2x_GetRaw_Rx(void);
extern void SHT2x_GetRaw_Tx(uint8_t cmd);
extern uint16_t config_read(uint16_t readAddr);
extern void config_write(uint16_t writeAddr,uint16_t writeData);
extern int modbus_ReportResetCnt(void);
void init_SHT21(void)
{
SHT2x_SoftReset();
HAL_Delay(20);
//SHT2x_SetResolution(RES_14_12);
SHT2x_GetRaw_Tx(SHT2x_READ_TEMP_NOHOLD);
//读取已复位次数
g_RebootCnt = config_read(REG_ADDR_REBOOT_CNT);
if(g_RebootCnt>CNT_NUM)
{
uint16_t data = SHT2x_GetRaw_Rx();
if(data!=0||g_RebootCnt==0xFFFF)//读取成功或者首次运行,需要清零计数标志
{
g_RebootCnt = 0;
config_write(REG_ADDR_REBOOT_CNT,g_RebootCnt);
SHT2x_GetRaw_Tx(SHT2x_READ_TEMP_NOHOLD);
}
}
//读取主动复位总数
g_RebootCntTotal = config_read(REG_ADDR_REBOOT_CNT_TOTAL);
if(g_RebootCntTotal==0xFFFF)//首次运行,未清零
{
g_RebootCntTotal=0;
config_write(REG_ADDR_REBOOT_CNT_TOTAL,g_RebootCntTotal);
}
//上报复位数到PLC
modbus_ReportResetCnt();
}
//相对湿度 每30ms 读一次
//温度 每90ms 读一次
void SHT21_Measurement(void)
{
static uint8_t cnt=0;
if(g_RebootCnt>CNT_NUM)return;
cnt++;
if(cnt==9) //读取温度
{
uint16_t data=0;
data= SHT2x_GetRaw_Rx();
if(data==0)//读取失败
{
g_RebootCnt++;
//记录复位次数到eeprom中
config_write(REG_ADDR_REBOOT_CNT,g_RebootCnt);
//通过自动复位来自救
RX1_LED_GPIO_Port->BSRR = (uint32_t)RX1_LED_Pin << 16u;
RX2_LED_GPIO_Port->BSRR = (uint32_t)RX2_LED_Pin << 16u;
RX3_LED_GPIO_Port->BSRR = (uint32_t)RX3_LED_Pin << 16u;
TX1_LED_GPIO_Port->BSRR = (uint32_t)TX1_LED_Pin << 16u;
TX2_LED_GPIO_Port->BSRR = (uint32_t)TX2_LED_Pin << 16u;
TX3_LED_GPIO_Port->BSRR = (uint32_t)TX3_LED_Pin << 16u;
while(1);
}
shtValue.T = -4685 + 17572 * (data/ 65536.0);
SHT2x_GetRaw_Tx(SHT2x_READ_RH_NOHOLD);
}
if(cnt>=12)//读取湿度
{
uint16_t data=0;
data= SHT2x_GetRaw_Rx()&0xfffc;
if(data==0||data>55574)//读取失败
{
g_RebootCnt++;
//记录复位次数到eeprom中
config_write(REG_ADDR_REBOOT_CNT,g_RebootCnt);
HAL_Delay(3);
//记录总复位次数
g_RebootCntTotal++;
config_write(REG_ADDR_REBOOT_CNT_TOTAL,g_RebootCntTotal);
//通过自动复位来自救
RX1_LED_GPIO_Port->BSRR = (uint32_t)RX1_LED_Pin << 16u;
RX2_LED_GPIO_Port->BSRR = (uint32_t)RX2_LED_Pin << 16u;
RX3_LED_GPIO_Port->BSRR = (uint32_t)RX3_LED_Pin << 16u;
TX1_LED_GPIO_Port->BSRR = (uint32_t)TX1_LED_Pin << 16u;
TX2_LED_GPIO_Port->BSRR = (uint32_t)TX2_LED_Pin << 16u;
TX3_LED_GPIO_Port->BSRR = (uint32_t)TX3_LED_Pin << 16u;
while(1);
}
shtValue.RH = -600 + 12500 * (data /65536.0);
SHT2x_GetRaw_Tx(SHT2x_READ_TEMP_NOHOLD);
cnt=0;
}
}
2.2 IIC通信相关的函数
/* SHT21湿度温度传感器 设备地址默认0x80*/
#include "Define.h"
#include "TypeDef.h"
/**
* @brief Performs a soft reset.
*/
void SHT2x_SoftReset(void){
uint8_t cmd = SHT2x_SOFT_RESET;
HAL_I2C_Master_Transmit(&hi2c2, SHT2x_I2C_ADDR << 1, &cmd, 1, SHT2x_TIMEOUT);
}
/**
* @brief Gets the value stored in user register.
* @return 8-bit value stored in user register, 0 to 255.
*/
uint8_t SHT2x_ReadUserReg(void) {
uint8_t val;
uint8_t cmd = SHT2x_READ_REG;
HAL_I2C_Master_Transmit(&hi2c2, SHT2x_I2C_ADDR << 1, &cmd, 1, SHT2x_TIMEOUT);
HAL_I2C_Master_Receive(&hi2c2, SHT2x_I2C_ADDR << 1, &val, 1, SHT2x_TIMEOUT);
return val;
}
void SHT2x_GetRaw_Tx(uint8_t cmd) {
HAL_I2C_Master_Transmit(&hi2c2, SHT2x_I2C_ADDR << 1, &cmd, 1, SHT2x_TIMEOUT);
}
uint16_t SHT2x_GetRaw_Rx(void) {
uint8_t val[3] = { 0 };
HAL_I2C_Master_Receive(&hi2c2, SHT2x_I2C_ADDR << 1, val, 3, SHT2x_TIMEOUT);
return (val[0] << 8 | val[1]);
}
/**
* @brief Sets the measurement resolution.
* @param res Enum resolution.
* @note Available resolutions: RES_14_12, RES_12_8, RES_13_10, RES_11_11.
* @note RES_14_12 = 14-bit temperature and 12-bit RH resolution, etc.
*/
void SHT2x_SetResolution(SHT2x_Resolution res) {
uint8_t val = SHT2x_ReadUserReg();
val = (val & 0x7e) | res;
uint8_t temp[2] = { SHT2x_WRITE_REG, val };
HAL_I2C_Master_Transmit(&hi2c2, SHT2x_I2C_ADDR << 1, temp, 2, SHT2x_TIMEOUT);
}