【Telink B91】1. B91入坑总结以及串口Demo测试
【Telink B91】2. 矩阵按键以及freeRTOS应用
【Telink B91】3. 硬件I2C驱动OLED
【Telink B91】4. 硬件I2C采集HS3003温湿度信息


前言

本文使用硬件I2C驱动HS3003采集环境温湿度信息,HS3003是一块基于I2C通信的温湿度传感器,7为I2C地址为0x44。

本文使用的I2C与上一篇文章中的I2C是同一路,也就是同一根I2C总线上挂载了两哥I2C从机设备,其中一个用于OLED控制,一个用于HS3003。

因为使用了FreeRTOS,所以在I2C通信的时候需要使用互斥量对通信的数据进行保护,避免在通信器件被打断导致通信不正常,本文会对此处做说明。

1 HS3003介绍

1.1 I2C连接

硬件连接如下:

- SCL - PB2
- SDA - PB3

1.2 操作方式

启动HS3003进行采样的操作就是发送HS3003的I2C地址,发送地址之后可以自动启动采样,开始采集数据。如下图:

1688862944472.png

1.3 数据获取

从下图可以看出,发送HS300X地址+低位读就可以获取采集的数据。

**注:重点说明,默认采样精度为14bit,可以通过配置修改,精度越高,采样时间越长,下图中有说明,默认精度下的采样时间为33ms左右,所以在测量请求发出之后,需要等待33毫秒之后在读取。**

1688862996778.png


采集数据分析,从图中可以清楚看出,默认温度和湿度数据都为14bit数据,都占用了两个字节。

其中湿度的高两位为状态为状态位,表示采集数据状态是否有效,见下图:

- 0表示数据采集完成
- 1表示没有完成有效采集。
- 温度的低两位没有任何用处。

1688863019077.png

1.4 采样数据处理

采集到的数据为原始数据,需要进行计算得出真实的温湿度数据,计算公式如下:

1688863068612.png

即:
湿度值(%):采样值/(16383) * 100
温度值(摄氏度):采样值/(16383) * 165 - 40

2 软件开发

如下所示,其中:

- Hs300x_StartSample:开始采集数据,即发送HS3003的地址0x44<<1即可。
- Hs300x_ReadData:为读取数据,读取Hs3003的采样结果

注:发起采样和读取结果之前需要间隔至少33.9ms,用于Hs3003采集数据并进行转换。

从文中可以看到I2C发送与读取都放在了如下函数中。这就是FreeRTOS互斥量,用来保护I2C通信数据用的。如果不使用任何操作系统,裸机跑程序,则无需加保护。
    if (pdTRUE == xSemaphoreTake(Mutex_i2c_Handle, portMAX_DELAY))
  •     {
  •     .....
  •         // release the mutex
  •         (void)xSemaphoreGive(Mutex_i2c_Handle);
  •     }
  • 复制代码


    app_hs3003.c
    /*
  • @hehung
  • 2023-7-9
  • email: 1398660197@qq.com
  • wechat: hehung95
  • reproduced and please indicate the source @hehung
  • */
  • #include "app_hs3003.h"
  • #include "app_hw_i2c.h"
  • #include "app_config.h"
  • #define HS300x_I2C_SLAVE_ADDR_7BIT           (0x44U << 1)
  • #define HS300X_DATA_VALID                    (0x00U)
  • #define HS300X_DATA_STALE                    (0x01U)
  • #define HS300X_STATUS_MASK                   (0xC0000000U)
  • #define HS300X_STATUS_POS                    (30U)
  • #define HS300X_DATA_MASK                     (0x3FFFFFFCU)
  • #define HS300X_HUMI_DATA_MASK                (0x3FFF0000U)
  • #define HS300X_HUMI_DATA_POS                 (16U)
  • #define HS300X_TEMP_DATA_MASK                (0x0000FFFCU)
  • #define HS300X_TEMP_DATA_POS                 (2U)
  • /* calculation formula, 2^14 - 1 */
  • #define HS300X_DATA_FACTOR                   (16383U)
  • static uint8_t Hs300x_DataConvert(uint32_t read_data, s_Hs300xDataType *cal_result);
  • static uint8_t Hs300x_DataConvert(uint32_t read_data, s_Hs300xDataType *cal_result)
  • {
  •     uint32_t humi_data;
  •     uint32_t temp_data;
  •     if (((read_data & HS300X_STATUS_MASK) >> HS300X_STATUS_POS) == HS300X_DATA_VALID)
  •     {
  •         // Data is valid
  •         humi_data = (read_data & HS300X_HUMI_DATA_MASK) >> HS300X_HUMI_DATA_POS;
  •         temp_data = (read_data & HS300X_TEMP_DATA_MASK) >> HS300X_TEMP_DATA_POS;
  •         // Calculate the humidity: humi_data/(2^14-1) * 100
  •         cal_result->humi = (double)humi_data/(double)(HS300X_DATA_FACTOR) * 100.0;
  •         // Calculate the temperature: temp_data/(2^14-1) * 165 - 40
  •         cal_result->temp = (double)temp_data/(double)(HS300X_DATA_FACTOR) * 165.0 - 40;
  •    
  •         return 1;
  •     }
  •     else
  •     {
  •         DEBUG ("\r\n Wrong data sample \r\n");
  •         return 0;
  •     }
  • }
  • void Hs300x_StartSample(void)
  • {
  •     uint8_t data = 0;
  •     if (pdTRUE == xSemaphoreTake(Mutex_i2c_Handle, portMAX_DELAY))
  •     {
  •         // Only send the address to start HS300X convert
  •         i2c_master_write(HS300x_I2C_SLAVE_ADDR_7BIT, &data, 0);
  •         // release the mutex
  •         (void)xSemaphoreGive(Mutex_i2c_Handle);
  •     }
  • }
  • s_Hs300xDataType Hs300x_ReadData(void)
  • {
  •     uint8_t data[4];  // one address + 4bytes data
  •     uint32_t data_u32;
  •     s_Hs300xDataType humi_temp;
  •     // Read measurement from sensor HS300X
  •     if (pdTRUE == xSemaphoreTake(Mutex_i2c_Handle, portMAX_DELAY))
  •     {
  •         // Only send the address to start HS300X convert
  •         i2c_master_read(HS300x_I2C_SLAVE_ADDR_7BIT, data, 4);
  •         // release the mutex
  •         (void)xSemaphoreGive(Mutex_i2c_Handle);
  •     }
  •     // Convert the data to 32bit
  •     data_u32 = (uint32_t)((data[0] << 24U) |
  •                           (data[1] << 16U) |
  •                           (data[2] << 8U) |
  •                           (data[3]));
  •     // Read the temperature and humidity
  •     (void)Hs300x_DataConvert(data_u32, &humi_temp);
  • //#ifdef HS300X_DEBUG
  •     DEBUG ("HS300X origin data1:%02x%02x%02x%02x\r\n", data[0],data[1],data[2],data[3]);
  •     // printf("HS300X origin data2:%x\n", data_u32);
  •     DEBUG ("Temp:%f--Humi:%f\r\n", humi_temp.temp, humi_temp.humi);
  • //#endif
  •     return humi_temp;
  • }
  • 复制代码


    app_hs3003.h
    /*
  • @hehung
  • 2023-7-9
  • email: 1398660197@qq.com
  • wechat: hehung95
  • reproduced and please indicate the source @hehung
  • */
  • #ifndef APP_HS3003_H__
  • #define APP_HS3003_H__
  • typedef struct
  • {
  •     double humi;
  •     double temp;
  • } s_Hs300xDataType;
  • extern s_Hs300xDataType Hs300x_ReadData(void);
  • extern void Hs300x_StartSample(void);
  • #endif
  • 复制代码


    新建一个任务,用来采集HS3003的数据,如下:
        xTaskCreate(Os_TaskSensor, "sensor_t", 1024*2, (void*)0, 1, 0);
    复制代码

    // Sensor sample task
  • static void Os_TaskSensor(void *pvParameters)
  • {
  •     (void)(pvParameters);
  •     // Initialize
  •     while(1)
  •     {
  •         // Sample for HS3003
  •         // Start HS300X
  •         Hs300x_StartSample();
  •         // Delay 50ms for waiting for temperature/humidity calculate result
  •         vTaskDelay(500);
  •         // Read sample result
  •         Hs300x_ReadData();
  •         // Sample every 1s
  •         vTaskDelay(500);
  •     }
  • }
  • 复制代码


    3 测试结果

    将采集到的数据解析为温度和湿度之后,如下图所示:

    1688828979802.png