Skip to content

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总线进行操作,有一个专门的写保护功能。

测试步骤

  1. 根据I2C设备名称,获取I2C设备句柄。
  2. 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
Back to top