Linux下的I2C通信

I2C通信:


一.硬件初识:

IIC(inter-intergrated-Circu):内部集成总线

四线通讯:SCL,SDA,GND,VCC,串行,半双工

  1. I2C 总线是同步,串行,半双工通信总线。

  2. I2C 总线由时钟线 SDASCL两根信号线构成。并且都有上拉电阻。确保总线空闲状态为高电平。

  3. I2C 总线支持多设备连接,允许多主机存在,但同一时刻只允许一台主机。

  4. 每一个I2C 外设都会对应一个唯一的地址(这个地址可以从 I2C 外设器件的数据手册中得知),主机和从机之间的通信就是通过这个地址来确定主机要和哪个从机进行通信的。

  5. I2C 总线上挂载的设备的数量受总线最大电容 400pF 限制。如果挂的是相同型号的器件还受到器件的地址限制。

  6. I2C 总线在标准模式下传输速率可达 100kbit/s,在快速模式下可达 400kbit/s,在高速模
    式下可达3.4Mbit/s

  7. I2C 总线上的主机和从机之间以字节(8位)为单位进行数据传输。

  8. I2C 有硬件12C 和软件 12C。

通讯时序:

高位先传输

I2C子系统框架:


驱动开发,只需实现设备驱动层的Client,和Driver即可:向内核中添加一个描述i2c外设资源的device部分,在driver中调用核心层的API实现I2C的通讯驱动

二.1. I2C_client部分:

用于描述一个I2c外设的资源,地址,GPIO,中断信息等等…表示通信的对象
向内核中添加一个client的方法可以是设备树或者使用c程序添加

设备树:
//挂载在i2c1设备控制器下
&i2c1{
//状态
    status = "okay";
//标签@地址
    myft5x06:my-ft5x06@38{
//配对属性
        compatible = "my-ft5x06";
//regI2c地址
        reg = <0x38>;


    };
}
c语言添加:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>



struct i2c_adapter *i2c_ada;
// 定义I2C设备信息,用于描述一个I2C设备的资源
struct i2c_board_info ft5x06[] = {
    {I2C_BOARD_INFO("my-ft5x06", 0x38)},
    {}
};

static int __init iic_device_init(void)
{
    i2c_ada = i2c_get_adapter(1); // 获取I2C适配器
    i2c_new_device(i2c_ada, ft5x06); // 创建设备
    i2c_put_adapter(i2c_ada); // 释放适配器
    return 0;
}

static void __exit iic_device_exit(void)
{
}

module_init(iic_device_init);
module_exit(iic_device_exit);
MODULE_LICENSE("GPL");t);
MODULE_LICENSE("GPL");

2. I2C_driver部分:

驱动框架:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>

int iic_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
{

    return 0;
}
int iic_driver_remove(struct i2c_client *client)
{

    return 0;
}

// const struct of_device_id my_match_table[] ={
//     {.compatible = "my-ft5x06"},
//     {}
// }

const struct i2c_device_id *my_id_table[] = {
    {"my-ft5x06"},
    {}
} ;

struct i2c_driver my_iic_driver =
{
    .driver = {
        //.name用于和使用c注册的device名字作匹配
        .name = "my-ft5x06",
        .owner = THIS_MODULE,
        //.of_match_table用于匹配设备树中的节点
        // .of_match_table = my_match_table,
    },  
    .probe = iic_driver_probe, 
    .remove = iic_driver_remove,
    //.id_table和.name用于和使用c注册的device名字作匹配,优先使用table
    .id_table = my_id_table,
};

static int iic_driver_init(void)
{

    int ret = i2c_add_driver(&my_iic_driver); // 添加驱动程序

    if (ret < 0)
    {
        printk("i2c_add_driver failed\n");
    }
    return 0;
}
static void iic_driver_exit(void)
{

    i2c_del_driver(&my_iic_driver); // 删除驱动程序
}

module_init(iic_driver_init);
module_exit(iic_driver_exit);
MODULE_LICENSE("GPL");

3. 获取设备信息:

使用设备树与driver匹配成功后,执行probe函数->获取设备树中资源信息:补全probe函数功能功能:

struct gpio_desc *reset_gpio;
struct gpio_desc *irq_gpio;

// 中断处理函数
irqreturn_t ft5x06_handler(int irq, void *args)
{
    printk("ft5x06_handler\n");
    // 中断处理逻辑

    return IRQ_RETVAL(IRQ_HANDLED);//表示中断已经处理完毕
}

int iic_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;

    printk("iic_driver_probe\n");
    // 获取设备树中的节点信息
    // 获取复位引脚信息
    reset_gpio = gpiod_get_optional(&client->dev, "reset", 0);
    if (IS_ERR(reset_gpio))
    {
        printk("get reset gpio failed\n");
        return PTR_ERR(reset_gpio);
    }
    // 获取中断引脚信息
    irq_gpio = gpiod_get_optional(&client->dev, "irq", 0);
    if (IS_ERR(irq_gpio))
    {
        printk("get irq gpio failed\n");
        return PTR_ERR(irq_gpio);
    }
    // 复位设备
    gpiod_direction_output(reset_gpio, 0);
    mdelay(5);
    gpiod_direction_output(reset_gpio, 1);

    // 申请中断
    //  IRO_TYPE_EDGE_FALLING |IROF_ONESHOT:下降沿触发,中断可嵌套
    ret = request_irq(client->irq, ft5x06_handler, IRO_TYPE_EDGE_FALLING | IROF_ONESHOT, "ft5x06_irq", NULL);
    if (ret < 0)
    {
        printk("request_irq failed\n");
        return ret;
    }

    return 0;
}

中断的返回信息:

/**
 * enum irqreturn
 * @IRQ_NONE        interrupt was not from this device
 * @IRQ_HANDLED        interrupt was handled by this device
 * @IRQ_WAKE_THREAD    handler requests to wake the handler thread
 */
enum irqreturn {
    IRQ_NONE        = (0 << 0),
    IRQ_HANDLED        = (1 << 0),
    IRQ_WAKE_THREAD        = (1 << 1),
};

typedef enum irqreturn irqreturn_t;
#define IRQ_RETVAL(x)    ((x) != IRQ_NONE)

#endif

4. I2C核心层API:

i2c_master_recv 函数
函数原型:

static inline int i2c_master_recv(const struct i2c_client *client,char *buf, int count)

函数作用: 使用 12C 总线读数据
函数参数:client: 对应的12C 的 client

:buf: 存放读到的数据的缓冲区的指针
:count:要读取的字节数
返回值: 成功返回读取到的字节数,失败返回负数

i2c_master_send 函数
函数原型:

static inline int i2c_master_send(const struct i2c_client *client,const char *buf, int count)

函数作用:使用12C 总线写数据
函数参数:client:对应的12C 的 client
:buf: 要发送的数据的缓冲区的指针
:count:要发送的字节数
返回值:成功返回发送的字节数,失败返回负数

i2c_transfer 函数
函微原型:

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);

函数作用: 可以使用12C 总线发送和接收。具体是发送还是接收是由参数 msg,中的成员来决
定的。
函数参数:adap: 使用那个 12C 适配器
:msg: 12C 的数据包
:num: msg 的数量
返回值: 成功返回值大于 0,失败返回值小于 0

5. I2C驱动读写寄存器:

使用全局变量获取从probe中得到的client:

struct i2c_client *fx5x06_client;

probe中保存

fx5x06_client = client;

i2c读数据:

// 读寄存器数据
int ft5x06_read_reg(u8 reg)
{
    u8 data;
    // 发送读取寄存器的命令,两个数据包
    struct i2c_msg msgs[] = {
        [0] = {
            .addr = fx5x06_client->addr,
            .flags = 0,
            .buf = &reg,
            .len = sizeof(reg),
        },
        [1] = {
            .addr = fx5x06_client->addr,
            .flags = I2C_M_RD,
            .buf = &data,
            .len = sizeof(data),
        }};
    i2c_transfer(fx5x06_client->adapter, msgs, 2);
    return data;
}

i2c写数据:

// 写寄存器数据
void ft5x06_write_reg(u8 reg, u8 data, u8 len)
{
    u8 buff[256];
    // 发送写入寄存器的命令,两个数据包
    struct i2c_msg msgs[] = {
        [0] = {
            .addr = fx5x06_client->addr,
            .flags = 0,
            .buf = buff,
            .len = len + 1,
        },
    };
    //buff中存放寄存器地址+数据
    buff[0] = reg;
    memcpy(&buff[1], &data, len);
    // 发送数据
    i2c_transfer(fx5x06_client->adapter, msgs, 1);
}

源程序:

iic_driver:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>

struct gpio_desc *reset_gpio;
struct gpio_desc *irq_gpio;

struct i2c_client *fx5x06_client;

// 读寄存器数据
int ft5x06_read_reg(u8 reg)
{
    u8 data;
    // 发送读取寄存器的命令,两个数据包
    struct i2c_msg msgs[] = {
        [0] = {
            .addr = fx5x06_client->addr,
            .flags = 0,
            .buf = &reg,
            .len = sizeof(reg),
        },
        [1] = {
            .addr = fx5x06_client->addr,
            .flags = I2C_M_RD,
            .buf = &data,
            .len = sizeof(data),
        }};
    i2c_transfer(fx5x06_client->adapter, msgs, 2);
    return data;
}

// 写寄存器数据
void ft5x06_write_reg(u8 reg, u8 data, u8 len)
{
    u8 buff[256];
    // 发送写入寄存器的命令,两个数据包
    struct i2c_msg msgs[] = {
        [0] = {
            .addr = fx5x06_client->addr,
            .flags = 0,
            .buf = buff,
            .len = len + 1,
        },
    };
    // buff中存放寄存器地址+数据
    buff[0] = reg;
    memcpy(&buff[1], &data, len);
    // 发送数据
    i2c_transfer(fx5x06_client->adapter, msgs, 1);
}
// 中断处理函数
irqreturn_t ft5x06_handler(int irq, void *args)
{
    printk("ft5x06_handler\n");
    // 中断处理逻辑

    return IRQ_RETVAL(IRQ_HANDLED); // 表示中断已经处理完毕
}

int iic_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;

    printk("iic_driver_probe\n");
    // 使用全局变量保存client
    fx5x06_client = client;

    // 获取设备树中的节点信息
    // 获取复位引脚信息
    reset_gpio = gpiod_get_optional(&client->dev, "reset", 0);
    if (IS_ERR(reset_gpio))
    {
        printk("get reset gpio failed\n");
        return PTR_ERR(reset_gpio);
    }
    // 获取中断引脚信息
    irq_gpio = gpiod_get_optional(&client->dev, "irq", 0);
    if (IS_ERR(irq_gpio))
    {
        printk("get irq gpio failed\n");
        return PTR_ERR(irq_gpio);
    }
    // 复位设备
    gpiod_direction_output(reset_gpio, 0);
    mdelay(5);
    gpiod_direction_output(reset_gpio, 1);

    // 申请中断
    //  IRO_TYPE_EDGE_FALLING |IROF_ONESHOT:下降沿触发,中断可嵌套
    ret = request_irq(client->irq, ft5x06_handler, IRO_TYPE_EDGE_FALLING | IROF_ONESHOT, "ft5x06_irq", NULL);
    if (ret < 0)
    {
        printk("request_irq failed\n");
        return ret;
    }

    return 0;
}
int iic_driver_remove(struct i2c_client *client)
{

    return 0;
}

// const struct of_device_id my_match_table[] ={
//     {.compatible = "my-ft5x06"},
//     {}
// }

const struct i2c_device_id *my_id_table[] = {
    {"my-ft5x06"},
    {}};

struct i2c_driver my_iic_driver =
    {
        .driver = {
            //.name用于和使用c注册的device名字作匹配
            .name = "my-ft5x06",
            .owner = THIS_MODULE,
            //.of_match_table用于匹配设备树中的节点
            // .of_match_table = my_match_table,
        },
        .probe = iic_driver_probe,
        .remove = iic_driver_remove,
        //.id_table和.name用于和使用c注册的device名字作匹配,优先使用table
        .id_table = my_id_table,
};

static int iic_driver_init(void)
{

    int ret = i2c_add_driver(&my_iic_driver); // 添加驱动程序

    if (ret < 0)
    {
        printk("i2c_add_driver failed\n");
    }
    return 0;
}
static void iic_driver_exit(void)
{

    i2c_del_driver(&my_iic_driver); // 删除驱动程序
}

module_init(iic_driver_init);
module_exit(iic_driver_exit);
MODULE_LICENSE("GPL");

注:board和client

i2c_board_info和i2c_client都可以描述一个i2c外设的资源信息

i2c_board_info注册板载信息,和i2c_client的结构体相差无几,但成员变量中没有adapter的变量指针,而adapter是底层i2c的重要成员变量所以

i2c_new_device(i2c_ada, ft5x06); // 创建设备

参数需要板载i2c设备信息i2c_ada适配器指针,向内核注册一个完整的i2c_client设备

在应用层使用i2c通信:

应用层使用i2c的操作,会调用内核层的i2c通信,使用应用层的通信,不需要向内核里注册client即可直接与从机通信。

Linux下应用层通用的I2c驱动程序在i2c-dev.c中:

i2c外设的驱动程序分成了i2c_client 和i2c_driver,在 Linux 内核中提供了一个通用的 i2c驱动,
这个通用的驱动程序给应用程序提供了操作 i2c 控制器的设备节点。所以在应用程序中可以
直接通过 fd = open("/dev/i2c-1",O_RDWR);进行i2c 通信。这个通用的驱动程序就是 i2c-dev.c。
驱动所在位置:
kernel/drivers/i2c

使能内核支持应用层的I2c通信:

>  编译内核镜像:
 Device Driver -->
 	 i2C support -->
		 <*> i2C device interface

在dev目录下就会有i2c的设备节点了

i2c_app.c:(使用ioctl通信)

/*
在应用层使用C语言编写一个IIC通信的程序。该程序应该能够实现IIC通信的各种功能,如读写数据、设置地址等。
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <string.h>


#define I2C_DEVICE "/dev/i2c-1"  // I2C设备文件路径
#define I2C_ADDRESS 0x50  // I2C设备地址

//i2c读数据
int i2c_read(int fd,unsigned char slave_addr, unsigned char reg_addr) {
    unsigned char data;
    struct i2c_rdwr_ioctl_data i2c_msg;
    struct i2c_msg messages [] ={
        [0] = {
            .addr = slave_addr,
            .flags = 0,
            .len = sizeof(reg_addr),
            .buf = &reg_addr,
        },
        [1] = {
            .addr = slave_addr,
            .flags = I2C_M_RD,
            .len = sizeof(data),
            .buf = &data,
        },
    };
    i2c_msg.msgs = messages;
    i2c_msg.nmsgs = 2;

    int ret = ioctl(fd, I2C_RDWR, &i2c_msg);
    if(ret < 0){
        printf("I2C read error\n");
        return ret;
    }
    return data;

}

//i2c写数据
void i2c_write(int fd,unsigned char slave_addr, int reg_addr, unsigned char data,int len) {
    unsigned char buf[256];
    struct i2c_rdwr_ioctl_data i2c_msg;
    struct i2c_msg messages [] ={
        [0] = {
            .addr = slave_addr,
            .flags = 0,
            .len = len+1,
            .buf = buf,
        },
    };
    buf[0]= reg_addr;
    memcpy(&buf[1], &data, len);
    i2c_msg.msgs = messages;
    i2c_msg.nmsgs = 1;

    int ret = ioctl(fd, I2C_RDWR, &i2c_msg);
    if(ret < 0){
        printf("I2C write error\n");
    }
}


int main(int argc, char *argv[]) {
    int fd;
    int REG_VALUE;
    fd = open("I2C_DEVICE", O_RDWR);
    if(fd < 0){
        printf("Failed to open I2C device\n");
        return -1;
    }
    i2c_write(fd, I2C_ADDRESS, 0x00, 0x55, 1);

    REG_VALUE = i2c_read(fd, I2C_ADDRESS, 0x00);

    printf("REG_VALUE: %d\n", REG_VALUE);



    return 0;
}

i2c_app.c(使用write/read)

用户层的读写会调用内核层的读写:

查看内核中i2c的读写函数:

static ssize_t i2cdev_write(struct file *file, const char __user *buf,
                  size_t count, loff_t *offset)
  {
          int ret;
          char *tmp;
          struct i2c_client *client = file->private_data;

          if (count > 8192)
                  count = 8192;

          tmp = memdup_user(buf, count);
          if (IS_ERR(tmp))
                  return PTR_ERR(tmp);

          pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
                  iminor(file->f_path.dentry->d_inode), count);

          ret = i2c_master_send(client, tmp, count);
          kfree(tmp);
        return ret;
  }
static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
                  loff_t *offset)
  {
          char *tmp;
          int ret;

          struct i2c_client *client = file->private_data;

          if (count > 8192)
                  count = 8192;

          tmp = kmalloc(count, GFP_KERNEL);
          if (tmp == NULL)
                  return -ENOMEM;

          pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
                  iminor(file->f_path.dentry->d_inode), count);

          ret = i2c_master_recv(client, tmp, count);
          if (ret >= 0) 
                  ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
          kfree(tmp);
          return ret;
  }

编写在用户层的读写:

// 使用read和write驱动i2c通信
void i2c_kernel_write(int fd, int reg_addr, unsigned char data)
{
    unsigned char wr_data[2];
    wr_data[0] = reg_addr;
    wr_data[1] = data;

    int ret = write(fd, wr_data, sizeof(wr_data));
    if (ret < 0)
    {
        printf("I2C write error\n");
    }
}
int i2c_kernel_read(int fd, unsigned char reg_addr)
{
    int ret;
    unsigned char rd_data[1];
    rd_data[0] = reg_addr;

    write(fd, rd_data, sizeof(rd_data));
    read(fd, rd_data, sizeof(rd_data));

    printf("I2C read data: %x\n", rd_data[0]);

    ret = rd_data[0];

    return ret;
}turn reg_addr[0];

}

在调用读写之前需要使用ioctl去设置i2c通信时从机的地址ioctl(fd,I2C_SLAVE_FORCE,SLAVE_ADDR);

#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it
is already in use by a driver! */

fd : i2c设备的节点描述符

I2C_SLAVE_FORCE:设置地址的命令

SLAVE_ADDR : 从机的地址

使用ioctl设置地址时:实际的调用部分是设置client的addr

    case I2C_SLAVE_FORCE:
        /* NOTE:  devices set up to work with "new style" drivers
         * can't use I2C_SLAVE, even when the device node is not
         * bound to a driver.  Only I2C_SLAVE_FORCE will work.
         *
         * Setting the PEC flag here won't affect kernel drivers,
         * which will be using the i2c_client node registered with
         * the driver model core.  Likewise, when that client has
         * the PEC flag already set, the i2c-dev driver won't see
         * (or use) this setting.
         */
        if ((arg > 0x3ff) ||
            (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
            return -EINVAL;
        if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
            return -EBUSY;
        /* REVISIT: address could become busy later */
        client->addr = arg;
        return 0;

源程序:

/*
在应用层使用C语言编写一个IIC通信的程序。该程序应该能够实现IIC通信的各种功能,如读写数据、设置地址等。
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>

#define I2C_DEVICE "/dev/i2c-1" // I2C设备文件路径
#define I2C_ADDRESS 0x50        // I2C设备地址

// 使用ioctl函数i2c读数据
int i2c_read(int fd, unsigned char slave_addr, unsigned char reg_addr)
{
    unsigned char data;
    struct i2c_rdwr_ioctl_data i2c_msg;
    struct i2c_msg messages[] = {
        [0] = {
            .addr = slave_addr,
            .flags = 0,
            .len = sizeof(reg_addr),
            .buf = &reg_addr,
        },
        [1] = {
            .addr = slave_addr,
            .flags = I2C_M_RD,
            .len = sizeof(data),
            .buf = &data,
        },
    };
    i2c_msg.msgs = messages;
    i2c_msg.nmsgs = 2;

    int ret = ioctl(fd, I2C_RDWR, &i2c_msg);
    if (ret < 0)
    {
        printf("I2C read error\n");
        return ret;
    }
    return data;
}

// 使用ioctl函数i2c写数据
void i2c_write(int fd, unsigned char slave_addr, int reg_addr, unsigned char data, int len)
{
    unsigned char buf[256];
    struct i2c_rdwr_ioctl_data i2c_msg;
    struct i2c_msg messages[] = {
        [0] = {
            .addr = slave_addr,
            .flags = 0,
            .len = len + 1,
            .buf = buf,
        },
    };
    buf[0] = reg_addr;
    memcpy(&buf[1], &data, len);
    i2c_msg.msgs = messages;
    i2c_msg.nmsgs = 1;

    int ret = ioctl(fd, I2C_RDWR, &i2c_msg);
    if (ret < 0)
    {
        printf("I2C write error\n");
    }
}

// 使用read和write驱动i2c通信
void i2c_kernel_write(int fd, int reg_addr, unsigned char data)
{
    unsigned char wr_data[2];
    wr_data[0] = reg_addr;
    wr_data[1] = data;

    int ret = write(fd, wr_data, sizeof(wr_data));
    if (ret < 0)
    {
        printf("I2C write error\n");
    }
}
int i2c_kernel_read(int fd, unsigned char reg_addr)
{
    int ret;
    unsigned char rd_data[1];
    rd_data[0] = reg_addr;

    write(fd, rd_data, sizeof(rd_data));
    read(fd, rd_data, sizeof(rd_data));

    printf("I2C read data: %x\n", rd_data[0]);

    ret = rd_data[0];

    return ret;
}

int main(int argc, char *argv[])
{
    int fd;
    int REG_VALUE;
    fd = open("I2C_DEVICE", O_RDWR);
    if (fd < 0)
    {
        printf("Failed to open I2C device\n");
        return -1;
    }
    i2c_write(fd, I2C_ADDRESS, 0x00, 0x55, 1);

    REG_VALUE = i2c_read(fd, I2C_ADDRESS, 0x00);

    printf("REG_VALUE: %d\n", REG_VALUE);

    // 使用read和write驱动i2c通信
    // ioctl(fd,I2C_SLAVE_FORCE,I2C_ADDRESS);
    //  i2c_kernel_write(fd, 0x00, 0x55);
    //  REG_VALUE = i2c_kernel_read(fd, 0x00);
    //  printf("REG_VALUE: %d\n", REG_VALUE);

    close(fd);

    return 0;
}
  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux操作系统下,I2C是一种常见的通信协议,用于连接主机与各种外部设备,如传感器、扩展模块等。在编写Linux下的I2C代码时,需要使用Linux提供的I2C子系统,它包含了各种函数和结构体,用于管理和操作I2C总线。 首先,我们需要创建一个I2C设备的句柄,可以使用函数`open()`打开对应的设备文件,如`/dev/i2c-0`。如果成功打开设备文件,就可以使用`ioctl()`函数进行各种设置和控制操作。例如,通过`I2C_SLAVE`命令可以指定要与之通信的从设备的地址。 接下来,我们可以使用`i2c_smbus_*()`系列函数来进行I2C通信。这些函数封装了一些常用的I2C操作,如读写字节、读取寄存器等。对于特定的I2C设备,可能还需要使用其他特定的函数进行访问。 在使用`i2c_smbus_*()`函数进行通信时,需要注意传入的参数。例如,读操作需要指定要读取的字节个数,写操作需要指定要写入的数据。同时,还要注意处理函数的返回值,以便判断操作是否成功。 另外,可以使用`close()`关闭I2C设备的句柄,释放资源。 需要注意的是,编写Linux下的I2C代码需要有一定的编程基础和对Linux系统的了解。还需要查阅相关的资料,了解具体的设备地址、寄存器映射关系,以及所需的操作命令和数据格式等。 总之,编写Linux下的I2C代码需要熟悉Linux系统提供的I2C子系统和相关函数,同时还需要了解具体的设备和通信协议的细节。只有掌握了这些知识,才能有效地进行I2C通信,并与外部设备进行数据交互。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想和我重名?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值