目录
概述
1 软硬件介绍
1.1 软件版本信息
1.2 认识HS3003
1.2.1 HS3003特性
1.2.2 HS3003寄存器
1.2.2.1 温湿度数据寄存器
1.2.2.2 参数寄存器
1.2.2.3 一个参数配置Demo
1.2.3 温湿度值转换
1.2.4 HS3003应用电路
1.2.4.1 PIN引脚定义
1.2.4.2 sensor 应用电路
1.3 MCU与HS3003对应关系
2 FSP配置项目
2.1 配置项目参数
2.2 生成项目文件架构
3 代码实现
3.1 I2C的库函数
3.1.1 R_SCI_I2C_Open()
3.1.2 R_SCI_I2C_Read()
3.1.3 R_SCI_I2C_Write()
3.2 应用函数接口
3.2.1 初始化函数
3.2.2 读数据函数
3.2.3 写数据函数
3.2.4 回调函数
3.3 源代码文件
4 HS3003驱动实现
4.1 编写驱动程序
4.2 编写测试代码
5 测试
概述
本文主要介绍使用Renesas MCU之i2c读写数据功能,包括硬件资源介绍,FSP配置项目的方法,还介绍了SCI_I2C的接口函数,笔者使用一款I2C接口类型的Sensor(HS3003)作为Device,使用I2C接口驱动该sensor,还编写测试函数验证其功能。
1 软硬件介绍
1.1 软件版本信息
软硬件信息 | 版本信息 |
---|---|
Renesas MCU | R7FA4M2AD3C |
Keil | MDK ARM 5.38 |
FSP 版本 | 5.3.0 |
调试工具:st-link | ST-LINK/V2-1 |
注意:
在Keil MDK中可以更改FSP的版本,方法如下
1.2 认识HS3003
1.2.1 HS3003特性
HS3003是瑞萨公司出品的一款高精度温湿度传感器,下面看看其主要参数:
1.2.2 HS3003寄存器
HS3003采用标准的I2C通信方式,对其寄存器的操作必须遵循标准的I2C时序。现在分析如何操作其寄存器,读取数据。
1.2.2.1 温湿度数据寄存器
温湿度数据寄存器的数据位定义如下,其主要由四个字节组成一个32bit数据, bit-0 和 bit-1为Mask,其主要用来标记当前数据是否有效(mask =0 数据有效), 温度数据(低16 bit ): bit-2 ~ bit ~ 15
湿度数据( 高16 bit): bit-8 ~ bit 13
采样温湿度数据间隔时间根据配置的ADC精度来选取,精度要求越高,采样所需要的时间就越长。那么读取数据时,需要等待的时间就越长。
1.2.2.2 参数寄存器
精度参数如下:
参数寄存器列表
如何配置参数呢?芯片手册给了四个步骤
1.2.2.3 一个参数配置Demo
下面给一个各一个配置参数的范例,配置humidity 的采集精度为12bit, 那么参数设定如下:
bit-10: 0
bit-11: 1
typedef struct
{
unsigned short res1 : 10;
unsigned short tempdata : 2;
unsigned short res2 : 4;
} stru_para_bit;
typedef struct{
union
{
unsigned short data;
stru_para_bit para_bit;
};
}stru_para;
int hs300x_init(void)
{
int ret;
unsigned char buff[4];
stru_para para;
// step-1 write data from 0x06
buff[0] = 0x06;
buff[1] = 0;
buff[2] = 0;
ret = write(fd, buff, 3);
if( ret < 0 )
{
printf("read temper cmd to hs3003 register failure.\n");
return -1;
}
// step -2: read reg - 0x81
buff[0] = 0x81;
ret = write(fd, buff, 1);
if( ret < 0 )
{
printf("read cmd to hs3003 register failure. \r\n");
return -1;
}
ret = read(fd, buff, 2);
if( ret < 0 )
{
printf("write cmd to hs3003 register failure.\n");
return -1;
}
printf(" read reg: 0x81 - data0 = %02x data1 = %02x \r\n",buff[0],buff[1]);
//step -3: write data from 0x46
para.data = buff[0]<<8 | buff[1];
para.para_bit.tempdata = 1;
buff[0] = 0x46;
buff[1] = (unsigned char)para.data;
buff[2] = (unsigned char)(para.data>>8);
ret = write(fd, buff, 3);
if( ret < 0 )
{
printf("write cmd to hs3003 register failure. \r\n");
return -1;
}
printf("write reg: 0x46 - data0 = %02x data1 = %02x \r\n",buff[0],buff[1]);
return 0;
}
1.2.3 温湿度值转换
datasheet中给的转换公式如下:
下面看看在程序中如何实现温湿度值转换的
首先定义一个数据结构
typedef struct
{
unsigned int mask : 2;
unsigned int tempdata : 14;
unsigned int humidydata : 14;
unsigned int res : 2;
} Datafetch_bit;
typedef struct{
union
{
unsigned int data;
Datafetch_bit fetch_bit;
};
float tempval;
float humival;
}hs300x_data;
从温湿度的数据寄存器中读取出来有四个分别为8bit的数据, 将该数据拼成一个32bit的数据,在赋值给data, 上述数据结构会自动解析该数据。通过mask位判断数据是否有效。
phs300x_data->data = ((buff[0] << 24U) |(buff[1] << 16U) |(buff[2] << 8U)|(buff[3]));
if( phs300x_data->fetch_bit.mask == HS300X_DATA_VALID){
// get temperature value
val = phs300x_data->fetch_bit.tempdata;
phs300x_data->tempval = (double)val/(double)(HS300X_DATA_FACTOR) * 165.0 - 40;
printf(" - TM(C): %.2f \r\n", phs300x_data->tempval);
// get humidity value
val = phs300x_data->fetch_bit.humidydata;
phs300x_data->humival = (double)val/(double)(HS300X_DATA_FACTOR) * 100.0;
printf(" - HM(\%): %.2f \r\n", phs300x_data->humival);
}
1.2.4 HS3003应用电路
1.2.4.1 PIN引脚定义
传感器封装
pin引脚
1.2.4.2 sensor 应用电路
下面是传感器模块的实际应用电路:
1.3 MCU与HS3003对应关系
MCU接口 | HS3003 | 功能 |
---|---|---|
P409 | SDA | I2C数据端口 |
P408 | SCL | I2C时钟接口 |
2 FSP配置项目
2.1 配置项目参数
1)配置系统时钟,根据硬件特性配置时钟,笔者的板卡上的晶振为12M Hz
2) 在Pins面板配置SCI3,使能I2C,并且配置IO端口
3)在Stacks面板创建i2c的object
配置参数
2.2 生成项目文件架构
点击Generate Project content 按钮,生成项目文件,其文件架构如下:
3 代码实现
3.1 I2C的库函数
3.1.1 R_SCI_I2C_Open()
函数原型:
fsp_err_t R_SCI_I2C_Open ( i2c_master_ctrl_t *const p_api_ctrl,
i2c_master_cfg_t const *const p_cfg )
函数功能: 打开I2C设备
返回值介绍:
FSP_SUCCESS Requested clock rate was set exactly. FSP_ERR_ALREADY_OPEN Module is already open. FSP_ERR_IP_CHANNEL_NOT_PRESENT Channel is not available on this MCU. FSP_ERR_ASSERTION Parameter check failure due to one or more reasons below:
- p_api_ctrl or p_cfg is NULL.
- extended parameter is NULL.
- Callback parameter is NULL.
- Clock rate requested is greater than 400KHz
- Invalid IRQ number assigned
3.1.2 R_SCI_I2C_Read()
函数原型:
fsp_err_t R_SCI_I2C_Read ( i2c_master_ctrl_t *const p_api_ctrl,
uint8_t *const p_dest,
uint32_t const bytes,
bool const restart )
函数功能: 从I2C设备执行读取操作。当操作(成功)完成时,调用者将通过回调中的I2C_MASTER_EVENT_RX_COMPLETE收到通知。
返回值:
FSP_SUCCESS Function executed without issue. FSP_ERR_ASSERTION The parameter p_ctrl, p_dest is NULL, bytes is 0. FSP_ERR_INVALID_SIZE Provided number of bytes more than uint16_t size (65535) while DTC is used for data transfer. FSP_ERR_NOT_OPEN Device was not even opened.
3.1.3 R_SCI_I2C_Write()
函数原型:
fsp_err_t R_SCI_I2C_Write ( i2c_master_ctrl_t *const p_api_ctrl,
uint8_t *const p_src,
uint32_t const bytes,
bool const restart )
函数功能: 对I2C设备进行写操作,如果相关通道上已经有正在进行的I2C传输,则此函数将失败。否则,将开始I2C写操作。当用户没有提供回调时,该函数执行阻塞写入。否则,写操作是非阻塞的,并且当操作完成时将通过回调中的I2C_EVENT_TX_COMPLETE通知调用者。
返回值:
FSP_SUCCESS Function executed without issue. FSP_ERR_ASSERTION p_ctrl, p_src is NULL. FSP_ERR_INVALID_SIZE Provided number of bytes more than uint16_t size (65535) while DTC is used for data transfer. FSP_ERR_NOT_OPEN Device was not even opened.
3.2 应用函数接口
创建bsp_i2c.c文件,实现i2c的应用函数接口
3.2.1 初始化函数
代码第24行:打开端口
代码第27行:设置设备地址
3.2.2 读数据函数
代码第54行:从设备中读取数据
代码第57行:判断接收数据是否完成
3.2.3 写数据函数
代码第36行:从设备中写数据
代码第41行:判断写数据是否完成
3.2.4 回调函数
代码第16行:接收当前event
3.3 源代码文件
创建 bsp_i2c.c文件,编写以下代码:
/*
FILE NAME : bsp_i2c.c
Description: i2c interface function
Author : tangmingfei2013@126.com
Date : 2024/06/03
*/
#include "bsp_i2c.h"
#include "hal_data.h"
i2c_master_event_t g_i2c_callback_event;
void g_i2c2_callback (i2c_master_callback_args_t * p_args)
{
if (NULL != p_args)
{
g_i2c_callback_event = p_args->event;
}
}
void i2c2_init_para( uint32_t const slaveAddress )
{
fsp_err_t err;
err = R_SCI_I2C_Open(&g_i2c2_ctrl, &g_i2c2_cfg);
assert(FSP_SUCCESS == err);
err = R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, slaveAddress, I2C_MASTER_ADDR_MODE_7BIT);
assert(FSP_SUCCESS == err);
}
void i2c2_write_bytes(uint8_t *pbuff, uint16_t length )
{
unsigned int timeout_ms = 100;
fsp_err_t err;
err = R_SCI_I2C_Write(&g_i2c2_ctrl, pbuff, length, false);
assert(FSP_SUCCESS == err);
g_i2c_callback_event = I2C_MASTER_EVENT_ABORTED;
/* Since there is nothing else to do, block until Callback triggers*/
while ((I2C_MASTER_EVENT_TX_COMPLETE != g_i2c_callback_event) && timeout_ms)
{
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
timeout_ms--;;
}
}
void i2c2_read_bytes(uint8_t *pbuff, uint16_t length )
{
unsigned int timeout_ms = 100;
fsp_err_t err;
g_i2c_callback_event = I2C_MASTER_EVENT_ABORTED;
err = R_SCI_I2C_Read(&g_i2c2_ctrl, pbuff, length, false);
assert(FSP_SUCCESS == err);
/* Since there is nothing else to do, block until Callback triggers*/
while ((I2C_MASTER_EVENT_RX_COMPLETE != g_i2c_callback_event) && timeout_ms)
{
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
timeout_ms--;;
}
}
/* End of this file */
4 HS3003驱动实现
4.1 编写驱动程序
1)创建hs3003_drv.c文件,编写如下代码:
/*
FILE NAME : hs3003_drv.c
Description: hs3003 driver
Author : tangmingfei2013@126.com
Date : 2024/06/03
*/
#include "bsp_i2c.h"
#include "hal_data.h"
#include "hs3003_drv.h"
int hs300x_init(void)
{
unsigned char buff[4];
stru_para para;
i2c2_init_para(HS300X_ADDR);
// step-1 write data from 0x06
buff[0] = 0x06;
buff[1] = 0;
buff[2] = 0;
i2c2_write_bytes(buff, 3);
// step -2: read reg - 0x81
buff[0] = 0x81;
i2c2_write_bytes(buff, 1);
i2c2_read_bytes(buff, 2);
//step -3: write data from 0x46
para.data = (unsigned int)(buff[0]<<8 | buff[1]);
para.para_bit.tempdata = 1;
buff[0] = 0x46;
buff[1] = (unsigned char)para.data;
buff[2] = (unsigned char)(para.data>>8);
i2c2_write_bytes( buff, 3);
return 0;
}
int hs300x_read_value(hs300x_data *phs300x_data)
{
unsigned char buff[4];
unsigned int val;
stru_para para;
// write data to 0xa0
para.data = 0;
buff[0] = 0xa0;
buff[1] = (unsigned char)para.data;
buff[2] = (unsigned char)(para.data>>8);
i2c2_write_bytes(buff, 3);
R_BSP_SoftwareDelay( 1, BSP_DELAY_UNITS_MILLISECONDS);
i2c2_read_bytes(buff, 4);
phs300x_data->data = (unsigned int)((buff[0] << 24U) |(buff[1] << 16U) |(buff[2] << 8U)|(buff[3]));
if( phs300x_data->fetch_bit.mask == HS300X_DATA_VALID){
// get temperature value
val = phs300x_data->fetch_bit.tempdata;
phs300x_data->tempval = (float)((double)val/(double)(HS300X_DATA_FACTOR) * 165.0 - 40);
// get humidity value
val = phs300x_data->fetch_bit.humidydata;
phs300x_data->humival = (float)((double)val/(double)(HS300X_DATA_FACTOR) * 100.0);
}
return 0;
}
/* End of this file */
2)创建hs3003_drv.h文件,编写如下代码:
/*
FILE NAME : hs3003_drv.c
Description: hs3003 driver
Author : tangmingfei2013@126.com
Date : 2024/06/03
*/
#ifndef HS3003_DRV_H
#define HS3003_DRV_H
#include "hal_data.h"
/* hs3003 i2c address */
#define HS300X_ADDR (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)
#define HS300X_REG_R_TRG 0X06
#define HS300X_REG_W_TRG 0X46
/* calculation formula, 2^14 - 1 */
#define HS300X_DATA_FACTOR (16383U)
typedef struct
{
unsigned int mask : 2;
unsigned int tempdata : 14;
unsigned int humidydata : 14;
unsigned int res : 2;
} Datafetch_bit;
typedef struct{
union
{
unsigned int data;
Datafetch_bit fetch_bit;
};
float tempval;
float humival;
}hs300x_data;
typedef struct
{
unsigned int res1 : 10;
unsigned int tempdata : 2;
unsigned int res2 : 4;
} stru_para_bit;
typedef struct{
union
{
unsigned int data;
stru_para_bit para_bit;
};
}stru_para;
int hs300x_init(void);
int hs300x_read_value(hs300x_data *phs300x_data);
#endif /* HS3003_DRV_H */
4.2 编写测试代码
代码第48行:初始化hs3003
代码第60行:读取hs3003温湿度值
5 测试
编译代码,然后将代码下载到板卡中,运行代码
当吧手指放到hs3003芯片上,温湿度值就会变化