I2C/dev
目录下/dev/i2c-X
这样的设备文件进行访问
本教程将介绍如何使用 Linux 提供的 I2C 接口进行编程
1. 关键结构体
1.1 struct i2c_msg
i2c_msg
是 I2C 消息的描述结构体
struct i2c_msg {
__u16 addr; // 从设备的地址
__u16 flags; // 操作标志位
__u16 len; // 要发送/接收的数据长度
__u8 *buf; // 数据缓冲区指针
};
主要标志位
I2C_M_RD
: 表示读操作 如果未设置此标志。 则表示写操作, 。 I2C_M_TEN
: 表示使用 10 位地址模式。 I2C_M_STOP
: 表示在消息结束时生成 STOP 信号。
1.2 struct i2c_rdwr_ioctl_data
i2c_rdwr_ioctl_data
结构体用于通过 ioctl
系统调用执行 I2C 读写操作i2c_msg
数组和消息的数量
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; // 指向消息数组
__u32 nmsgs; // 消息的数量
};
2. I2C 应用编程概述
在用户空间中
- 打开 I2C 设备
通过: open()
函数打开/dev/i2c-X
设备文件。 - 设置从设备地址
使用: ioctl()
系统调用设置目标从设备的地址。 - 数据读写
通过: read()
和write()
进行简单的读写操作 或使用, ioctl()
进行复杂的多字节传输。
2.1 打开 I2C 设备
使用 open()
函数打开 I2C 设备文件/dev/i2c-1
int file;
file = open("/dev/i2c-1", O_RDWR);
if (file < 0) {
perror("Failed to open the i2c bus");
exit(1);
}
2.2 设置从设备地址
通过 ioctl()
设置与哪个从设备进行通信
int addr = 0x50; // 从设备地址
if (ioctl(file, I2C_SLAVE, addr) < 0) {
perror("Failed to acquire bus access and/or talk to slave");
exit(1);
}
I2C_SLAVE
是常用的 ioctl
命令
2.3 读写 I2C 数据
2.3.1 写入数据
使用 write()
函数将数据写入 I2C 设备
unsigned char buffer[1] = { 0xA0 };
if (write(file, buffer, 1) != 1) {
perror("Failed to write to the i2c bus");
}
2.3.2 读取数据
使用 read()
函数从 I2C 设备读取数据
unsigned char buffer[1];
if (read(file, buffer, 1) != 1) {
perror("Failed to read from the i2c bus");
} else {
printf("Data read: 0x%02x\n", buffer[0]);
}
2.4 使用 ioctl
进行复杂读写操作
对于更复杂的读写操作I2C_RDWR
命令结合 i2c_rdwr_ioctl_data
来实现
2.4.1 写入多个字节
假设要向寄存器 0x10 写入两个字节的数据
unsigned char outbuf[3] = { 0x10, 0x01, 0x02 };
struct i2c_msg messages[1];
messages[0].addr = addr;
messages[0].flags = 0; // 写操作
messages[0].len = 3;
messages[0].buf = outbuf;
struct i2c_rdwr_ioctl_data ioctl_data;
ioctl_data.msgs = messages;
ioctl_data.nmsgs = 1;
if (ioctl(file, I2C_RDWR, &ioctl_data) < 0) {
perror("Failed to write to the i2c bus");
}
2.4.2 读取寄存器数据
通常
unsigned char reg = 0x10;
unsigned char inbuf[1];
struct i2c_msg messages[2];
messages[0].addr = addr;
messages[0].flags = 0; // 写操作
messages[0].len = 1;
messages[0].buf = ®
messages[1].addr = addr;
messages[1].flags = I2C_M_RD; // 读操作
messages[1].len = 1;
messages[1].buf = inbuf;
struct i2c_rdwr_ioctl_data ioctl_data;
ioctl_data.msgs = messages;
ioctl_data.nmsgs = 2;
if (ioctl(file, I2C_RDWR, &ioctl_data) < 0) {
perror("Failed to read from the i2c bus");
} else {
printf("Register 0x10 read: 0x%02x\n", inbuf[0]);
}
3. 常用的 ioctl
命令
I2C_SLAVE
: 设置从设备地址。 I2C_RDWR
: 执行多条 I2C 消息 读或写( ) 对应, i2c_rdwr_ioctl_data
。
4. 完整的 I2C 应用层示例
以下是一个完整的示例程序
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <unistd.h>
int main() {
int file;
int addr = 0x50; // I2C 从设备地址
// 打开 I2C 设备
if ((file = open("/dev/i2c-1", O_RDWR)) < 0) {
perror("Failed to open the i2c bus");
return 1;
}
// 设置从设备地址
if (ioctl(file, I2C_SLAVE, addr) < 0) {
perror("Failed to acquire bus access and/or talk to slave");
return 1;
}
// 写入数据到寄存器 0x10
unsigned char outbuf[3] = { 0x10, 0x01, 0x02 };
if (write(file, outbuf, 3) != 3) {
perror("Failed to write to the i2c bus");
return 1;
}
// 读取寄存器 0x10 的值
unsigned char reg = 0x10;
unsigned char inbuf[1];
struct i2c_msg messages[2];
messages[0].addr = addr;
messages[0].flags = 0;
messages[0].len = 1;
messages[0].buf = ®
messages[1].addr = addr;
messages[1].flags = I2C_M_RD;
messages[1].len = 1;
messages[1].buf = inbuf;
struct i2c_rdwr_ioctl_data ioctl_data;
ioctl_data.msgs = messages;
ioctl_data.nmsgs = 2;
if (ioctl(file, I2C_RDWR, &ioctl_data) < 0) {
perror("Failed to read from the i2c bus");
return 1;
} else {
printf("Register 0x10 read: 0x%02x\n", inbuf[0]);
}
close(file);
return 0;
}
5. 使用 i2c-tools
进行调试
i2c-tools
是一组用于调试 I2C 设备的工具集i2cdetect
i2cget
i2cset
和 i2cdump
等常用工具
5.1 i2cdetect
i2cdetect
用于扫描 I2C 总线
i2cdetect -y 1
5.2 i2cget
i2cget
用于读取 I2C 设备寄存器的数据
i2cget -y 1 0x50 0x00
5.3 i2cset
i2cset
用于向 I2C 设备写入数据
i2cset -y 1 0x50 0x00 0xFF
5.4 i2cdump
i2cdump
用于读取 I2C 设备的所有寄存器
i2cdump -y 1 0x50
6. 总结
I2C 是嵌入式系统中常见的通信协议open()
read()
write()
和 ioctl()
等系统调用i2c-tools
提供了一组命令行工具
如需进一步了解 i2c-tools
的源码和开发方法