瑞萨单片机论坛
直播中

hehung

8年用户 659经验值
擅长:嵌入式技术
私信 关注
[经验]

【RA4M2设计挑战赛】2. 硬件IIC读取HS3003的温湿度数据

过往分享

下面是参加RA4M2使用活动的分享:
【瑞萨RA4系列开发板体验】1. 新建工程+按键控制LED
【瑞萨RA4系列开发板体验】2. KEIL环境搭建+STLINK调试+FreeRTOS使用
【瑞萨RA4系列开发板体验】3. KEIL下UART实现printf与scanf重定向
【瑞萨RA4系列开发板体验】4. PWM驱动LED
【瑞萨RA4系列开发板体验】5. 硬件IIC驱动OLED显示汉字
【瑞萨RA4系列开发板体验】6. ADC测量摇杆模块偏移量
【瑞萨RA4系列开发板体验】7. 用DAC输出正弦波以及余弦波
【瑞萨RA4系列开发板体验】8. 超声波测距模块在RA4M2上的应用
【瑞萨RA4系列开发板体验】9. 用两路DAC在示波器上显示一个爱心

RA4M2挑战赛分享:
【RA4M2设计挑战赛】1. RASC配置FreeRTOS

前言

本文将操作官方模块HS300X(温湿度传感器),基于FreeRTOS作为OS,实现硬件IIC采集HS3003的温湿度数据。

HS300X原理图

00.jpg

通过对比了RA4M2开发板的PMOD接口以及HS300X的接口,HS300X是IIC接口,但是单片机的PMOD接口没有一个对应的IIC接口可以匹配,所以我们将HS300X直接和单片机的IIC引脚连接,不通过PMOD连接。

IIC接口

由于OLED也是IIC接口的,OLED操作可以参考我之前的帖子:【瑞萨RA4系列开发板体验】5. 硬件IIC驱动OLED显示汉字
OLED使用的是sci3的硬件i2c接口

所以我打算将HS300X也接到sci3 i2x接口上,即:
SCL3 - P408
SDA3 - P409

HS300X操作方式

虽然知道了HS300X是IIC接口,但是我们还不知道该如何操作,需要了解HS300X的操作方式,寄存器,IIC地址等,查看官方提供的手册《REN_HS300x-Datasheet_DST_20210809.pdf》

测量请求

通过直接写HS300X地址就可以唤醒传感器,然后自动采集数据,说明见下:
从下图中可以看到IIC地址为0x44,然后加一个低位1表示写,就可以触发转换。
01.jpg

数据获取

从下图可以看出,发送HS300X地址+低位读就可以获取采集的数据。
注:重点说明,默认采样精度为14bit,可以通过配置修改,精度越高,采样时间越长,下图中有说明,默认精度下的采样时间为33ms左右,所以在测量请求发出之后,需要等待33毫秒之后在读取
02.jpg

采集数据分析,从图中可以清楚看出,默认温度和湿度数据都为14bit数据,都占用了两个字节,其中湿度的高两位为状态为,表示采集数据状态,见下图,为0表示数据采集完成,1表示没有完成有效采集。
温度的低两位没有任何用处。
03.jpg

采样精度修改

采样精度可以修改,精度月底,采样时间越快。可以通过下属寄存器进行修改,该部分本文不会实现,只作为功能想描述。
修改方式也很简单,IIC地址+低位写0+修改精度寄存器地址+精度即可完成修改,详情参考数据手册。
07.jpg

采样数据处理

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

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

软件编写

知道了硬件设置以及原理,现在可以看是编写软件了,如下:
app_Hs300x.c

/*
@hehung
2023-2-8
转载请注明出处,版权由@hehung所有
email: 1398660197qq.com
wechat: hehung95
*/

/*******************************************************************************
 * Header Include
 ******************************************************************************/
#include "hal_data.h"
#include "app_hw_i2c.h"
#include "app_hs300x.h"

#define HS300X_DEBUG
#undef HS300X_DEBUG

#ifdef HS300X_DEBUG
#include <stdio.h>
#endif 

/*******************************************************************************
 * Macro Definitions
 ******************************************************************************/
#define HS300x_I2C_SLAVE_ADDR_7BIT           (0x44U)

#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 Variables Definitions 
 ******************************************************************************/

/*******************************************************************************
 * Static Function Declarations 
 ******************************************************************************/
static void Hs300x_ReadFromI2C(uint8_t *data_buffer, uint8_t data_len);
static void Hs300x_WriteToI2C(uint8_t *data_buffer, uint8_t data_len);
static bool Hs300x_DataConvert(uint32_t read_data, s_Hs300xDataType *cal_result);

/*******************************************************************************
 * Function Definitions 
 ******************************************************************************/
/*********************Hs300x读数据函数************************************/
static void Hs300x_ReadFromI2C(uint8_t *data_buffer, uint8_t data_len)
{
	fsp_err_t err;
	uint32_t timeout_ms = 100;

    // setting mutex for lock sci3_i2c bus
    if (pdTRUE == xSemaphoreTake(mutex_sci3_i2c, portMAX_DELAY))
    {
		R_SCI_I2C_SlaveAddressSet(&g_sci3_i2c_ctrl, 
								HS300x_I2C_SLAVE_ADDR_7BIT, 
								I2C_MASTER_ADDR_MODE_7BIT);

		err = R_SCI_I2C_Read(&g_sci3_i2c_ctrl, data_buffer, data_len, true);
		assert(FSP_SUCCESS == err);
		
		/* Since there is nothing else to do, block until Callback triggers*/
		while ((I2C_MASTER_EVENT_TX_COMPLETE != sci3_i2c_event) && timeout_ms>0)
		{
			R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
			timeout_ms--;
		}
		
		if (I2C_MASTER_EVENT_ABORTED == sci3_i2c_event)
		{
			__BKPT(0);
		}
		/* Read data back from the I2C slave */
		sci3_i2c_event = I2C_MASTER_EVENT_ABORTED;

 		// release the mutex, unlock
        (void)xSemaphoreGive(mutex_sci3_i2c);
    }
}

/*********************Hs300x写数据函数************************************/
static void Hs300x_WriteToI2C(uint8_t *data_buffer, uint8_t data_len)
{
	fsp_err_t err;
	uint32_t timeout_ms = 100;

	// setting mutex for lock sci3_i2c bus
    if (pdTRUE == xSemaphoreTake(mutex_sci3_i2c, portMAX_DELAY))
    {
		R_SCI_I2C_SlaveAddressSet(&g_sci3_i2c_ctrl, 
									HS300x_I2C_SLAVE_ADDR_7BIT, 
									I2C_MASTER_ADDR_MODE_7BIT);

		err = R_SCI_I2C_Write(&g_sci3_i2c_ctrl, data_buffer, data_len, true);
		assert(FSP_SUCCESS == err);
		
		/* Since there is nothing else to do, block until Callback triggers*/
		while ((I2C_MASTER_EVENT_TX_COMPLETE != sci3_i2c_event) && timeout_ms>0)
		{
			R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
			timeout_ms--;
		}
		
		if (I2C_MASTER_EVENT_ABORTED == sci3_i2c_event)
		{
			__BKPT(0);
		}
		/* Read data back from the I2C slave */
		sci3_i2c_event = I2C_MASTER_EVENT_ABORTED;

 		// release the mutex, unlock
        (void)xSemaphoreGive(mutex_sci3_i2c);
    }
}

static bool 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;
#ifdef HS300X_DEBUG
		printf("humidity:%f, temperature:%f\n", cal_result->humi, cal_result->temp);
#endif
		
		return true;
	}
	else
	{
		return false;
	}
}

void Hs300x_Init(void)
{
    // Do not settings, keep default settings in sensor device
}

s_Hs300xDataType Hs300x_ReadData(void)
{
    uint8_t data[4];
	uint32_t data_u32;
	s_Hs300xDataType humi_temp;
	
	// Write address start measurement
    Hs300x_WriteToI2C(NULL, 0);
	// Delay 50ms for waiting for convert finished
	vTaskDelay(pdMS_TO_TICKS(50));
	// Read measurement from sensor HS300X
	Hs300x_ReadFromI2C(data, 4);
	// Convert the data to 32bit
	data_u32 = (uint32_t)((data[0] << 24U) | 
	                      (data[1] << 16U) | 
	                      (data[2] << 8U) | 
	                      (data[3]));
	// Read the temperature and hunidity
	(void)Hs300x_DataConvert(data_u32, &humi_temp);
	
#ifdef HS300X_DEBUG
	printf("HS300X origin data1:%x%x%x%x\n", data[0],data[1],data[2],data[3]);
	// printf("HS300X origin data2:%x\n", data_u32);
#endif

	return humi_temp;
}

app_Hs300x.h

/*
@hehung
2023-2-8
转载请注明出处,版权由@hehung所有
email: 1398660197qq.com
wechat: hehung95
*/

#ifndef APP_HS300X_H_
#define APP_HS300X_H_

#include "app_common.h"

typedef struct 
{
    double humi;
    double temp;
} s_Hs300xDataType;

extern void Hs300x_Init(void);
extern s_Hs300xDataType Hs300x_ReadData(void);

#endif /* APP_HS300X_H_ */

新建一个任务,然后写入如下代码开始测试验证。

#define DISP_DEBUG

// Display sensor information: humidity/temperature/light strength
static void Disp_SensorMonitor(void)
{
    s_Hs300xDataType humi_temp;

    humi_temp = Hs300x_ReadData();
#ifdef DISP_DEBUG
	printf("humidity: %.2f%%, temperature: %.2fC\n", humi_temp.humi, humi_temp.temp);
#endif
}

试验结果

06.jpg

更多回帖

发帖
×
20
完善资料,
赚取积分