I2C设备
I2C简介
I2C(Inter Integrated Circuit)总线是 PHILIPS 公司开发的一种半双工、双向二线制同步串行总线。I2C 总线传输数据时只需两根信号线,一根是双向数据线 SDA(serial data),另一根是双向时钟线 SCL(serial clock)。SPI 总线有两根线分别用于主从设备之间接收数据和发送数据,而 I2C 总线只使用一根线进行数据收发。
I2C又称IIC,更详细介绍说明请查看RT-Thread官网:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/i2c/i2c
驱动支持
访问I2C设备前,需要保证相关驱动配置已选中。
Windows环境:利用RT-Thread官方env工具直接在代码根目录下执行menuconfig进入配置。
Linux环境:在代码根目录下执行scons --menuconfig进入配置。
I2C驱动所在路径如下:
RT-Thread Components -> Device Drivers -> Using I2C device drivers
打开驱动配置
上述配置选中后,相关的GPIO配置也需要配置,打开源码文件:board/board.h搜索"BSP_USING_I2C1",取消对应注释,这里选用软件模拟的I2C,修改如下:
#define BSP_USING_I2C1
#define BSP_I2C1_SCL_PIN GET_PIN(A, 5)
#define BSP_I2C1_SDA_PIN GET_PIN(A, 6)
访问I2C设备
访问I2C设备,库中提供了以下接口:
函数 | 描述 |
---|---|
rt_device_find() | 根据I2C名称查找设备获取设备句柄 |
rt_i2c_transfer() | I2C读写数据 |
查找I2C设备
查找I2C设备,函数原型如下所示:
rt_device_t rt_device_find(const char* name);
-
参数
[IN]name:I2C设备名称,目前注册到的系统中的I2C设备名称为"hw_i2c"。
-
返回值
RT_NULL:失败,设备不存在。
非RT_NULL:成功,该返回值是操作I2C设备的句柄,在后续的接口中作为函数入参。
I2C读写数据
打开I2C设备并进行读写操作,函数原型如下所示:
rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device* bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
-
参数
[IN]bus:I2C设备句柄,查找I2C设备函数的返回值。
[INOUT]msgs:待读写的消息数组指针。
// 结构体定义头文件所在路径: // rt-thread/components/drivers/include/drivers/i2c.h struct rt_i2c_msg { rt_uint16_t addr; rt_uint16_t flags; rt_uint16_t len; rt_uint8_t* buf; };
[IN]num:消息数组的元素个数。
-
返回值
成功,返回消息数组的元素个数。
失败,返回错误码。
I2C使用示例
这里提供I2C测试实例中以使用AT24C02作为例子。
使用示例需要配置menuconfig打开配置(默认关闭),路径如下:
wiota APP -> open i2c, default close(_IIC_APP_)
AT24C02简介
AT24C02是一个2K位串行CMOS EEPROM, 内部含有256个8位字节。该器件内部有一个16字节页写缓冲器,通过I2C总线进行操作,有一个专门的写保护功能。
测试步骤
- 根据I2C设备名称,获取I2C设备句柄。
- I2C收发数据。
#include <rtthread.h>
#ifdef _IIC_APP_
#include <rtdevice.h>
#include "uc_iic_app.h"
#define IIC_DEVICE_NAME "hw_i2c"
#define AT24C02_ADDR 0xA0
static rt_device_t iic_dev = NULL;
static rt_err_t write_reg(struct rt_i2c_bus_device *bus,
rt_uint8_t reg,
rt_uint8_t *data)
{
rt_uint8_t buf[8];
struct rt_i2c_msg msgs;
rt_uint32_t buf_size = 1;
buf[0] = reg; //cmd
if (data != RT_NULL)
{
buf[1] = data[0];
buf[2] = data[1];
buf[3] = data[2];
buf[4] = data[3];
buf_size = 5;
}
msgs.addr = AT24C02_ADDR;
msgs.flags = RT_I2C_WR;
msgs.buf = buf;
msgs.len = buf_size;
if (rt_i2c_transfer(bus, &msgs, 1) == 1)
{
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
static rt_err_t read_regs(struct rt_i2c_bus_device *bus,
rt_uint8_t len,
rt_uint8_t *buf)
{
struct rt_i2c_msg msgs;
msgs.addr = AT24C02_ADDR;
msgs.flags = RT_I2C_RD;
msgs.buf = buf;
msgs.len = len;
if (rt_i2c_transfer(bus, &msgs, 1) == 1)
{
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
int iic_app_init(void)
{
rt_err_t ret = RT_EOK;
iic_dev = rt_device_find(IIC_DEVICE_NAME);
if (!iic_dev)
{
rt_kprintf("find %s failed!\n", IIC_DEVICE_NAME);
return RT_ERROR;
}
return ret;
}
void iic_app_sample(void)
{
rt_err_t ret = RT_EOK;
unsigned char set_data[4] = {1, 2, 3, 4};
unsigned char get_data[4] = {0};
rt_kprintf("iic test demo.\r\n");
ret = iic_app_init();
if(ret != RT_EOK)
{
rt_kprintf("init iic failed!\n");
return;
}
ret = write_reg((struct rt_i2c_bus_device *)iic_dev, 0, set_data);
if(ret != RT_EOK)
{
rt_kprintf("iic write data failed!\n");
return;
}
ret = read_regs((struct rt_i2c_bus_device *)iic_dev, 4, get_data);
if(ret != RT_EOK)
{
rt_kprintf("iic write data failed!\n");
return;
}
for (rt_uint8_t num = 0; num < 4; num++)
{
if (set_data[num] != get_data[num])
{
rt_kprintf("i2c data match fail. num=%d, %d!= %d\n",
num, set_data[num], get_data[num]);
}
}
}
#endif