【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通信数据用的。如果不使用任何操作系统,裸机跑程序,则无需加保护。
  1.     if (pdTRUE == xSemaphoreTake(Mutex_i2c_Handle, portMAX_DELAY))
  2.     {
  3.     .....
  4.         // release the mutex
  5.         (void)xSemaphoreGive(Mutex_i2c_Handle);
  6.     }


app_hs3003.c
  1. /*
  2. @hehung
  3. 2023-7-9
  4. email: 1398660197@qq.com
  5. wechat: hehung95
  6. reproduced and please indicate the source @hehung
  7. */
  8. #include "app_hs3003.h"
  9. #include "app_hw_i2c.h"
  10. #include "app_config.h"
  11. #define HS300x_I2C_SLAVE_ADDR_7BIT           (0x44U << 1)
  12. #define HS300X_DATA_VALID                    (0x00U)
  13. #define HS300X_DATA_STALE                    (0x01U)
  14. #define HS300X_STATUS_MASK                   (0xC0000000U)
  15. #define HS300X_STATUS_POS                    (30U)
  16. #define HS300X_DATA_MASK                     (0x3FFFFFFCU)
  17. #define HS300X_HUMI_DATA_MASK                (0x3FFF0000U)
  18. #define HS300X_HUMI_DATA_POS                 (16U)
  19. #define HS300X_TEMP_DATA_MASK                (0x0000FFFCU)
  20. #define HS300X_TEMP_DATA_POS                 (2U)
  21. /* calculation formula, 2^14 - 1 */
  22. #define HS300X_DATA_FACTOR                   (16383U)
  23. static uint8_t Hs300x_DataConvert(uint32_t read_data, s_Hs300xDataType *cal_result);
  24. static uint8_t Hs300x_DataConvert(uint32_t read_data, s_Hs300xDataType *cal_result)
  25. {
  26.     uint32_t humi_data;
  27.     uint32_t temp_data;
  28.     if (((read_data & HS300X_STATUS_MASK) >> HS300X_STATUS_POS) == HS300X_DATA_VALID)
  29.     {
  30.         // Data is valid
  31.         humi_data = (read_data & HS300X_HUMI_DATA_MASK) >> HS300X_HUMI_DATA_POS;
  32.         temp_data = (read_data & HS300X_TEMP_DATA_MASK) >> HS300X_TEMP_DATA_POS;
  33.         // Calculate the humidity: humi_data/(2^14-1) * 100
  34.         cal_result->humi = (double)humi_data/(double)(HS300X_DATA_FACTOR) * 100.0;
  35.         // Calculate the temperature: temp_data/(2^14-1) * 165 - 40
  36.         cal_result->temp = (double)temp_data/(double)(HS300X_DATA_FACTOR) * 165.0 - 40;
  37.    
  38.         return 1;
  39.     }
  40.     else
  41.     {
  42.         DEBUG ("\r\n Wrong data sample \r\n");
  43.         return 0;
  44.     }
  45. }
  46. void Hs300x_StartSample(void)
  47. {
  48.     uint8_t data = 0;
  49.     if (pdTRUE == xSemaphoreTake(Mutex_i2c_Handle, portMAX_DELAY))
  50.     {
  51.         // Only send the address to start HS300X convert
  52.         i2c_master_write(HS300x_I2C_SLAVE_ADDR_7BIT, &data, 0);
  53.         // release the mutex
  54.         (void)xSemaphoreGive(Mutex_i2c_Handle);
  55.     }
  56. }
  57. s_Hs300xDataType Hs300x_ReadData(void)
  58. {
  59.     uint8_t data[4];  // one address + 4bytes data
  60.     uint32_t data_u32;
  61.     s_Hs300xDataType humi_temp;
  62.     // Read measurement from sensor HS300X
  63.     if (pdTRUE == xSemaphoreTake(Mutex_i2c_Handle, portMAX_DELAY))
  64.     {
  65.         // Only send the address to start HS300X convert
  66.         i2c_master_read(HS300x_I2C_SLAVE_ADDR_7BIT, data, 4);
  67.         // release the mutex
  68.         (void)xSemaphoreGive(Mutex_i2c_Handle);
  69.     }
  70.     // Convert the data to 32bit
  71.     data_u32 = (uint32_t)((data[0] << 24U) |
  72.                           (data[1] << 16U) |
  73.                           (data[2] << 8U) |
  74.                           (data[3]));
  75.     // Read the temperature and humidity
  76.     (void)Hs300x_DataConvert(data_u32, &humi_temp);
  77. //#ifdef HS300X_DEBUG
  78.     DEBUG ("HS300X origin data1:%02x%02x%02x%02x\r\n", data[0],data[1],data[2],data[3]);
  79.     // printf("HS300X origin data2:%x\n", data_u32);
  80.     DEBUG ("Temp:%f--Humi:%f\r\n", humi_temp.temp, humi_temp.humi);
  81. //#endif
  82.     return humi_temp;
  83. }


app_hs3003.h
  1. /*
  2. @hehung
  3. 2023-7-9
  4. email: 1398660197@qq.com
  5. wechat: hehung95
  6. reproduced and please indicate the source @hehung
  7. */
  8. #ifndef APP_HS3003_H__
  9. #define APP_HS3003_H__
  10. typedef struct
  11. {
  12.     double humi;
  13.     double temp;
  14. } s_Hs300xDataType;
  15. extern s_Hs300xDataType Hs300x_ReadData(void);
  16. extern void Hs300x_StartSample(void);
  17. #endif


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

  1. // Sensor sample task
  2. static void Os_TaskSensor(void *pvParameters)
  3. {
  4.     (void)(pvParameters);
  5.     // Initialize
  6.     while(1)
  7.     {
  8.         // Sample for HS3003
  9.         // Start HS300X
  10.         Hs300x_StartSample();
  11.         // Delay 50ms for waiting for temperature/humidity calculate result
  12.         vTaskDelay(500);
  13.         // Read sample result
  14.         Hs300x_ReadData();
  15.         // Sample every 1s
  16.         vTaskDelay(500);
  17.     }
  18. }


3 测试结果

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

1688828979802.png