【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地址,发送地址之后可以自动启动采样,开始采集数据。如下图:
1.3 数据获取
从下图可以看出,发送HS300X地址+低位读就可以获取采集的数据。
**注:重点说明,默认采样精度为14bit,可以通过配置修改,精度越高,采样时间越长,下图中有说明,默认精度下的采样时间为33ms左右,所以在测量请求发出之后,需要等待33毫秒之后在读取。**
采集数据分析,从图中可以清楚看出,默认温度和湿度数据都为14bit数据,都占用了两个字节。
其中湿度的高两位为状态为状态位,表示采集数据状态是否有效,见下图:
- 0表示数据采集完成
- 1表示没有完成有效采集。
- 温度的低两位没有任何用处。
1.4 采样数据处理
采集到的数据为原始数据,需要进行计算得出真实的温湿度数据,计算公式如下:
即:
湿度值(%):采样值/(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 测试结果
将采集到的数据解析为温度和湿度之后,如下图所示: