本帖最后由 1084504793 于 2024-1-21 21:18 编辑
SHT30是SHT3X系列温湿度传感器中的一款,除SHT30外,还有SHT31和SHT35。它们的对比如下图所示,
其中D代表数字量,A代表模拟量。 在购买SHT30模块的时候需要注意一下的是SHT30-ARP代表输出的是模拟量;SHT30-DIS代表输出的是数字量。 本文主要介绍的是SHT30-DIS模块,且通信方式是IIC,模块实拍图片如下
SHT30电气特性 SHT30的电气特性见下表 参数
| 规格
| 工作电压
| 2.4V~5.5V
| 芯片尺寸
| 2.5mm×2.5mm×0.9mm
| 测量范围
| 温度:-40~+125℃ 湿度:0~100%RH
| 精度
| 温度:±0.3℃ 湿度:±3%RH(25℃)
| 分辨率
| 温度:0.015℃ 湿度:0.01%RH
| 衰减值
| 温度:<0.03℃/年 湿度:<0.25%RH/年
| 输出信号
| IIC接口
| 反应时间(湿度)
| 8sec(tau63%)
| 能耗
| 4.8uW(8位,1次测量/秒条件下)
| 引脚数
|
|
该表是从手册中整理而来,因为网上相关的手册基本上都是官方的英文手册,里面有很多的内容没有集体描述出来,中文手册多是通过翻译软件直接翻译的。需要注意的是官方给的文档中写的工作电压是2.4-5.5V,但是在传感器模块背面却印有2.4-2.5V的字样。在测试过程中将模块的工作电压正极VCC接到M61板子的5V或3.3V供电引脚也是可以正常工作的,所以模块的丝印有可能是印刷有误,毕竟印这么窄的供电范围也是很难满足的。 SHT30芯片引脚如下图所示
其中各个引脚说明如下 需要注意的是购买的模块没有将ADDR、ALERT和nRESET引脚引出来。所以SHT30的IIC通信地址是固定的。我购买的模块是将ADDR接地,也就是接低电平,所以SHT30的IIC通信地址为0x44。若ADDR接高电平,则SHT30的IIC通信地址为0x45。模块也不能进行中断检测,不过官方在这方面的说明不仅少,而且一般也是不会用到该功能的,所以本文也只介绍常用的功能。除了中断的功能没有用到外,还有其自加热功能也没有用到,自加热主要是增加芯片的供电电流而产热,但是实现起来有很大的危险,而且目前有很多的芯片不支持引脚输出大电流,建议用到加热的功能,最好还是购买专门的模块使用。
SHT30驱动编写 因为官方的驱动是英文版,且很多细节没有完全写出来,中文版也只是硬翻译而已,所以本文直接跳过文档的讲解直接讲解代码相关的内容。我也是看了很多遍的文档和官方给的示例代码,也通过代码不断地进行调试和验证才大概了解SHT30的部分使用方法。 SHT30模块采用标准的IIC通信,通信速率可以选择400KBps,还是用之前常用的IIC驱动函数就可以实现SHT30的温湿度测量功能。IIC写数据函数定义如下 - void IIC_SenCmd(uint8_t _Cmd, uint8_t *Sendbuf, uint16_t _length)
- {
- if (SHT30_ADDR)
- {
- msgs[0].addr = SHT30_ADDR_H;
- }
- else
- {
- msgs[0].addr = SHT30_ADDR_L;
- }
- msgs[0].flags = I2C_M_NOSTOP;
- msgs[0].buffer = &_Cmd;
- msgs[0].length = 1;
- if (_length != 0)
- {
- /* 有数据的发送 */
- if (SHT30_ADDR)
- {
- msgs[0].addr = SHT30_ADDR_H;
- }
- else
- {
- msgs[0].addr = SHT30_ADDR_L;
- }
- msgs[1].flags = 0;
- msgs[1].buffer = Sendbuf;
- msgs[1].length = _length;
- bflb_i2c_transfer(i2c, msgs, 2);
- }
- else
- {
- /* 只发一个字节的数据 */
- msgs[0].flags = 0;
- bflb_i2c_transfer(i2c, msgs, 1);
- }
- }
复制代码 IIC读数据函数定义如下 - void IIC_RecData(uint8_t *_Recbuf, uint16_t _length)
- {
- if (SHT30_ADDR)
- {
- msgs[0].addr = SHT30_ADDR_H;
- }
- else
- {
- msgs[0].addr = SHT30_ADDR_L;
- }
- msgs[0].flags = I2C_M_READ;
- msgs[0].buffer = _Recbuf;
- msgs[0].length = _length;
- bflb_i2c_transfer(i2c, msgs, 1);
- }
复制代码 这两个函数在之前的驱动移植中也是这样定义,所以不做过多的讲解,代码也是很简单的。 SHT30有多种测试模式,每种测试模式都是需要发送两个字节的数据指令,其实SHT30的所有指令都是发送两个字节的数据决定的。首先是测试模式发送函数定义,也可以用于所有指令发送,但是其他指令基本没有用到,函数定义如下 - SHT30CMDSendResu SHT30_SendTestMode(SHT30CMD _Cmd)
- {
- if (_Cmd >= SHT30_CMD_LAST)
- {
- return SHT30_CMD_SEND_RESU_ERR;
- }
- IIC_SenCmd(SHT30CMDSendData[_Cmd][0], &SHT30CMDSendData[_Cmd][1], SHT30_CMD_LEN_BYTE - 1);
- //printf("Chip Test Mode CMD send over\r\n");
- return SHT30_CMD_SEND_RESU_OK;
- }
复制代码 参数 _Cmd为要发送的指令,是一个枚举类型的定义,该枚举定义在SHT30.h文件中,定义如下 - /* SHT30支持的指令 */
- typedef enum
- {
- SHT30_CMD_MEAS_CLOCKSTR_H = 0,
- SHT30_CMD_MEAS_CLOCKSTR_M,
- SHT30_CMD_MEAS_CLOCKSTR_L,
- SHT30_CMD_MEAS_POLLING_H,
- SHT30_CMD_MEAS_POLLING_M,
- SHT30_CMD_MEAS_POLLING_L,
- SHT30_CMD_MEAS_PERI_05_H,
- SHT30_CMD_MEAS_PERI_05_M,
- SHT30_CMD_MEAS_PERI_05_L,
- SHT30_CMD_MEAS_PERI_1_H,
- SHT30_CMD_MEAS_PERI_1_M,
- SHT30_CMD_MEAS_PERI_1_L,
- SHT30_CMD_MEAS_PERI_2_H,
- SHT30_CMD_MEAS_PERI_2_M,
- SHT30_CMD_MEAS_PERI_2_L,
- SHT30_CMD_MEAS_PERI_4_H,
- SHT30_CMD_MEAS_PERI_4_M,
- SHT30_CMD_MEAS_PERI_4_L,
- SHT30_CMD_MEAS_PERI_10_H,
- SHT30_CMD_MEAS_PERI_10_M,
- SHT30_CMD_MEAS_PERI_10_L,
- SHT30_CMD_FETCH_DATA, /* 周期模式的读出测量 */
- SHT30_CMD_ART, /* ART(加速响应) */
- SHT30_CMD_STOP_PERI_DATA_ACQU, /* 中断指令或采集数据 */
- SHT30_CMD_SOFT_RESET, /* 软复位 */
- SHT30_CMD_RESET_THRO_PIN_NRESET, /* 硬复位 */
- SHT30_CMD_HEATER_ENABLE, /* 使能加热器 */
- SHT30_CMD_HEATER_DISABLE, /* 关闭加热器 */
- SHT30_CMD_READ_STATUS, /* 读取状态 */
- SHT30_CMD_CLEAR_STATUS, /* 清除状态 */
- SHT30_CMD_LAST,
- }SHT30CMD;
复制代码 该枚举按照英文手册先后出现的指令一个个的列举出来,方便后续的补充和使用。 回到指令发送函数中,主要代码是IIC_SenCmd(SHT30CMDSendData[_Cmd][0], &SHT30CMDSendData[_Cmd][1], SHT30_CMD_LEN_BYTE - 1);。主要是调用IIC发送函数,因SHT30的指令是两个字节的数据,所有的参数存放在全局变量SHT30CMDSendData中,所以调用IIC发送驱动函数时参数做了兼容处理。全局变量SHT30CMDSendData定义在SHT30.c中,按照指令的枚举类型的顺序一个个的定义的,这样方便指令的同一管理。大家在使用时可以删除部分不用的指令,以节约M61的资源空间。SHT30CMDSendData的定义如下 - /* SHT30指令发送参数值 */
- uint8_t SHT30CMDSendData[SHT30_CMD_LAST][SHT30_CMD_LEN_BYTE] =
- {
- {0x2C, 0x06},
- {0x2C, 0x0D},
- {0x2C, 0x10},
- {0x24, 0x00},
- {0x24, 0x0B},
- {0x24, 0x16},
- {0x20, 0x32},
- {0x20, 0x24},
- {0x20, 0x2F},
- {0x21, 0x30},
- {0x21, 0x26},
- {0x21, 0x2D},
- {0x22, 0x36},
- {0x22, 0x20},
- {0x22, 0x2B},
- {0x23, 0x34},
- {0x23, 0x22},
- {0x23, 0x29},
- {0x27, 0x37},
- {0x27, 0x21},
- {0x27, 0x2A},
- {0xE0, 0x00}, /* 周期模式的读出测量 */
- {0x2B, 0x32}, /* ART(加速响应) */
- {0x30, 0x93}, /* 中断指令或采集数据 */
- {0x30, 0xA2}, /* 软复位 */
- {0x00, 0x06}, /* 硬复位 */
- {0x30, 0x6D}, /* 使能加热器 */
- {0x30, 0x66}, /* 关闭加热器 */
- {0xF3, 0x2D}, /* 读取状态 */
- {0x30, 0x41}, /* 清除状态 */
- };
复制代码 最后是驱动SHT30正常工作的函数。因官方文档中写出了很多的测试模式,有单次的,有循环的,有低分辨率的,有高分辨率的。但是文档并没有给出详细的区别,也是轻描淡写的,尤其是不同分辨率下的测试模式对应的延时时长没有明确给出,按照字面意思去算延时是有问题。网上的驱动也都是只用那一种测试模式,延时时间是80ms,所以自己写了个测试函数,将所有的测试模式都试了一遍,然后延时都是80ms。测试发现各种模式算出来的数据相差非常小,一般是查小数点后两位。有兴趣的可以改变测试模式的下发,然后查看计算数据的区别,在此不再多说了。设置并读取的函数定义如下 - SHT30ReadResu SHT30_ReadTempAndHumi(float *_LuxVal)
- {
- uint8_t RecData[7] = {0};
- uint16_t Temp = 0;
- if (SHT30_TEST_MODE > SHT30_CMD_MEAS_PERI_10_L)
- {
- return SHT30_READ_ERR;
- }
- if (SHT30_CMD_SEND_RESU_ERR == SHT30_SendTestMode(SHT30_TEST_MODE))
- {
- return SHT30_READ_ERR;
- }
- /* 等待测量完成 */
- bflb_mtimer_delay_ms(50);
- /* 接收测量数据 */
- IIC_RecData(RecData, 6);
- Temp = (RecData[0] << 8) | RecData[1];
- *(_LuxVal++) = (float)Temp * 175.0 / 65535.0 -45.0;
- Temp = (RecData[3] << 8) | RecData[4];
- *_LuxVal = (float)Temp * 100.0 / 65535.0;
- return SHT30_READ_OK;
- }
复制代码 测试模式的选取是通过宏定义 SHT30_TEST_MODE决定的,定义在SHT30.h文件中,可以通过修改改变测试模式。测试模式下发后延时80ms,等待模块测量完成。接收数据有六个字节的数据,返回数据格式如下所示 前两个字节的数据是温度数据,然后紧跟着CRC校验值,之后是湿度数据和湿度数据的CRC校验值。驱动中接收到这六个数据后直接计算温湿度值,对于CRC校验并没有使用,因为用的地方不多。若大家有想用到CRC校验的,可以参考官方给的驱动程序。计算方式也很简单,接收到的数据组成一个十六位的二字节数据,然后乘以100除以65535。将计算结果保存在参数指针中,需要注意的是保存的数值是先保存温度数据,然后是湿度数据,都是计算后的原始数据,没有做放大处理,传递的参数最好是大于等于2的单精度浮点型数组。 在main.c有调用SHT30驱动的例子,并将获取到的温湿度值通过串口打印出来。main.c文件代码如下 - #include "board.h"
- #include "SHT30.h"
- #include "bflb_gpio.h"
- struct bflb_device_s *gpio;
- typedef enum
- {
- LED_STA_OFF = 0, /* 关闭 */
- LED_STA_ON, /* 打开 */
- LED_STA_LAST,
- }LedSta;
- void LED_Init()
- {
- /* 初始化绿灯,用来指示LED状态 */
- gpio = bflb_device_get_by_name("gpio");
- bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
- }
- void LED_SetSta(LedSta _Sta)
- {
- if (_Sta)
- {
- /* 高电平打开LED */
- bflb_gpio_set(gpio, GPIO_PIN_14);
- }
- else
- {
- /* 低电平关闭LED */
- bflb_gpio_reset(gpio, GPIO_PIN_14);
- }
- }
- int main(void)
- {
- float TempAndHumiVal[2] = {0};
- LedSta LEDSta = LED_STA_ON;
-
- board_init(); /* 板卡初始化 */
- LED_Init(); /* LED初始化 */
- SHT30_Init(); /* 初始化SHT30 */
- LED_SetSta(LEDSta);
- while (1)
- {
- /* 读取光照强度 */
- if (SHT30_READ_OK == SHT30_ReadTempAndHumi(TempAndHumiVal))
- {
- printf("SHT30 Read Temperature is:%f Humidity is:%f\r\n",TempAndHumiVal[0],TempAndHumiVal[1]);
- }
- else
- {
- printf("SHT30 Read Err!!!\r\n");
- }
- bflb_mtimer_delay_ms(1000);
- /* LED状态翻转,用来识别MCU是否正常工作 */
- if (LED_STA_ON == LEDSta)
- {
- LEDSta = LED_STA_OFF;
- }
- else
- {
- LEDSta = LED_STA_ON;
- }
-
- LED_SetSta(LEDSta);
- }
- }
复制代码 其中除了通过板载的绿色LED灯闪烁来告诉程序正常运行外,与SHT30有关的代码就两行,一行是SHT30初始化调用 SHT30_Init(); /* 初始化SHT30 */,主要是初始化板子外设的IIC0,通信速率设置为400Kbps。另外是调用SHT30读取温湿度函数 SHT30_ReadTempAndHumi(TempAndHumiVal),并通过串口将温湿度值打印出来。打印结果如下
SHT30驱动代码 |