- 12 I2C编程应用开发
- 12.1 I2C协议
- 12.1.1 概述
- 12.2.2 物理层
- 1) 特性1:半双工(非全双工)
- 2) 特性2:地址和角色可配置
- 3) 特性3:多主机
- 4) 特性4:传输速率
- 5) 特性5:负载和距离
- 12.2.3 协议层
- 1) 数据有效性
- 2) 起始和结束条件
- 3) 应答
- 4) 数据帧格式
- 12.2 在linux系统下操作I2C总线的外设
- 12.2.1 概述
- 12.2.2 简述I2C的linux驱动
- 1) I2C核心层:
- 2) I2C总线驱动层:
- 3) I2C总线驱动层:
- 12.3 在linux应用层使用I2C
- 12.3.1 如何使用I2C tools测试I2C外设
- 1) I2C tools概述:
- 2) 下载I2C tools源码:
- 3) 编译I2C tools源码:
- 4) 介绍I2C tools各功能之—i2cdetect
- 5) 介绍I2C tools各功能之—i2cget
- 6) 介绍I2C tools各功能之—i2cdump
- 7) 介绍I2C tools各功能之—i2cset
- 8) 介绍I2C tools各功能之—i2ctransfer
- 12.3.2 在linux应用程序中读写I2C外设
- 1) 确定I2C适配器的设备文件节点
- 2) 打开适配器对应的设备节点
- 3) IOCTL控制
- 4) 使用I2C协议和设备进行通信
- 5) 用read和write读写I2C设备
- 6) 用数据包的方式操作I2C设备
- 12.3.3 简介I2C的调试方式
- 1) 概述I2C通信中完成正常通信的常见元素:
- 12.4 总结I2C在嵌入式项目开发的应用优缺点
- 1) I2C时钟信号(SCL)的同步问题
- 2) 总线驱动能力
I2C(Inter-Integrated Circuit BUS)是I2C BUS简称,中文为集成电路总线,是目前应用最广泛的总线之一。和IMX6ULL有些相关的是,刚好该总线是NXP前身的PHILIPS设计。
12.1 I2C协议 12.1.1 概述 I2C是一种串行通信总线,使用多主从架构,最初设计目的为了让主板、嵌入式系统或手机用来连接低速周边设备。多用于小数据量的场合,有传输距离短,任意时刻只能有一个主机等特性。严格意义上讲,I2C应该是软硬件结合体,所以我们将分物理层和协议层来介绍该总线。
I2C总线结构如下图:
传输数据时,我们需要发数据,从主设备发送到从设备上去;也需要把数据从从设备传送到主设备上去,数据涉及到双向传输。
对于I2C通信的过程,下面使用一个形象的生活例子进行类比。
体育老师:可以把球发给学生,也可以把球从学生中接过来。
① 发球:
- a. 老师说:注意了(start);
- b. 老师对A学生说,我要球发给你(A就是地址);
- c. 老师就把球发出去了(传输);
- d. A收到球之后,应该告诉老师一声(回应);
- e. 老师说下课(停止)。
② 接球:
-
a. 老师说注意了(start);
-
b. 老师说:B把球发给我(B是地址);
-
c. B就把球发给老师(传输);
-
d. 老师收到球之后,给B说一声,表示收到球了(回应);
-
e. 老师说下课(停止)。
我们就使用这个简单的例子,来解释一下I2C的传输协议:
① 老师说注意了,表示开始信号(start)
② 老师告诉某个学生,表示发送地址(address)
③ 老师发球/接球,表示数据的传输
④ 老师/学生收到球,回应表示:回应信号(ACK)
⑤ 老师说下课,表示I2C传输接受§
12.2.2 物理层 1) 特性1:半双工(非全双工) I2C总线中只使用两条线路:SDA、SCL。
① SDA(串行数据线):
主芯片通过一根SDA线既可以把数据发给从设备,也可以从SDA上读取数据。在I2C设备内部有两个引脚(发送引脚/接受引脚),它们都连接到外部的SDA线上,具体可以参考下图device端里面的I2Cn_SDA(output/input)。
② SCL(串行时钟线):
I2C主设备发出时钟,从设备接收时钟。
SDA和SCL引脚的内部电路结构一致,引脚的输出驱动与输入缓冲连在一起。其中输出为漏极开路的场效应管、输入缓冲为一只高输入阻抗的同相器。这样结构有如下特性:
a. 由于 SDA、SCL 为漏极开路结构,借助于外部的上拉电阻实现了信号的“线与”逻辑;
b. 引脚在输出信号的同时还作用输入信号供内部进行检测,当输出与输入不一致时,就表示有问题发生了。这为 “时钟同步”和“总线仲裁”提供硬件基础。
SDA和CLK连接线上连有两个上拉电阻,当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低。
物理层连接如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kyu89PWq-1639020220827)(http://photos.100ask.net/NewHomeSite/IIC_Image003.png)]
2) 特性2:地址和角色可配置 每个连接到总线的器件都可以通过唯一的地址和其它器件通信,主机/从机角色和地址可配置,主机可以作为主机发送器和主机接收器。
3) 特性3:多主机 I2C是真正的多主机总线,I2C设备可以在通讯过程转变成主机。如果两个或更多的主机同时请求总线,可以通过冲突检测和仲裁防止总线数据被破坏。
4) 特性4:传输速率 传输速率在标准模式下可以达到100kb/s,快速模式下可以达到400kb/s。
5) 特性5:负载和距离 节点的最大数量受限于地址空间以及总线电容决定,另外总电容也限制了实际通信距离只有几米。
12.2.3 协议层 1) 数据有效性 I2C协议的数据有效性是靠时钟来保证的,在时钟的高电平周期内,SDA线上的数据必须保持稳定。数据线仅可以在时钟SCL为低电平时改变。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WQhqSPjW-1639020220828)(http://photos.100ask.net/NewHomeSite/IIC_Image004.png)]
2) 起始和结束条件**起始条件:**当SCL为高电平的时候,SDA线上由高到低的跳变被定义为起始条件。
**结束条件:**当SCL为高电平的时候,SDA线上由低到高的跳变被定义为停止条件。
要注意起始和终止信号都是由主机发出的,连接到I2C总线上的器件,若具有I2C总线的硬件接口,则很容易检测到起始和终止信号。
总线在起始条件之后,视为忙状态,在停止条件之后被视为空闲状态。
3) 应答 每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据,从机应答主机所需要的时钟仍是主机提供的,应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答。
4) 数据帧格式 SDA线上每个字节必须是8位长,在每个传输(transfer)中所传输字节数没有限制,每个字节后面必须跟一个ACK。8位数据中,先传输最高有效位(MSB)传输。
下图是在linux系统环境里操作i2c总线上的外设流程框图。我们按照从下向上的顺序研究一下该流程中各个角色的功能。
在硬件层中,I2C硬件总线只有两条线路,上面可以挂载多个I2C-device,这些I2C-device有的在I2C总线里充当主机的角色,一般情况该主机为板子上的主cpu中的I2C控制器,比如我们用的100ask_imx6UL板子,这个I2C主机就是imx6中的I2C控制器模块;其他的I2C-device在I2C总线里充当从机的角色,通常这些从机是板子上完成特定功能的传感器外设,只不过该外设与主控cpu的通信方式是只需要两条线路的I2C总线,比如在我们的100ask_imx6UL板子中就有eeprom和AP3216两个外设,它们在I2C总线中充当的都是I2C从机的角色,它们和主控芯片imx6中的I2C控制器1都是以并联的方式挂在这个I2C总线上。
在内核中,驱动程序对下要完成I2C总线上的I2C通信协议,收集硬件传感器的I2C数据并封装成标准的linux操作接口供用户空间的应用程序操作。对上要实现可以通过linux程序把数据流组织成I2C协议下发到硬件层的相应的外设传感器中。
在用户空间的应用程序中,应用工程师完全可以不必理会I2C协议的详细规定。只需要按照驱动层提供给我们的操作I2C外设的操作接口函数就可以像操作linux中其他普通设备文件那样轻松的操作I2C外设了。
I2C在linux内核层的驱动框架主要由三部分组成:
1) I2C核心层: I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(algorithm)的上层部分,并且还提供了一系列与具体硬件平台无关的接口函数以及探测设备,检测设备地址的上层代码等。它位于内核源码目录下的drivers/i2c/i2c-core.c文件中,是I2C总线驱动和设备驱动之间依赖于I2C核心作为纽带。
I2C核心中的主要函数包括:
增加/删除i2c_adapter
int i2c_add_adapter(struct i2c_adapter *adap);
int i2c_del_adapter(struct i2c_adapter *adap);
增加/删除i2c_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
int i2c_del_driver(struct i2c_driver *driver);
inline int i2c_add_driver(struct i2c_driver *driver);
i2c_client依附/脱离
int i2c_attach_client(struct i2c_client *client);
int i2c_detach_client(struct i2c_client *client);
i2c传输、发送和接收
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num);
用于进行I2C适配器和I2C设备之间的一组消息交互。其本身不具备驱动适配器物理硬件完成消息交互的能力,它只是寻找到i2c_adapter对应的i2c_algorithm,并使用i2c_algorithm的master_xfer()函数真正驱动硬件流程。
int i2c_master_send(struct i2c_client *client,const char *buf ,int count);
int i2c_master_recv(struct i2c_client *client, char *buf ,int count);
i2c_master_send()和i2c_master_recv()函数内部会调用i2c_transfer()函数分别完成一条写消息和一条读消息。
a) I2C控制命令分派
下面函数有助于将发给I2C适配器设备文件ioctl的命令分派给对应适配器的algorithm的algo_control()函数或i2c_driver的command()函数:
int i2c_control(struct i2c_client *client, unsigned int cmd, unsigned long arg);
void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg);
2) I2C总线驱动层:
I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。
它主要完成的功能有:
a) 初始化I2C适配器所使用的硬件资源,申请I/O地址、中断号等。
b) 通过i2c_add_adapter()添加i2c_adapter的数据结构,当然这个i2c_adapter数据结构的成员已经被xxx适配器的相应函数指针所初始化。
c) 释放I2C适配器所使用的硬件资源,释放I/O地址、中断号等。
d) 通过i2c_del_adapter()删除i2c_adapter的数据结构。
3) I2C总线驱动层: I2C设备驱动(也称为客户驱动)是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。I2C设备驱动模块加载函数通用的方法是在I2C设备驱动模块加载函数中完成两件事:通过register_chrdev()函数将I2C设备注册为一个字符设备。通过I2C核心的i2c_add_driver()函数添加i2c_driver。
12.3 在linux应用层使用I2C 前面我们讲解了I2C的协议及在linux驱动框架,那么当你拿到开发板或者是从公司的硬件同事拿到一个带有I2C外设的板子,我们应该如何最快速的使用起来这个I2C设备呢?既然我们总是说这个I2C总线在嵌入式开发中被广泛的使用,那么是否有现成的测试工具帮我们完成这个快速使用板子的I2C设备呢?答案是有的,而且这个测试工具的代码还是开源的,它被广泛的应用在linux应用层来快速验证I2C外设是否可用,为我们测试I2C设备提供了很好的捷径。
12.3.1 如何使用I2C tools测试I2C外设 1) I2C tools概述: I2C tools包含一套用于Linux应用层测试各种各样I2C功能的工具。它的主要功能包括:总线探测工具、SMBus访问帮助程序、EEPROM解码脚本、EEPROM编程工具和用于SMBus访问的python模块。只要你所使用的内核中包含I2C设备驱动,那么就可以在你的板子中正常使用这个测试工具。
2) 下载I2C tools源码: 前面我们已经说过了这个I2C tools工具是开源的,那么这个源码在哪里可以找到呢?
下载方法一:直接在内核的网站https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/下载I2C tools代码的压缩包。
下载方法二:利用git管理工具下载这个I2C tools的源代码,命令为git clone git://git.kernel.org/pub/scm/utils/i2c-tools/i2c-tools.git强烈建议读者采用第二种方法下载这个代码,因为你可以通过git快速地了解这个开源代码的不同版本的功能改进及bug修复,而且使用git开发也是作为一名优秀的开发人员必备的一项技能。
3) 编译I2C tools源码: 进入刚才利用git下载好的iic-tools源码目录,修改编译工具为你当前使用的交叉编译工具:
26 CC ?= arm-linux-gnueabihf-gcc
27 AR ?= arm-linux-gnueabihf-ar
编译源码:如果你想编译静态版本,你可以输入命令:make USE_STATIC_LIB=1;如果使用动态库的话,可以直接输入make进行编译。安装命令为:make install,如果你想要让最后生成的二进制文件最小的话,可以在“make install”之前运行“make strip”。但是,这将不能生成任何调试库,也就不能尝试进一步调试。然后将tools目录下的5个可执行文件i2cdetect,i2cdump,i2cget,i2cset和i2ctransfer复制到板子的/usr/sbin/中;将lib目录下的libi2c.so.0.1.1文件复制到板子的/usr/lib/libi2c.so.0。之后别忘了将上面的文件修改为可执行的权限。
4) 介绍I2C tools各功能之—i2cdetect i2cdetect的主要功能就是I2C设备查询,它用于扫描I2C总线上的设备。它输出一个表,其中包含指定总线上检测到的设备的列表。
该命令的常用格式为:i2cdetect [-y] [-a] [-q|-r] i2cbus [first last]。具体参数的含义如下:
-y取消交互模式。默认情况下,i2cdetect将等待用户的确认, 当使用此标志时,它将直接执行操作。-a强制扫描非规则地址。一般不推荐。-q使用SMBus“快速写入”命令进行探测。一般不推荐。-r使用SMBus“接收字节”命令进行探测。一般不推荐。-F显示适配器实现的功能列表并退出。-V显示I2C工具的版本并推出。-l显示已经在系统中使用的I2C总线。i2cbus表示要扫描的I2C总线的编号或名称。first last表示要扫描的从设备地址范围。 该功能的常用方式:
第一,先通过i2cdetect -l查看当前系统中的I2C的总线情况:
第二,若总线上挂载I2C从设备,可通过i2cdetect扫描某个I2C总线上的所有设备。可通过控制台输入i2cdetect -y 1:(其中"–"表示地址被探测到了,但没有芯片应答; "UU"因为这个地址目前正在被一个驱动程序使用,探测被省略;而16进制的地址号60,1e和50则表示发现了一个外部片选从地址为0x60,0x1e(AP3216)和0x50(eeprom)的外设芯片。
第三,查询I2C总线1 (I2C -1)的功能,命令为i2cdetect -F 1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pCijYzNc-1639020220832)(http://photos.100ask.net/NewHomeSite/IIC_Image011.png)]
5) 介绍I2C tools各功能之—i2cget i2cget的主要功能是获取I2C外设某一寄存器的内容。该命令的常用格式为:
i2cget [-f] [-y] [-a] i2cbus chip-address [data-address [mode]]。具体参数的含义如下:
-f强制访问设备,即使它已经很忙。 默认情况下,i2cget将拒绝访问 已经在内核驱动程序控制下的设备。-y取消交互模式。默认情况下,i2cdetect将等待用户的确认,当使用此 标志时,它将直接执行操作。-a允许在0x00 - 0x07和0x78 - 0x7f之间使用地址。一般不推荐。i2cbus表示要扫描的I2C总线的编号或名称。这个数字应该与i2cdetect -l列出 的总线之一相对应。chip-address要操作的外设从地址。data-address被查看外设的寄存器地址。mode显示数据的方式: b (read byte data, default) w (read word data) c (write byte/read byte) 下面是完成读取0总线上从地址为0x50的外设的0x10寄存器的数据,命令为:
i2cget -y -f 0 0x50 0x10
i2cdump的主要功能查看I2C从设备器件所有寄存器的值。 该命令的常用格式为:i2cdump [-f] [-r first-last] [-y] [-a] i2cbus address [mode [bank [bankreg]]]。具体参数的含义如下:
-f强制访问设备,即使它已经很忙。 默认情况下,i2cget将拒绝访问已经在内核驱动程序控制下的设备。-r限制正在访问的寄存器范围。 此选项仅在模式b,w,c和W中可用。对于模式W,first必须是偶数,last必须是奇数。-y取消交互模式。默认情况下,i2cdetect将等待用户的确认,当使用此标志时,它将直接执行操作。-V显示I2C工具的版本并推出。i2cbus表示要扫描的I2C总线的编号或名称。这个数字应该对应于i2cdetect -l列出的总线之一。first last表示要扫描的从设备地址范围。modeb: 单个字节 w:16位字 s:SMBus模块 i:I2C模块的读取大小 c: 连续读取所有字节,对于具有地址自动递增功能的芯片(如EEPROM)非常有用。W与 w类似,只是读命令只能在偶数寄存器地址上发出;这也是主要用于EEPROM的。 下面是完成读取0总线上从地址为0x50的eeprom的数据,命令为:
i2cdump -f -y 0 0x50
i2cset的主要功能是通过I2C总线设置设备中某寄存器的值。该命令的常用格式为:
i2cset [-f] [-y] [-m mask] [-r] i2cbus chip-address data-address [value] …[mode]
具体参数的含义如下:
-f强制访问设备,即使它已经很忙。 默认情况下,i2cget将拒绝访问已经在内核驱动程序控制下的设备。-r在写入值之后立即读取它,并将结果与写入的值进行比较。-y取消交互模式。默认情况下,i2cdetect将等待用户的确认,当使用此标志时,它将直接执行操作。-V显示I2C工具的版本并推出。i2cbus表示要扫描的I2C总线的编号或名称。这个数字应该对应于i2cdetect -l列出的总线之一。-m mask如果指定mask参数,那么描述哪些value位将是实际写入data-addres的。掩码中设置为1的位将从值中取出,而设置为0的位将从数据地址中读取,从而由操作保存。modeb: 单个字节 w:16位字 s:SMBus模块 i:I2C模块的读取大小 c: 连续读取所有字节,对于具有地址自动递增功能的芯片(如EEPROM)非常有用。 W与 w类似,只是读命令只能在偶数寄存器地址上发出;这也是主要用于EEPROM的。 下面是完成向0总线上从地址为0x50的eeprom的0x10寄存器写入0x55,命令为:
i2cset -y -f 0 0x50 0x10 0x55
然后用i2cget读取0总线上从地址为0x50的eeprom的0x10寄存器的数据,命令为:i2cget -y -f 0 0x50 0x10
i2ctransfer的主要功能是在一次传输中发送用户定义的I2C消息。i2ctransfer是一个创建I2C消息并将其合并为一个传输发送的程序。对于读消息,接收缓冲区的内容被打印到stdout,每个读消息一行。
该命令的常用格式为:i2ctransfer [-f] [-y] [-v] [-a] i2cbus desc [data] [desc [data]]
具体参数的含义如下:
-f强制访问设备,即使它已经很忙。 默认情况下,i2cget将拒绝访问已经在内核驱动程序控制下的设备。-y取消交互模式。默认情况下,i2cdetect将等待用户的确认,当使用此标志时,它将直接执行操作。-v启用详细输出。它将打印所有信息发送,即不仅为读消息,也为写消息。-V显示I2C工具的版本并推出。-a允许在0x00 - 0x02和0x78 - 0x7f之间使用地址。一般不推荐。i2cbus表示要扫描的I2C总线的编号或名称。这个数字应该对应于i2cdetect -l列出的总线之一。 下面是完成向0总线上从地址为0x50的eeprom的0x20开始的4个寄存器写入0x01,0x02,0x03,0x04命令为:i2ctransfer -f -y 0 w5@0x50 0x20 0x01 0x02 0x03 0x04然后再通过命令i2ctransfer -f -y 0 w1@0x50 0x20 r4将0x20地址的4个寄存器数据读出来,见下图:
首先通过前面的介绍,我们已经知道站在cpu的角度来看,操作I2C外设实际上就是通过控制cpu中挂载该I2C外设的I2C控制器,而这个I2C控制器在linux系统中被称为“I2C适配器”,这个已经在驱动简介中介绍过了。而且众所周知,在linux系统中,每一个设备都是以文件的形式存在的,所以在linux中操作I2C外设就变成了操作I2C适配器设备文件。Linux系统(也就是内核)为每个I2C适配器生成了一个主设备号为89的设备节点(次设备号为0-255),它并没有针对特定的I2C外设而设计,只是提供了通用的read(),write(),和ioctl()等文件操作接口,在用户空间的应用层就可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器,并控制I2C设备的工作方式。
操作流程:
1) 确定I2C适配器的设备文件节点 i2c适配器的设备节点是/dev/i2c-x,其中x是数字。由于适配器编号是动态分配的(和注册次序有关),所以想了解哪一个适配器对应什么编号,可以查看/sys/class/i2c-dev/目录下的文件内容(在这里笔者强烈建议读者好好利用好sys文件系统):
cat /sys/class/i2c-dev/i2c-0/name
cat /sys/class/i2c-dev/i2c-1/name
然后查看硬件原理图中eeprom是挂在cpu的i2c1控制器中了,然后查看IMX6UL芯片手册中I2C1的寄存器地址为21A_0000。
比对后,我们就很容易知道eeprom外设对应的I2C控制器的设备节点为:/dev/i2c-0。
2) 打开适配器对应的设备节点 当用户打开适配器设备节点的时候,Kernel中的i2c-dev代码为其建立一个i2c_client,但是这个i2c_client并不加到i2c_adapter的client链表当中。当用户关闭设备节点时,它自动被释放。
3) IOCTL控制 这个可以参考内核源码中的include/linux/i2c-dev.h文件。下面举例说明主要的IOCTL命令:
I2C_SLAVE_FORCE设置I2C从设备地址(只有在该地址空闲的情况下成功)I2C_SLAVE_FORCE强制设置I2C从设备地址(无论内核中是否已有驱动在使用这个地址都会成功)I2C_TENBIT选择地址位长: 0 表示是7bit地址 ; 不等于0 就是10 bit的地址。只有适配器支持I2C_FUNC_10BIT_ADDR,这个请求才是有效的。I2C_FUNCS获取适配器支持的功能,详细的可以参考文件include/linux/i2c.hI2C_RDWR设置为可读写I2C_RETRIES设置收不到ACK时的重试次数I2C_TIMEOUT设置超时的时限 4) 使用I2C协议和设备进行通信 代码为:ioctl(file,I2C_RDWR,(struct i2c_rdwr_ioctl_data *)msgset); 它可以进行连续的读写,中间没有间歇。只有当适配器支持I2C_FUNC_I2C此命令才有效。参数msgset是一个指针,指向一个i2c_rdwr_ioctl_data类型的结构体,该结构体的功能就是让应用程序可以向内核传递消息,其成员包括:struct i2c_msg __ user *msgs; 和表示i2c_msgs 个数的 __u32 nmsgs,它也决定了在硬件I2C总线的硬件通信中有多少个开始信号。由于I2C适配器与外设通信是以消息为单位的,所以struct i2c_msg对我们来说是非常重要的,它可以包含多条消息,而一条消息有可能包含多个数据,比如对于eeprom页写就包含多个数据。下面就介绍一下这个结构体的内容:
__u16 addr;从设备地址__u16 flags;标志(读/写)I2C_M_TEN这是一个10位芯片地址I2C_M_RD从设备到适配器读数据I2C_M_NOSTART不发送起始位I2C_M_REV_DIR_ADDR翻转读写标志I2C_M_IGNORE_NAK忽略I2C的NACK信号I2C_M_NO_RD_ACK读操作的时候不发ACK信号I2C_M_RECV_LEN第一次接收数据的长度__u16 len;写入或者读出数据的个数(字节)__u8 *buf;写入或者读出数据的地址 buf[0]。 注意:千万不要忘记给 2c_rdwr_ioctl_data结构体中的最重要的结构i2c_msg中的buf分配内存。 5) 用read和write读写I2C设备 当然你可以使用read()/write()来与I2C设备进行通信,代码如下(以eeprom为例简要概述操作过程):
第一,打开I2C控制器文件节点: fd =open(“/dev/i2c-0”, O_RDWR);
第二,设置eeprom的设备地址:ioctl(fd,I2C_SLAVE, 0x50);
第三,向eeprom写数据:
首先将要操作的eeprom的第一个寄存器地址赋给写buf的第0个元素wr_buf[0] = 0x10;
然后把要写入的数据写入到后面的buf中for(i=1;i
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?