【外设移植】SHT30 温湿度传感器M61开发板驱动

[复制链接]
查看2707 | 回复12 | 2024-1-21 21:14:31 | 显示全部楼层 |阅读模式
本帖最后由 1084504793 于 2024-1-21 21:18 编辑

        SHT30是SHT3X系列温湿度传感器中的一款,除SHT30外,还有SHT31和SHT35。它们的对比如下图所示,
SHT3x系列对比.png
        其中D代表数字量,A代表模拟量。
        在购买SHT30模块的时候需要注意一下的是SHT30-ARP代表输出的是模拟量;SHT30-DIS代表输出的是数字量。
        本文主要介绍的是SHT30-DIS模块,且通信方式是IIC,模块实拍图片如下
SHT30.jpg

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次测量/秒条件下)


引脚数


8个


        该表是从手册中整理而来,因为网上相关的手册基本上都是官方的英文手册,里面有很多的内容没有集体描述出来,中文手册多是通过翻译软件直接翻译的。需要注意的是官方给的文档中写的工作电压是2.4-5.5V,但是在传感器模块背面却印有2.4-2.5V的字样。在测试过程中将模块的工作电压正极VCC接到M61板子的5V或3.3V供电引脚也是可以正常工作的,所以模块的丝印有可能是印刷有误,毕竟印这么窄的供电范围也是很难满足的。
        SHT30芯片引脚如下图所示

GetImage.png
        其中各个引脚说明如下
SHT30引脚说明.png
       需要注意的是购买的模块没有将ADDR、ALERT和nRESET引脚引出来。所以SHT30的IIC通信地址是固定的。我购买的模块是将ADDR接地,也就是接低电平,所以SHT30的IIC通信地址为0x44。若ADDR接高电平,则SHT30的IIC通信地址为0x45。模块也不能进行中断检测,不过官方在这方面的说明不仅少,而且一般也是不会用到该功能的,所以本文也只介绍常用的功能。除了中断的功能没有用到外,还有其自加热功能也没有用到,自加热主要是增加芯片的供电电流而产热,但是实现起来有很大的危险,而且目前有很多的芯片不支持引脚输出大电流,建议用到加热的功能,最好还是购买专门的模块使用。

SHT30驱动编写
        因为官方的驱动是英文版,且很多细节没有完全写出来,中文版也只是硬翻译而已,所以本文直接跳过文档的讲解直接讲解代码相关的内容。我也是看了很多遍的文档和官方给的示例代码,也通过代码不断地进行调试和验证才大概了解SHT30的部分使用方法。
        SHT30模块采用标准的IIC通信,通信速率可以选择400KBps,还是用之前常用的IIC驱动函数就可以实现SHT30的温湿度测量功能。IIC写数据函数定义如下
  1. void IIC_SenCmd(uint8_t _Cmd, uint8_t *Sendbuf, uint16_t _length)
  2. {
  3.         if (SHT30_ADDR)
  4.         {
  5.                 msgs[0].addr = SHT30_ADDR_H;
  6.         }
  7.         else
  8.         {
  9.                 msgs[0].addr = SHT30_ADDR_L;
  10.         }
  11.     msgs[0].flags = I2C_M_NOSTOP;
  12.     msgs[0].buffer = &_Cmd;
  13.     msgs[0].length = 1;

  14.         if (_length != 0)
  15.         {
  16.                 /* 有数据的发送 */
  17.                 if (SHT30_ADDR)
  18.                 {
  19.                         msgs[0].addr = SHT30_ADDR_H;
  20.                 }
  21.                 else
  22.                 {
  23.                         msgs[0].addr = SHT30_ADDR_L;
  24.                 }
  25.              msgs[1].flags = 0;
  26.              msgs[1].buffer = Sendbuf;
  27.              msgs[1].length = _length;
  28.              bflb_i2c_transfer(i2c, msgs, 2);
  29.         }
  30.         else
  31.         {
  32.                 /* 只发一个字节的数据 */
  33.                 msgs[0].flags = 0;
  34.                 bflb_i2c_transfer(i2c, msgs, 1);
  35.         }
  36. }
复制代码
       IIC读数据函数定义如下
  1. void IIC_RecData(uint8_t *_Recbuf, uint16_t _length)
  2. {
  3.            if (SHT30_ADDR)
  4.         {
  5.                 msgs[0].addr = SHT30_ADDR_H;
  6.         }
  7.         else
  8.         {
  9.                 msgs[0].addr = SHT30_ADDR_L;
  10.         }
  11.     msgs[0].flags = I2C_M_READ;
  12.     msgs[0].buffer = _Recbuf;
  13.     msgs[0].length = _length;
  14.     bflb_i2c_transfer(i2c, msgs, 1);
  15. }
复制代码
       这两个函数在之前的驱动移植中也是这样定义,所以不做过多的讲解,代码也是很简单的。
        SHT30有多种测试模式,每种测试模式都是需要发送两个字节的数据指令,其实SHT30的所有指令都是发送两个字节的数据决定的。首先是测试模式发送函数定义,也可以用于所有指令发送,但是其他指令基本没有用到,函数定义如下
  1. SHT30CMDSendResu SHT30_SendTestMode(SHT30CMD _Cmd)
  2. {
  3.         if (_Cmd >= SHT30_CMD_LAST)
  4.         {
  5.                 return SHT30_CMD_SEND_RESU_ERR;
  6.         }
  7.         IIC_SenCmd(SHT30CMDSendData[_Cmd][0], &SHT30CMDSendData[_Cmd][1], SHT30_CMD_LEN_BYTE - 1);

  8.         //printf("Chip Test Mode CMD send over\r\n");
  9.         return SHT30_CMD_SEND_RESU_OK;
  10. }
复制代码
       参数_Cmd为要发送的指令,是一个枚举类型的定义,该枚举定义在SHT30.h文件中,定义如下
  1. /* SHT30支持的指令 */
  2. typedef enum
  3. {
  4.         SHT30_CMD_MEAS_CLOCKSTR_H = 0,   
  5.         SHT30_CMD_MEAS_CLOCKSTR_M,  
  6.         SHT30_CMD_MEAS_CLOCKSTR_L,
  7.         SHT30_CMD_MEAS_POLLING_H,
  8.         SHT30_CMD_MEAS_POLLING_M,
  9.         SHT30_CMD_MEAS_POLLING_L,
  10.         SHT30_CMD_MEAS_PERI_05_H,
  11.         SHT30_CMD_MEAS_PERI_05_M,
  12.         SHT30_CMD_MEAS_PERI_05_L,
  13.         SHT30_CMD_MEAS_PERI_1_H,
  14.         SHT30_CMD_MEAS_PERI_1_M,
  15.         SHT30_CMD_MEAS_PERI_1_L,
  16.         SHT30_CMD_MEAS_PERI_2_H,
  17.         SHT30_CMD_MEAS_PERI_2_M,
  18.         SHT30_CMD_MEAS_PERI_2_L,
  19.         SHT30_CMD_MEAS_PERI_4_H,
  20.         SHT30_CMD_MEAS_PERI_4_M,
  21.         SHT30_CMD_MEAS_PERI_4_L,
  22.         SHT30_CMD_MEAS_PERI_10_H,
  23.         SHT30_CMD_MEAS_PERI_10_M,
  24.         SHT30_CMD_MEAS_PERI_10_L,
  25.         SHT30_CMD_FETCH_DATA,                /* 周期模式的读出测量 */
  26.         SHT30_CMD_ART,                       /* ART(加速响应) */
  27.         SHT30_CMD_STOP_PERI_DATA_ACQU,       /* 中断指令或采集数据 */
  28.         SHT30_CMD_SOFT_RESET,                /* 软复位 */
  29.         SHT30_CMD_RESET_THRO_PIN_NRESET,     /* 硬复位 */
  30.         SHT30_CMD_HEATER_ENABLE,             /* 使能加热器 */
  31.         SHT30_CMD_HEATER_DISABLE,            /* 关闭加热器 */
  32.         SHT30_CMD_READ_STATUS,               /* 读取状态 */
  33.         SHT30_CMD_CLEAR_STATUS,              /* 清除状态 */
  34.         SHT30_CMD_LAST,
  35. }SHT30CMD;
复制代码
       该枚举按照英文手册先后出现的指令一个个的列举出来,方便后续的补充和使用。
        回到指令发送函数中,主要代码是IIC_SenCmd(SHT30CMDSendData[_Cmd][0], &SHT30CMDSendData[_Cmd][1], SHT30_CMD_LEN_BYTE - 1);。主要是调用IIC发送函数,因SHT30的指令是两个字节的数据,所有的参数存放在全局变量SHT30CMDSendData中,所以调用IIC发送驱动函数时参数做了兼容处理。全局变量SHT30CMDSendData定义在SHT30.c中,按照指令的枚举类型的顺序一个个的定义的,这样方便指令的同一管理。大家在使用时可以删除部分不用的指令,以节约M61的资源空间。SHT30CMDSendData的定义如下
  1. /* SHT30指令发送参数值 */
  2. uint8_t SHT30CMDSendData[SHT30_CMD_LAST][SHT30_CMD_LEN_BYTE] =
  3. {
  4.         {0x2C, 0x06},
  5.         {0x2C, 0x0D},
  6.         {0x2C, 0x10},
  7.         {0x24, 0x00},
  8.         {0x24, 0x0B},
  9.         {0x24, 0x16},
  10.         {0x20, 0x32},
  11.         {0x20, 0x24},
  12.         {0x20, 0x2F},
  13.         {0x21, 0x30},
  14.         {0x21, 0x26},
  15.         {0x21, 0x2D},
  16.         {0x22, 0x36},
  17.         {0x22, 0x20},
  18.         {0x22, 0x2B},
  19.         {0x23, 0x34},
  20.         {0x23, 0x22},
  21.         {0x23, 0x29},
  22.         {0x27, 0x37},
  23.         {0x27, 0x21},
  24.         {0x27, 0x2A},
  25.         {0xE0, 0x00},   /* 周期模式的读出测量 */
  26.         {0x2B, 0x32},   /* ART(加速响应) */
  27.         {0x30, 0x93},   /* 中断指令或采集数据 */
  28.         {0x30, 0xA2},   /* 软复位 */
  29.         {0x00, 0x06},   /* 硬复位 */
  30.         {0x30, 0x6D},   /* 使能加热器 */
  31.         {0x30, 0x66},   /* 关闭加热器 */
  32.         {0xF3, 0x2D},   /* 读取状态 */
  33.         {0x30, 0x41},   /* 清除状态 */
  34. };
复制代码
        最后是驱动SHT30正常工作的函数。因官方文档中写出了很多的测试模式,有单次的,有循环的,有低分辨率的,有高分辨率的。但是文档并没有给出详细的区别,也是轻描淡写的,尤其是不同分辨率下的测试模式对应的延时时长没有明确给出,按照字面意思去算延时是有问题。网上的驱动也都是只用那一种测试模式,延时时间是80ms,所以自己写了个测试函数,将所有的测试模式都试了一遍,然后延时都是80ms。测试发现各种模式算出来的数据相差非常小,一般是查小数点后两位。有兴趣的可以改变测试模式的下发,然后查看计算数据的区别,在此不再多说了。设置并读取的函数定义如下
  1. SHT30ReadResu SHT30_ReadTempAndHumi(float *_LuxVal)
  2. {
  3.         uint8_t RecData[7] = {0};
  4.         uint16_t Temp = 0;

  5.         if (SHT30_TEST_MODE > SHT30_CMD_MEAS_PERI_10_L)
  6.         {
  7.                 return SHT30_READ_ERR;
  8.         }
  9.         if (SHT30_CMD_SEND_RESU_ERR == SHT30_SendTestMode(SHT30_TEST_MODE))
  10.         {
  11.                 return SHT30_READ_ERR;
  12.         }

  13.         /* 等待测量完成 */
  14.         bflb_mtimer_delay_ms(50);
  15.         /* 接收测量数据 */
  16.         IIC_RecData(RecData, 6);

  17.         Temp = (RecData[0] << 8) | RecData[1];
  18.         *(_LuxVal++) = (float)Temp * 175.0 / 65535.0 -45.0;
  19.         Temp = (RecData[3] << 8) | RecData[4];
  20.         *_LuxVal = (float)Temp * 100.0 / 65535.0;

  21.         return SHT30_READ_OK;
  22. }
复制代码
       测试模式的选取是通过宏定义SHT30_TEST_MODE决定的,定义在SHT30.h文件中,可以通过修改改变测试模式。测试模式下发后延时80ms,等待模块测量完成。接收数据有六个字节的数据,返回数据格式如下所示
返回数据格式.png
        前两个字节的数据是温度数据,然后紧跟着CRC校验值,之后是湿度数据和湿度数据的CRC校验值。驱动中接收到这六个数据后直接计算温湿度值,对于CRC校验并没有使用,因为用的地方不多。若大家有想用到CRC校验的,可以参考官方给的驱动程序。计算方式也很简单,接收到的数据组成一个十六位的二字节数据,然后乘以100除以65535。将计算结果保存在参数指针中,需要注意的是保存的数值是先保存温度数据,然后是湿度数据,都是计算后的原始数据,没有做放大处理,传递的参数最好是大于等于2的单精度浮点型数组。
        在main.c有调用SHT30驱动的例子,并将获取到的温湿度值通过串口打印出来。main.c文件代码如下
  1. #include "board.h"
  2. #include "SHT30.h"
  3. #include "bflb_gpio.h"

  4. struct bflb_device_s *gpio;

  5. typedef enum
  6. {
  7.         LED_STA_OFF = 0,   /* 关闭 */
  8.         LED_STA_ON,        /* 打开 */
  9.         LED_STA_LAST,
  10. }LedSta;

  11. void LED_Init()
  12. {
  13.         /* 初始化绿灯,用来指示LED状态 */
  14.         gpio = bflb_device_get_by_name("gpio");
  15.     bflb_gpio_init(gpio, GPIO_PIN_14, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
  16. }
  17. void LED_SetSta(LedSta _Sta)
  18. {
  19.         if (_Sta)
  20.         {
  21.                 /* 高电平打开LED */
  22.                 bflb_gpio_set(gpio, GPIO_PIN_14);
  23.         }
  24.         else
  25.         {
  26.                 /* 低电平关闭LED */
  27.                 bflb_gpio_reset(gpio, GPIO_PIN_14);
  28.         }
  29. }
  30. int main(void)
  31. {
  32.         float TempAndHumiVal[2] = {0};
  33.         LedSta LEDSta = LED_STA_ON;
  34.         
  35.         board_init();    /* 板卡初始化 */
  36.         LED_Init();      /* LED初始化 */
  37.         SHT30_Init();   /* 初始化SHT30 */
  38.         LED_SetSta(LEDSta);
  39.     while (1)
  40.         {
  41.                 /* 读取光照强度 */
  42.                 if (SHT30_READ_OK == SHT30_ReadTempAndHumi(TempAndHumiVal))
  43.                 {
  44.                         printf("SHT30 Read Temperature is:%f   Humidity is:%f\r\n",TempAndHumiVal[0],TempAndHumiVal[1]);
  45.                 }
  46.                 else
  47.                 {
  48.                         printf("SHT30 Read Err!!!\r\n");
  49.                 }

  50.                 bflb_mtimer_delay_ms(1000);
  51.                 /* LED状态翻转,用来识别MCU是否正常工作 */
  52.                 if (LED_STA_ON == LEDSta)
  53.                 {
  54.                         LEDSta = LED_STA_OFF;
  55.                 }
  56.                 else
  57.                 {
  58.                         LEDSta = LED_STA_ON;
  59.                 }
  60.                
  61.                 LED_SetSta(LEDSta);
  62.     }
  63. }
复制代码
        其中除了通过板载的绿色LED灯闪烁来告诉程序正常运行外,与SHT30有关的代码就两行,一行是SHT30初始化调用SHT30_Init();   /* 初始化SHT30 */,主要是初始化板子外设的IIC0,通信速率设置为400Kbps。另外是调用SHT30读取温湿度函数SHT30_ReadTempAndHumi(TempAndHumiVal),并通过串口将温湿度值打印出来。打印结果如下
打印结果.png

SHT30驱动代码
        官方文档 SHT30-31-35全套资料.rar (2.9 MB, 下载次数: 3)

本帖被以下淘专辑推荐:

回复

使用道具 举报

干簧管 | 2024-1-21 22:34:37 | 显示全部楼层
👍🏻
回复

使用道具 举报

wukong50 | 2024-1-22 08:13:21 | 显示全部楼层
回复

使用道具 举报

WT_0213 | 2024-1-22 08:33:25 | 显示全部楼层
回复

使用道具 举报

爱笑 | 2024-1-22 08:42:01 | 显示全部楼层
用心做好保姆工作
回复

使用道具 举报

bzhou830 | 2024-1-22 08:54:59 | 显示全部楼层
选择去发光,而不是被照亮
回复

使用道具 举报

lazy | 2024-1-22 11:13:49 | 显示全部楼层
回复

使用道具 举报

timo | 2024-1-22 14:43:28 | 显示全部楼层
回复

使用道具 举报

曹县 | 2024-1-22 17:14:05 | 显示全部楼层
回复

使用道具 举报

wukong50 | 2024-1-23 08:14:58 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则