IIC协议详解--Linux下I2C读取AT24C02例程

本文详细介绍了I2C协议的基本概念、硬件和软件框架,包括I2C的传输数据格式、时序信号、以及在Linux环境下的I2C读写操作。同时提到了SMBus与I2C的关系以及相关的工具I2CTools。
摘要由CSDN通过智能技术生成

记录一下IIC,好记性不如烂笔头。


一.I2C 简介

I2C 是很常见的一种总线协议, I2C是NXP公司设计的,I2C 使用两条线在主控制器和从机之间进行数据通信。一条是 SCL(串行时钟线),另外一条是 SDA(串行数据线),因为I2C这两条数据线是开漏输出的,所以需要接上拉电阻总线空闲的时候 SCL 和 SDA 处于高电平。 I2C 总线标准模式下速度可以达到 100 Kb/s快速模式下可以达到 400 Kb/s,在高速模式下可达到3.4 Mbit/s。一般通过I2C总线接口可编程时钟来实现传输速率的调整。

感兴趣的可以读《I2C总线规范和用户手册》

I2C 硬件框架

在这里插入图片描述
I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个从设备都会对应一个唯一的地址(可以从I2C器件的数据手册得知)。主从设备之间就通过这个地址来确定与哪个器件进行通信,在通常的应用中,我们把CPU带I2C总线接口的模块作为主设备,把挂接在总线上的其他设备都作为从设备。
⚫ 在一个芯片(SoC)内部,有一个或多个 I2C 控制器
⚫ 在一个 I2C 控制器上,可以连接一个或多个 I2C 设备。

I2C总线上可挂接的设备数量受总线的最大电容400pF限制,如果所挂接的是相同型号的器件,则还受器件地址的限制。一般I2C设备地址是7位地址(也有10位),地址分成两部分:芯片固化地址(生产芯片时候哪些接地,哪些接电源,已经固定),可编程地址(引出IO口,由硬件设备决定)。例如:某一个器件是7 位地址,其中1010xxx 高4位出厂时候固定了,低3位可以由设计者决定。则一条I2C总线上只能挂该种器件最少8个。如果7位地址都可以编程,那理论上就可以达到128个器件,但实际中不会挂载这么多。

⚫ I2C 总线只需要 2 条线:时钟线 SCL、数据线 SDA
⚫ 在 I2C 总线的 SCL、SDA 线上,都有上拉电阻
⚫ 总线数据长度:I2C总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输。

如果玩过单片机,肯定对模拟I2C时序这个操作并不陌生(如果对IIC时序不清楚,可以自行补充I2C时序基础知识)。在Linux上,cpu会自带I2C控制器,有了这个I2C控制器之后,就不用模拟时序了,只需要关注怎么把数据写到寄存器和怎么从寄存器读数据即可,具体的时序都是由I2C控制器来自动完成。

I2C 软件框架

在这里插入图片描述
以 I2C 接口的存储设备 AT24C02 为例:
⚫ APP:
◼ 提出要求:把字符串"abcde"写入 AT24C02 地址 16 开始的地方
◼ 不关心底层实现的细节
◼ 只需要调用设备驱动程序提供的接口
⚫ AT24C02 驱动:
◼ 知道 AT24C02 要求的地址、数据格式
◼ 知道发出什么信号才能让 AT24C02 执行擦除、烧写工作
◼ 知道怎么判断数据是否烧写成功
◼ 构造好一系列的数据,发给 I2C 控制器
⚫ I2C 控制器驱动
◼ 根据 I2C 协议发出各类信号:I2C 设备地址、I2C 存储地址、数据
◼ 根据 I2C 协议判断

IIC 传输数据的格式

I2C基本时序信号

I2C 协议中数据传输的单位是字节,也就是 8 位。但是要用到 9 个时钟:前面 8 个时钟用来传输 8 数据,第 9 个时钟用来传输回应信号。传输时,先传输最高位(MSB)。注意:起始和结束信号总是由主设备产生。
⚫ 空闲状态:SCL和SDA都保持着高电平。
⚫ 开始信号(S):SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线。
⚫ 结束信号(P):SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据
⚫ 响应信号(ACK):接收器在接收到 8 位数据后,在第 9 个时钟周期,拉低SDA。每个字节传输完成后的下一个时钟信号,在SCL高电平期间,SDA为低,则表示一个应答信号。
⚫ SDA 上传输的数据必须在 SCL 为高电平期间保持稳定,SDA 上的数据只能在SCL 为低电平期间变化
在这里插入图片描述

写操作流程

⚫ 主芯片要发出一个 start 信号
⚫ 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0表示写,1 表示读)
⚫ 从设备回应(用来确定这个设备是否存在),然后就可以传输数据
⚫ 主设备发送一个字节数据给从设备,并等待回应
⚫ 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据
⚫ 数据发送完之后,主芯片就会发送一个停止信号
⚫ 下图:白色背景表示"主→从",灰色背景表示"从→主"
在这里插入图片描述

读操作流程

⚫ 主芯片要发出一个 start 信号
⚫ 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0表示写,1 表示读)
⚫ 从设备回应(用来确定这个设备是否存在),然后就可以传输数据
⚫ 从设备发送一个字节数据给主设备,并等待回应
⚫ 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。
⚫ 数据发送完之后,主芯片就会发送一个停止信号
⚫ 下图:白色背景表示"主→从",灰色背景表示"从→主"
在这里插入图片描述

二. Linux下IIC读写

在这里插入图片描述
APP 可以通过两类驱动程序访问设备, I2C 设备自己的驱动程序,或者内核自带的 i2c-dev.c 驱动程序。
⚫ I2C Device Driver
◼ I2C 设备自己的驱动程序
◼ 内核自带的 i2c-dev.c 驱动程序,它是 i2c 控制器驱动程序暴露给用户空间的驱动程序(i2c-dev.c)
⚫ I2C Controller Driver
◼ 芯片 I2C 控制器的驱动程序(称为 adapter)
◼ 使用 GPIO 模拟的 I2C 控制器驱动程序(i2c-gpio.c)
Linux把I2C控制器抽象成了一个i2c_adapter,我们只要来分配这个i2c_adapter,就可以得到一个I2C控制器。
先来看一下我们的系统里面都有哪些I2C的节点。如下所示:

(base
  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是一个基于Arduino的iic读取AT24C02的示例代码: ``` #include <Wire.h> #define EEPROM_ADDR 0x50 // EEPROM地址 #define EEPROM_SIZE 256 // EEPROM容量 void setup() { Serial.begin(9600); Wire.begin(); // 初始化I2C总线 } void loop() { // 读取整个EEPROM byte data[EEPROM_SIZE]; readEEPROM(0, data, EEPROM_SIZE); // 输出EEPROM数据 for (int i = 0; i < EEPROM_SIZE; i++) { Serial.print(data[i], HEX); Serial.print(" "); if ((i+1) % 16 == 0) { Serial.println(); } } Serial.println(); delay(5000); } // 从EEPROM中读取数据 void readEEPROM(int addr, byte* data, int len) { Wire.beginTransmission(EEPROM_ADDR); Wire.write((byte)(addr >> 8)); // 地址高位 Wire.write((byte)(addr & 0xFF)); // 地址低位 Wire.endTransmission(); Wire.requestFrom(EEPROM_ADDR, len); for (int i = 0; i < len && Wire.available(); i++) { data[i] = Wire.read(); } } ``` 在上面的示例代码中,我们定义了EEPROM的地址为0x50,容量为256字节。在`setup()`函数中,我们初始化了I2C总线,然后在`loop()`函数中,我们读取整个EEPROM的数据,并输出到串口。在`readEEPROM()`函数中,我们先通过I2C总线发送地址和要读取的起始地址,然后通过`Wire.requestFrom()`函数请求读取数据。最后,我们通过`Wire.read()`函数读取数据并保存到`data`数组中。 要使用此代码,您需要将AT24C02连接到Arduino的I2C总线上,并将A0、A1和A2引脚连接到GND或VCC以设置EEPROM的I2C地址。最后,您可以使用Arduino IDE的串口监视器查看EEPROM的内容。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一码当前

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

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

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

打赏作者

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

抵扣说明:

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

余额充值