目录
一、I2C接口技术
1. I2C总线系统组成
2. I2C总线的状态及信号
3. I2C总线基本操作
4. 启动和停止条件
5. I2C总线数据传输格式
二、I2C总线上拉电阻的估算与选取
三、树莓派与AT24C02接口实验电路及Python SMBus串行I2C EEPROM应用编程
1. 启动RPi串行I2C接口及安装Python SMBus库
2. 树莓派与AT24C02 EEPROM接口实验电路
3. Python SMBus库函数介绍
4. 使用I2C Tools及Python SMBus读写AT24C02 EEPROM
I2C接口是嵌入式系统中常用的网络接口之一,它采用串行通信方式将MCU/传感器连接到系统总线,通过主机/从机的方式协调工作。
I2C/IIC(Inter-Integrated Circuit)总线是由PHILIPS公司于1982年针对MCU/传感器等应用需求而研制的一种两线式串行总线,用于连接MCU及传感器等设备。
I2C总线的主要特点如下:
(1)I2C总线最主要的优点是其简单性和有效性。
(2)由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。
(3)I2C总线的长度可高达25英尺(约7.6m),并且能够以标准模式100Kbps的传输速率支持40个组件。新一代I2C总线还支持高速模式400Kbps传输。
(4)I2C总线的另一个优点是支持多主控(multi-mastering), 其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号传输和时钟频率。当然,在任何时间点上只能有一个主控。
I2C总线协议包含两层协议:物理层和数据链路层。
在物理层,I2C总线仅使用了两条信号线:一个是串行数据线SDA (Serial DAta line),它用于数据的发送和接收;另一个是串行时钟线SCL (Serial Clock Line)构成的串行总线,它用于指示何时数据线上是有效数据,即数据同步。MCU与被控IC之间、IC与IC之间进行双向传送,I2C标准模式最大传送速率为100kbps,I2C快速模式最大传输速率为400kbps。
在数据链路层,每个连接到I2C总线上的设备都有唯一的地址,设备的地址由系统设计者决定。在信息的传输过程中,I2C总线上并接的每一设备既是主设备(或从设备)又是发送器(或接收器),这取决于它所要完成的功能。
由I2C总线所构成的系统可以有多个I2C节点设备,并且可以是多主系统,任何一个设备都可以为主I2C;但是任一时刻只能有一个主I2C设备,I2C具有总线仲裁功能,以保证系统正确运行。主I2C设备发出时钟信号、地址信号和控制信号,选择通信的从I2C设备并控制收发。
I2C总线要求:(1)各个节点设备必须具有I2C接口功能;(2)各个节点设备必须共地;(3)两根信号线必须接上拉电阻Rp。如图1所示。
(1)空闲状态
SCL和SDA均处于高电平状态,即为总线空闲状态(空闲状态为何是高电平的道理很简单,因为它们都接上拉电阻)。
(2)占有总线和释放总线
若想让器件使用总线应当先占有它,占有总线的主控器向SCL线发出时钟信号。数据传送完成后应当及时释放总线,即解除对总线的控制(或占有),使其恢复成空闲状态。
(3)启动信号[S]
启动信号由主控器产生。在SCL信号为高时,SDA产生一个由高变低的电平变化,产生启动信号。
(4)结束/停止信号[P]
当SCL线高电平时,主控器在SDA线上产生一个由低电平向高电平跳变,产生停止信号。启动信号和停止信号的产生见图2所示。
(5)应答/响应信号[A/NA]
应答信号是对字节数据传输的确认。应答信号占1位,数据接收者接收1字节数据后,应向数据发出者发送一个应答信号。对应于SCL第9个应答时钟脉冲,若SDA线仍保持高电平,则为非应答信号(NA/ACK)。低电平为应答,继续发送;高电平为非应答,结束发送。
(6)控制位信号[R/nW]
控制位信号占1位,IIC主机发出的读写控制信号,高为读、低为写(对IIC主机而言)。控制位(或方向位)在寻址字节中给出。
(7)地址信号
地址信号为从机地址,占7位,称之为“寻址字节”(见表1)。
下面对表1中的各字段进行说明。
器件地址(DA3-DA0):DA3-DA0是I2C总线接口器件固有的地址编码,由器件生产厂家给定,如AT24C××I2C总线EEPROM器件的地址为1010等。
引脚地址(A2、A1、A0):引脚地址由I2C总线接口器件的地址引脚A2、A1、A0的高低来确定,接高电平者为1,接地者为0。
读写控制位/方向位(R/n W):R/nW为1表示主机读,R/nW为0表示主机写。
7位地址和读写控制位组成1个字节,即寻址字节。
(8)等待状态
在IIC总线中,赋予接收数据的器件具有使系统进行等待状态的权力,但等待状态只能在一个数据字节完整接收之后进行。例如,当进行主机发送从机接收的数据传送操作时,若从机在接收到一个数据字节后,由于中断处理等原因而不能按时接收下一个字节;从机可以通过把SCL下拉为低电平,强行使主机进入等待状态;在等待状态下,主机不能发送数据,直到从机认为自己能继续接收数据时,再释放SCL线,使系统退出等待状态,主机才可以继续进行后续的数据传送。
(1)串行数据线SDA和串行时钟线SCL在连接到总线的器件间传递信息。
(2)每个器件都有一个唯一的地址标识,无论是MCU、LCD驱动器、存储器或键盘接口。
(3)每个器件都可以作为一个发送器或接收器,由器件的功能决定。显然,LCD驱动器只是一个接收器,而存储器则既可以接收又可以发送数据。
(4)除了将器件看作发送器和接收器外,在执行数据传输时它也可以被看作是主机或从机。
(5)主机是初始化总线的数据传输并产生允许传输时钟信号的器件,此时任何被寻址的器件都被看作是从机。
在SCL 线是高电平时,SDA 线从高电平向低电平切换,这个情况称为启动条件。当SCL是高电平时,SDA 线由低电平向高电平切换,称为停止条件。
启动和停止条件一般由主机产生。总线在启动条件后被认为处于忙的状态,在停止条件的某段时间后,总线被认为再次处于空闲状态。如果产生重复启动条件Sr而不产生停止条件P,总线将一直处于忙状态。
I2C总线数据传输格式见图3所示。在图3中,S为启动信号,R/nW为读写控制位,A/NA为应答信号,P为停止信号。
由于I2C设备的SCL、SDA总线是漏极开路的,因此在前面的图1中, I2C总线的SCL、SDA引脚必须外接上拉电阻Rp。
一般I2C的上拉电阻Rp在1 kΩ∽10 kΩ之间选取,如,Rp可以取1.5kΩ、1.8kΩ、2.2kΩ、4.7kΩ、5.1kΩ、6.8kΩ、10kΩ等典型值,上拉电阻的大小对时序有一定影响,对信号的上升时间和下降时间也有影响。
I2C上拉电阻Rp选取估算公式如下:
Rpmin={VDD(min)-0.4V}/3mA
Rpmax=(T/0.874) *C (T=1us, 100KHz; T=0.3us, 400KHz)
C是总线电容(Bus Capacitance)或总线负载电容。
Rp最大值由总线电容最大值CBmax决定,Rp最小值由VIO(VDD)与上拉驱动电流(设最大值为3mA)决定;
关于Rpmin的取值:在5V供电的嵌入式系统中,有Rpmin=5V/3mA≈1.7kΩ;在3.3V供电的嵌入式系统中,有Rpmin=3.3V/3mA=1.1kΩ;在2.8V供电的嵌入式系统中,有Rpmin=2.8V/3mA≈1kΩ。
关于Rpmax的取值:在I2C标准模式下,100Kbps总线负载电容最大值<=400pF;在I2C快速模式下,400Kbps总线的负载电容最大值<=200pF。根据具体的使用场景、当前的器件制造工艺、PCB的走线距离等因素以及标准向下兼容性,设计中以I2C快速模式为基础,即总线负载电容<200pF时,传输速度达到400Kbps是不成问题的,现按5V供电系统对应于50pF∽200pF估算,有Rpmax取值范围是1.7kΩ∽6.9kΩ。根据Rpmin与Rpmax的限制范围,在5V供电的嵌入式系统中,可取Rp=5.1kΩ, 总线负载电容的环境要求也容易达到;在3.3V供电的嵌入式系统中,可选Rp=1.8kΩ∽4.7kΩ;在2.8V供电的嵌入式系统中,控制台应用可选Rp=1.5kΩ∽2.2kΩ,可穿戴式或便携式等低供耗应用可选Rp=4.7kΩ牺牲速度来换取电池使用时间。总之,电源电压限制了上拉电阻Rp的最小值;总线负载电容(总线电容)限制了上拉电阻Rp的最大值。
如果使用树莓派I2C总线控制外设或传感器,则树莓派一般工作于主机模式。树莓派I2C总线遵守SMBus(System Management Bus,系统管理总线)协议。从类型上说,SMBus协议可看成是I2C总线协议的子类,采用Python语言访问I2C设备可直接使用SMBUS库/SMBUS模块。
默认情况下,I2C总线是禁止使用的,我们可以在Linux终端用raspi-config工具启动IC2接口,运行raspi-config工具命令如下:
$ sudo raspi-config
运行后按菜单提示,即可启动I2C接口。
另一种启动I2C接口的方法是在Preferences的主菜单中找到Raspberry Pi Configuration工具启动I2C接口。
安装Python的I2C库SMBus的方法是输入以下命令:
$ sudo apt-get install python-smbus
为了使这些修改有效,需要重新引导树莓派。
以树莓派3B为例,RPi 3B与AT24C02 EEPROM接口实验电路原理图见图4所示。由图4可知,RPi 3B串行I2C总线自带1.8kΩ上拉电阻,因此,RPi 3B串行I2C总线与AT24C02接口无需再外接上拉电阻。需要强调的是,是否在I2C总线外接上拉电阻,要看所使用的开发板是否自带I2C总线上拉电阻;若开发板没有提供I2C总线上拉电阻,则需按前面的I2C总线上拉电阻估算方法外接两个上拉电阻Rp。
为方便起见,这里使用面包板搭建RPI 3B与AT24C02接口实验电路,ATC24C02的VCC与RPi 3B的3.3V电源Pin1物理引脚连接,GND与RPI 3B的GND接地引脚Pin14连接,SCL与RPI 3B的I2C-1串行时钟线SCL.1的Pin14物理引脚连接,SCL与RPI 3B的I2C-1串行数据线SDA.1的Pin3物理引脚连接。这里,地址线A0、A1、A2都接地,查看AT24C02器件手册可知,在此配置下,I2C设备AT24C02地址是0x50 (注意:树莓派中的I2C设备地址计算是根据I2C器件的实际寻址地址0b1010A2A1A0得出的,故AT24C02设备寻址地址为0b1010000=0x50;如果按I2C器件手册中给出的带读写控制位的寻址地址字节为0b1010A2A1A0R/nW,即写I2C器件寻址地址为0xa0, 读I2C器件寻址地址为0xa1), 写保护WP接地,这样树莓派就能正常读写I2C设备了。实验接口电路连接好后,建议先用万用表检查接口连线是否正确(特别注意电源和地之间不能短路),然后再开机启动树莓派对AT24C02器件进行读写操作(见图5)。
在树莓派中,我们可用Python SMBus库函数访问串行I2C设备,导入SMBus模块及常用SMBus库函数介绍如下。
(1) Import SMBus
●To access I2C bus on Raspberry Pi using SMBus Python module, import SMBus module as follows.
import smbus
●Create object of SMBus class to access I2C based Python function.
= smbus.SMBus(I2C port no.)
I2C port no : I2C port no. i.e. 0 or 1
●Example - Bus = smbus.SMBus(1)
Now, we can access SMBus class with Bus object.
(2) Bus.write_byte_data(Device Address, Register Address, Value)
●This function is used to write data to the required register.
Device Address : 7-bit or 10-bit device address
Register Address : Register address to which we need to write
Value : pass value which needs to write into the register
●Example - Bus.write_byte_data(0x68, 0x01, 0x07)
(3) Bus.write_i2c_block_data(Device Address, Register Address, [value1, value2,….])
●This function is used to write a block of 32 bytes.
Device Address : 7-bit or 10-bit device address
Register Address : Register address to which we need to write data
Value1 Value2…. : write a block of bytes to the required address
●Example - Bus.write_i2c_block_data(0x68, 0x00, [0, 1, 2, 3, 4, 5]) # write 6 bytes of data from 0 address.
(4) Bus.read_byte_data(Device Address, Register Address)
●This function is used to read data byte from required register.
Device Address : 7-bit or 10-bit device address
Register Address : Register address from which we need to read data
●Example - Bus.read_byte_data (0x68, 0x01)
(5) Bus.read_i2c_block_data(Device Address, Register Address, block of bytes)
●This function is used to read a block of 32 bytes.
Device Address – 7-bit or 10-bit device address
Register Address – Register address from which we need to read data
Block of Bytes – read no of bytes from the required address
●Example - Bus.read_i2c_block_data(0x68, 0x00, 8) # return value is a list of 6 bytes
在树莓派终端输入以下命令,安装I2C Tools:
pi@yuanzy:~ $ sudo apt-get install i2c-tools
接下来,针对图4的实验接口电路,用 I2C Tools 命令对AT24C02基本读写操作功能进行检验。在下面的I2C Tools各命令中, I2C使用树莓派的 I2C-1(SCL.1, SDA.1),AT24C02设备地址为0x50。
pi@yuanzy:~ $ sudo i2cdetect -l
i2c-1 i2c bcm2835 I2C adapter
pi@yuanzy:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – -- – -- – -- – -- – -- – -- –
10: – -- – -- – -- – -- – -- – -- – -- – --
20: – -- – -- – -- – -- – -- – -- – -- – --
30: – -- – -- – -- – -- – -- – -- – -- – --
40: – -- – -- – -- – -- – -- – -- – -- – --
50: 50 51 – -- – -- – -- – -- – -- – -- – --
60: – -- – -- – -- – -- – -- – -- – -- – --
70: – -- – -- – -- – --
pi@yuanzy:~ $ sudo i2cdump -y 1 0x50
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff …
以上i2cdump显示了AT24C02设备所有字节单元的内容,因为是新购置芯片,故其256个字节单元为全1或0xff(即芯片内容为空)。
pi@yuanzy:~ $ sudo i2cset -y 1 0x50 0x00 0x60
pi@yuanzy:~ $ sudo i2cget -y 1 0x50 0x00
0x60
上面使用i2cset命令向AT24C02设备0#字节单元写入0x60,i2cget 读取AT24C02设备0#字节单元内容显示为0x60,说明写入的数据与读取的数据一致,树莓派读写AT24C02设备操作正常。
下面是用Python和Python SMBus库函数编写名为I2CAT24C02.py的程序向AT24C02器件256字节单元顺序写入0~255,然后再顺序读取AT24C02中的字节单元并显示输出,程序清单见图6所示。
I2CAT24C02.py程序顺序读取AT24C02中的256字节单元显示结果见图7所示。
还可使用I2C Tools的i2cdump命令显示AT24C02中的256字节单元内容(见图8)。由图7和图8可知,读取AT24C02设备字节单元内容的显示结果与写入到AT24C02设备字节单元的数据完全相同。