【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 1688862944472.png](https://static.assets-stash.eet-china.com/forum/202307/09/084831xq6l68zhzji2qh5l.png)
1.3 数据获取
从下图可以看出,发送HS300X地址+低位读就可以获取采集的数据。
**注:重点说明,默认采样精度为14bit,可以通过配置修改,精度越高,采样时间越长,下图中有说明,默认精度下的采样时间为33ms左右,所以在测量请求发出之后,需要等待33毫秒之后在读取。**
![1688862996778.png 1688862996778.png](https://static.assets-stash.eet-china.com/forum/202307/09/084831eqz3lllxqknlltmk.png)
采集数据分析,从图中可以清楚看出,默认温度和湿度数据都为14bit数据,都占用了两个字节。
其中湿度的高两位为状态为状态位,表示采集数据状态是否有效,见下图:
- 0表示数据采集完成
- 1表示没有完成有效采集。
- 温度的低两位没有任何用处。
![1688863019077.png 1688863019077.png](https://static.assets-stash.eet-china.com/forum/202307/09/084832g4pwihuuw4wbp3hh.png)
1.4 采样数据处理
采集到的数据为原始数据,需要进行计算得出真实的温湿度数据,计算公式如下:
![1688863068612.png 1688863068612.png](https://static.assets-stash.eet-china.com/forum/202307/09/084833pkerteeavw2oeoqv.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 taskstatic 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 1688828979802.png](https://static.assets-stash.eet-china.com/forum/202307/09/084830uwxk90fx2cqqpbek.png)