当前位置:文档之家› PIC24系列单片机原理与开发 第8章 IIC总线接口及编程

PIC24系列单片机原理与开发 第8章 IIC总线接口及编程

第8章 I2C总线接口及编程

8.1概述

I2C总线(Inter Integrated Circuit)是一种由PHILIPS公司开发的两线式串行总线,也是一种应用很广泛的串行接口逻辑,主要用于电路板内芯片的信息交换。I2C总线占用口线少、接口简单,减少了电路板的空间和芯片引脚的数量,降低了互联成本。I2C总线的另一个优点是,它支持多主控(multimastering)结构。总线上任何能够进行发送和接收的芯片都可以成为主控器。一个主控器能够控制信号的传输和时钟频率。因此很多IC芯片都采用I2C总线接口,例如显示驱动芯片、A/D和D/A转换芯片、温度传感器、EEPROM、日历时钟芯片等,极大地方便了嵌入式装置的电路和PCB板的设计。

I2C总线的主要特点如下:

(1)总线为二线制结构:双向的串行数据线SDA和串行同步时钟线SCL。总线上的所有

器件的同名端都分别挂在SDA、SCL线上(见图8-1)。

(2)总线上所有器件的SDA、SCL引脚的输出驱动都为漏极开路结构,通过外接上拉电

阻将总线上所有节点的SDA、SCL信号电平实现“线与”的逻辑关系。这不仅可以

将多个节点器件按同名端引脚直接挂在SDA、SCL线上,还使总线具备了“时钟同

步”,确保不同工作速度的器件同步工作。

(3)总线上所有器件都有一个“地址码”,主控器件通过地址码建立多机通信的机制。

因此I2C总线省去了外围器件的片选线,这样无论总线上挂接多少器件,仍然为简

单的二线结构。

(4)总线上的所有器件都具有“自动应答”功能,保证了数据交换的正确性;

(5)总线系统具有“时钟同步”功能。利用SCL线的“线与”逻辑协调不同器件之间的

速度问题。

(6)在I2C总线系统中可以实现“多主机(主控器)”结构。依靠“总线仲裁”机制确

保系统中任何一个主控器都可获得总线的控制权。各主控器之间没有优先级,当多

主机竞争总线时,依靠主控器对其SDA信号的“线与”逻辑,自动实现“总线仲裁”

功能。

(7)总线系统中的主控器一般是带CPU的模块;而被控器可以是无CPU的普通外围器

件,也可以是具有CPU的模块。主控器与被控器的区别在于SCL的发送权,即对总

线的控制权;

(8)I2C总线的工作速度分为3等级:S(标准模式),速率为100kb/s;F(快速模式),

速率为400kb/s;Hs(高速模式),速率为3.4Mb/s。

A外围器件1外围器件2外围器件m主控B外围器件n

8-1具有多主机的I2C总线的系统结构

根据型号的不同,PIC24系列的大多数芯片集成有两个I2C模块,有几款型号集成了三个I2C模块,只有少数几种型号芯片为一个I2C模块。例如PIC24FJxxGA006芯片的I2C模块为2个:I2C接口1,其引脚是SCL1/RG2和SDA1/RG3;I2C接口2,其引脚是SCL2/RF4

和SDA2/RF5。其它芯片的具体情况可参考相应型号的数据手册。

图8-2是PIC24系列芯片的I 2C 模块的结构框图。PIC24的I 2C 模块完全兼容I 2C 总线协议,并且还具有自己的一些特点:

模块中有独立波特率发生器,其不使用芯片中其他定时器资源。●

模块内有独立的主器件逻辑部件和从器件逻辑部件,各自的事件产生中断。●

支持多主机系统,在多主机总线仲裁期间,不会丢失任何报文。●

可以检测7位和10位器件地址,并可配置地址屏蔽。●

可以检测I 2C 协议中定义的全局呼叫地址。●

具有总线转发器模式(Bus Repeater Mode ),允许模块作为从器件忽略报文地址,接收所有报文。●

具有自动SCL 时钟延长功能,可为处理器提供响应从器件数据请求的延时。●支持100~400 kHz 总线规范。

8.2

I 2C 总线协议8.2.1总线时序

I 2C 总线是由数据线SDA 和时钟SCL 构成的串行总线,可发送和接收数据,总线上的每次数据传输都是由主控器所发起,并且只有在总线空闲时才能启动数据传输。

I 2C 总线在传送数据过程中有三个特征时序信号,它们分别是:起始信号、结束信号和应答信号。

(1)起始信号(S):当时钟线SCL 为高电平时,若SDA 由高电平变成低电平,则为起

始信号。

(2)结束信号(P):当时钟线SCL 为高电平时,若SDA 由低电平变成高电平,则为结

内部数据总线

8-2PIC24系列I 2

C 模块结构框图

(3)应答信号(A):总线数据传送时,每成功地传送一个字节数据后,数据接收方须产

生一个应答信号:在第9个时钟周期时将SDA 线拉低(这时发送方已释放数据

线SDA ),作为对发送方的应答(ACK),表示其已收到一个8位数据。

数据传送的格式为高位(D7)在先,SDA 线上的数据只有在时钟 SCL 为低电平时方可改变,在SDA 线上数据稳定后,时钟SCL 变为高电平后(期间)传送数据有效。每个SCL 时钟脉冲传送一位数据。当时钟线SCL 为高电平时,数据线SDA 必须保持稳定状态,不允许有跳变,否则数据线的任何电平变化将被看作总线的起始或停止信号。

8.2.2主控制器向从器件发送数据(写操作)

总线的操作过程如下:

(1)启动:主控器在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发

送起始信号“S”;

(2)寻址从器件:主控器接着发送一个命令字节。该字节由 7位的从器件地址(D7~D1)

和 1位读写控制位 R/W(D0)组成(此时 R/W=0);

(3)从器件应答:与地址匹配的从器件收到命令字节后,在时钟SCL 变低时产生应答信

号 ACK(ACK=0),时钟SCL 总是由主控器产生。

(4)发送数据字节:主控器收到从器件应答信号后开始发送第一个字节的数据;

(5)从器件应答:从器件每收到一个字节数据后产生一个应答信号 ACK;

(6)继续发送:主控器收到应答信号后再发送下一个数据字节, … …;

(7)结束:当主控器发送最后一个数据字节并收到被控器的 ACK 后,发送一个停止信

号“P”结束本次通信并释放总线。从器件收到“P”信号后也退出通信。

说明1:对于需要寻址单元地址的从器件,如24C256 EEPROM 芯片,首先发送的2个数据字节为芯片内存储单元的地址(高字节在前),然后才是写入改地址单元的数据。如果主控器未检测到从器件的应答信号,则说明传送出错。下面的图 8-4是对24C256芯片进行字节写的时序。

位应答位应答位应答位应答位停止位

图 8-4写EEPROM 24C256的一个字节时序

地址字节A15~A8A7~ A0数据

单元地址:MSB LSB

8.2.3主控器接收从器件的数据(读操作)

读操作的总线过程如下(时钟SCL 总是由主控器产生):

(1)启动:主控器在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,

发送起始信号“S”;

(2)寻址从器件:主控器接着发送一个命令字节。该字节由 7位的从器件地址(D7~

D1)和 1位读写控制位 R/W(D0)组成。如果还需寻址从器件的地址单元,则

位R/W=0,表示后续字节为“写”地址码。若不要寻址从器件的地址单元,则位

R/W=1,表示后续为“读”从器件的数据。

(3)从器件应答:与地址匹配的从器件收到命令字节后,在时钟SCL 变低时产生应

答信号 ACK(ACK=0)。

(4)发送所读单元的地址字节:主控器每发送一个字节均检测应答信号,从器件每

收到一个字节数据后产生一个应答信号 ACK。

(5)重新启动:主控器发送起始信号“S”,接着发送“读”命令字节。该字节由 7

位的从器件地址(D7~D1)和 1位读写控制位 R/W(D0)组成,其中位R/W=1。

(6)从器件应答:与地址匹配的从器件收到命令字节后,在时钟SCL 变低时产生应

答信号 ACK(ACK=0)。

(7)主控器读:在时钟SCL 的作用下,从器件在每个脉冲变低电平时将数据位送数

据线 SDA,供主控器在脉冲变电平时读入。

(8)主控器应答:主器件每收到一个字节数据后产生一个应答信号 ACK,但最后一

个字节除外(不作应答,即产生一个NACK 信号)。

(9)继续读:从器件收到应答信号后向主控器发送下一个数据,重复(7)~(9),

直到读完所需的字节数。

(10)结束:当主控器发送NACK 后,接着发送停止信号“P”,结束本次通信并释放

总线。从器件收到“P”信号后也退出通信。

说明1:对于需要寻址单元地址的从器件,如24C256 EEPROM 芯片,在读之前先要发送的2个字节的芯片内存储单元的地址(高字节在前),故首先仍是写指令。写完单元地址后要重新启动总线,才能发送读指令,然后再接收从器件发送的数据。图 8-5是对24C256进行单字节读的时序。如果是连续读从器件的多个字节,则主控器每收到一个字节后需发送一个应答信号 ACK,以通知从器件继续发送数据。若在应答位处主控器不产生应答信号,且接下来产生停止信号,则从器件退出通信。

说明2:从器件的单元地址也可以是一个字节或多个字节,取决于从器件的具体结构。例如 24C01/2芯片,单元地址为一个字节。

说明

3:如果不要寻址单元地址,则不要过程中的(2)~(4)。

写指令A15~

A8A7~ A0单元地址:MSB LSB

始位应答位应答位

应答位应答位停止位

读指令不应答重启动 8-5

读EEPROM 24LC256的一个字节

时序

8.3.I 2C 模块的寄存器

和其它外设模块一样,要使I 2C 模块正常工作,需按功能要求正确地配置和操作模块的各寄存器。I 2Cx (x 代表编号)模块有7个寄存器,它们是:

●控制寄存器I2CxCON :用于设置模块的工作方式和控制操作。

●状态寄存器I2CxSTAT :该寄存器的各状态标志位指示模块的工作状态。

●地址寄存器I2CxADD :用于装载从器件地址,该寄存器为9位。

地址屏蔽寄存器I2CxMSK :该寄存器指定I2CxADD 中的哪些位可以忽略,从而

提供了多地址支持。

●接收缓冲寄存器I2CxRCV :从总线接收的数据存于此寄存器供用户读取,I2CxRCV

寄存器是8位的只读寄存器。

●发送寄存器I2CxTRN :用于装载需发送的字节数据。I2CxTRN 为8位寄存器。●波特率发生器重载寄存器I2CxBRG :用于装载模块的波特率发生器重载值,其定

义了模块的波特率。

下面详细介绍各寄存器的功能。

1.控制寄存器I2CxCON

该寄存器主要负责模块的工作方式和操作控制。表8-1所列为控制寄存器I2CxCON 的各位定义。

表8-1控制寄存器I2CxCON各位功能定义其中:R=

, W=,-n =上电复位值,HC =用硬件清零R/W-0 U-0 R/W-0 R/W-1

R/W-0R/W-0 R/W-0 R/W-0I2CEN

SSLW MEN bit 15bit 8R/W-0 R/W-0R/W -0 R/W-0,HC R/W-0,HC R/W-0,HC R/W-0,HC R/W-0,HC GCEN

bit 7 bit 0bit 15

EN :1 =使能I2Cx ,将SDAx和SCLx引脚配置为I2C总线引脚0 =禁止I2Cx 。I2C引脚由端口功能控制bit 13

:1 =当器件进入空闲模式时模块停止工作0 =在空闲模式时模块继续工作bit 12

(作为从器件时):1 =释放SCLx时钟0 =保持SCLx (时钟延长)bit 11

(IPMI)(注1):1 =使能 IPMI ,应答所有地址0 =禁止 IPMI 支持模式bit 10

:1 = I2CxADD为10位从器件地址寄存器0 = I2CxADD为7位从器件地址寄存器bit 9

SSLW :1 =禁止边沿斜率控制0 =使能边沿斜率控制bit 8

MEN (注2):1 =使能符合SMBus规范的I/O引脚阈值0 =禁止SMBus输入阈值bit 7作为从器件时):1 = I2CxRSR中接收到广播呼叫地址时产生中断使能模块接收数据)

0 =禁止广播呼叫地址

bit 6

时钟延长使能位作为从器件时,与SCLREL )

1 =使能软件或接收时钟延长

0 =禁止软件或接收时钟延长

(作为主控器接收操作时):1 =在应答期间发送NACK

0 =在应答期间发送ACK

bit 4作为主控器接收操作时)

1 =发送应答和ACKDT ,应答发送结束时硬件自动清零此位

0 =应答序列不在进行中

bit 3作为主控器):

1 =使能接收模式在主器件接收到数据字节的第8)

0 =非接收模式

bit 2(作为主控器):

1 =,发送完毕硬件自动清零此位

0 =不发送停止信号

bit 1(作为主控器):

1 =,发送完毕硬件自动清零此位

0 =不产生重新启动信号

bit 0

(作为主控器):

1 =,发送完毕硬件自动清零此位

0 =不产生起始信号注1:IPMI 是智能型平台管理接口(Intelligent Platform Management Inte rface)的缩写,是管理基于 Intel 结构的系统中所使用的外围设备采用的一种工业标准。注2:SMBus 是系统管理总线(System Management Bus)的缩写,主要用于用于笔記本的电池管理或PC 机組态管理和用电管理。

2.状态寄存器I2CxSTAT

表8-2所列为状态寄存器I2CxSTAT 的各位定义。这些状态位是由硬件根据当时收发传送工作情况而自动建立,它们指示着模块的工作状态。

表8-2:状态寄存器I2CxSTAT各位功能定义其中:R=

,-n =上电复位值, HS=由硬件置位,HC =由硬件清零,HSC==由硬件置位/清零R-0, HSC

R-0, HSC U-0 U-0 U-0R/C-0,HS R-0, HSC R-0, HSC ACKSTAT

TAT CL TAT DD10bit 15bit 8R/C-0,HS R/C-0,HS R-0,HSC R/C-0,HSC R/C-0,HSC R-0,HSC R-0,HSC R-0,HSC IWCOL 2COV /A

bit 7 bit 0bit 15TAT (作为主控器发送操作,硬件置1):1 =

收到从器件的NACK 0 =

收到从器件的ACK bit 14TAT (主控器发送操作)1 =

。在发送开始时置1从器件应答结束时被清零)0 =未发送数据

bit 10CL :1 =在主控器操作期间检测到总线冲突

0 =无冲突

bit 9TAT :

1 =(当检测到停止条件时被清零)

0 =

未收到全局呼叫地址

bit 8DD10:1 = 10(当检测到停止条)

0 = 10位地址不匹配

bit 7WCOL :1 = I 2C ,写I2CxTRN (需软件清零)

0 =。

2COV

1 = I2CxRCV,又收到新字节(需软件清零)0 =无溢出

bit 5/A /(作从器件):1 =上一个接收的字节是数据

0 =上一个接收的字节是器件地址

;写I2CxTRN或接收到从器件字节时硬件置1

bit 4

:1 =。0 =。

检测停止条件时硬件置1检测到启动、重新启动位时硬件清零。

bit 3:1 =(或重新启动)位。0 =未检测启动位、重新启动时硬件置1在停止条件时硬件清零。

bit 2

/(从器件工作时): 1 =:从器件发数据,供主控器读

0 =:主控器发数据,写从器件

接收到I2C器件地址字节后由硬件置1,即寻址字节中的R/W。

bit 1BF

1 = I2CxRCV(在软件读I2CxRCV)0 =,I2CxRCV空

bit 0

1 = I2CxTRN(软件写I2CxTRN时硬件置1)0 =(由硬件清零),I2CxTRN为空

3.其余5个寄存器

(1)地址屏蔽寄存器I2CxMSK

只在作为从器件时地址屏蔽寄存器I2CxMSK才起作用。该寄存器可读也可写,其高6位为无效位,读时为“0”;低10位(I2CxMSK<9:0>)为屏蔽选择位。设报文寻址的地址数据的各位为Ai(10位地址:i=0~9;7位地址:i=0~6),若I2CxMSK置“1”,则对报文寻址的Ai位不作匹配检查,即屏蔽掉该位地址。换言之只对I2CxMSK为“0”的报文相应地址位进行匹配判定。

I2CxMSK:1=对接收报文的地址位Ai使能屏蔽,对该位不要求位匹配;

0=禁止对Ai位的屏蔽,该位要求位匹配。

(2)接收缓冲寄存器I2CxRCV

I2CxRCV是8位的只读寄存器,从总线接收的数据存于此寄存器供用户读取。无论是作主控器还是作从器件,在接收数据时,总线 SDA上的数据(0/1状态)移入一个不可访问的移位寄存器 I2CxRSR,见图 8-2。当I2CxRSR接收到一个完整字节时,模块就将该数据传送到 I2CxRCV寄存器,同时置状态寄存器的RBF位(I2CxSTAT<1>)为“1”。由此可见,I2CxRSR和 I2CxRCV构成一个双缓冲接收器,使得I2CxRCV中的数据在读取之前仍可接收数据。但需注意,如果在I2CxRCV寄存器中的数据读取之前,模块又接收到一个完整字节,则发生接收器溢出,I2COV位(I2CxSTAT<6>)置“1”。这时移位寄存器 I2CxRSR中的字节将丢失。

(3)发送寄存器I2CxTRN

I2CxTRN为8位寄存器,用于装载需发送的字节数据。当数据写入I2CxTRN寄存器时,发送缓冲器的状态位的TBF(I2CxSTAT<0>)置“1”,同时I2CxTRN寄存器逐位移出各位数据到总线的SDA。发送完成后,位TBF(I2CxSTAT<0>)自动清“0”。在发送当前数据时,可以重载 I2CxTRN寄存器,但一般不建议这样做,因为这将可能造成发送混乱。另外需注意,若总线未处于空闲状态,即SDA不是释放状态时,可能无法写入I2CxTRN寄存器。

(4)地址寄存器I2CxADD

I2CxADD为10位寄存器,用于存储从器件地址。在 7位寻址模式下,仅I2CxADD<6:0>有用。当工作在主模式(作主控器)时,该寄存器不起作用。

(5)波特率寄存器I2CxBRG

当作为 I 2C 主器件工作时,模块须产生总线的 SCLx 时钟。波特率发生器的重载

值来自于I2CxBRG 寄存器。I2CxBRG 是一个9位寄存器,其高7位总是为0。记SCLx 的时钟速率(波特率)为 F SCL ,N BGR 为寄存器I2CxBRG 中所赋的值,它们的关系为:表 8-6列出了在指令时钟频率为16MHz 、12MHz 和8MHz 时的常用时钟速率与I2CxBRG 取值的对应关系,可供用户设计时查阅。表8-3I 2C 时钟速率与指令时钟和2CxBRG 取值的关系

I2CxBRG 所需的

F SCL

F SCL

16 MHz

8 MHz 100 kHz 16 MHz

8 MHz

4 MHz

400 kHz

16 MHz

1 MHz 注意:I2CxBRG 寄存器的赋值需大于等于2。

8.4.I 2C 模块的中断

I 2Cx 模块可产生两种中断。一种中断由主模式(主控器)事件产生,中断入口为中断向量17(x=1)/50(x=2)或_MI2CxInterrupt ;另一种中断由从模式(从器件)事件产生,中断入口为中断向量16(x=1)/49(x=2)或_SI2CxInterrupt。

主模式中断标志位是MI2CxIF,主模式产生的事件使其置“1”;从模式中断标志位是SI2CxIF ,从模式产生的事件使其置“1”。

例如 PIC24FxxGA 系列芯片,模块1的主、从中断标志位分别为MI2C1IF ( IFS1<1>),SI2C1IF (IFS1<0>),模块2的主、从中断标志位分别为MI2C2IF ( IFS3<1>),SI2C2IF (IFS3<0>)如表 8-4所示。IFS1和IFS3是中断标志寄存器。

主模式在以下报文事件完成时产生中断(置主中断标志位):

●产生起始信号(启动):起始信号结束时置中断标志。

●产生停止信号:停止信号结束时置中断标志。

●发送一个字节:应答位接收(第9个SCL脉冲)完毕置中断标志。

●接收一个字节:接收缓冲器状态位RBF置“1”时置中断标志。

●发送应答:应答位(第9个SCL脉冲)发送完毕置中断标志。。

●重新启动:重新启动结束时置中断标志。

●检测到总线冲突事件置中断标志。

cy

cy SCL BRG BRG SCL F F F = N = 12(N +1)

2*F 或-,Fcy , Fcy =Fosc/2。

从模式在以下事件产生中断:

◆检测到有效的器件地址(包括全局呼叫地址)

◆请求数据发送

◆接收到一个字节数据

表 8-4 PIC24FxxGA系列芯片 I2C模块与中断相关的标志位

中断源

模块1主控事件(IFS1<1>)(IEC1<1>)(IPC4<6:4>)

模块1从动事件SI2C1IF(IFS1<0>)(IEC1<0>)(IPC4<2:0>)

模块2主控事件MI2C2IF(IFS3<2>)(IEC3<2>)(PC12<10:8>)

模块2从动事件SI2C2IF(IFS3<1>)(IEC3<1>)(IPC12<6:4>)

8.5.I2C模块的编程

若将控制寄存器I2CxCON中的位I2CEN置“1”,则使能I2Cx模块,引脚SDAx和 SCLx 由模块管理,与其对应的端口寄存器中的状态和方向寄存器中的设置均无关。在模块使能时,如果没有其他主控器在控制总线(多主系统时)、各从器件工作正常,则模块将获得对 SDAx和 SCLx引脚的控制,引脚SDAx和 SCLx处于释放状态。

从I2C总线协议看,PIC24芯片的I2C接口模块既可作为主控器(主模式),也可工作在从设备(从模式)方式。但I2C模块的控制寄存器中并没有一个主/从模式的设置位。实际上,一旦使能模块,则模块的主器件逻辑部件和从器件逻辑部件都同时在工作。至于是作主控器还是作从设备完全由用户对控制寄存器中相关控制位操作和对状态寄存器中的相关状态位

的响应按协议来编程而定。

8.5.1.在单主系统中作为主控器的编程

所谓单主系统是指挂接在I2C总线上的所有设备或器件只有一个主控器,其余均是从器件。这是嵌入式系统应用I2C总线的典型方式。例如嵌入式装置中通常接有I2C的EEPROM芯片作为非易失性存储器,用于保存设置参数或存储有关运行参数。这时PIC24的I2C

模块作为主控器对EEPROM芯片进行读、写数据操作。这种读、写从器件的通信又称为报文传输。

I2C模块作为主控器在报文传输过程中自动产生 SCLx时钟,并可产生I2C协议的各环节功能。但对具体报文协议的实现,需用户编程来操作I2C模块的相关寄存器或寄存器中的有关控制/状态位。下面以I2C模块1对芯片 24C02进行页内读、写N个字节为例,来说明编程步骤,设 24C02芯片的地址为cC02Addr(含R/W位,且R/W位=0),待读写的单元首地址(24C02中的)为 cMEMaddr。

注:24C02芯片的地址由其引脚的接法所定,请见24C02芯片的数据手册。

1.写芯片24C02的n个字节(不跨页,Page Write)

下面是编程的主要步骤,图8-6为其流程示意,例8-1中的xWrite( )为其代码。

(1)初始化:根据波特率设置好I2C1BRG寄存器,使能I2C模块,I2C1CON=0x8000

(位I2CEN=1);

(2)发送起始信号:I2C1CON bits.SEN=1;

(3)发送从器件地址(写:R/W=0):I2C1TRN =cC02Addr;

(4)等待从器件的应答:先等待发送状态位TRSTAT变“0”,然后检查应答状态位

ACKSTAT是否为“0”,若不为“0”,置出错标志,转(10)。

(5)发送存储器单元首地址:I2C1TRN =cMEMaddr;

(6)等待从器件的应答:同(4);

(7)发送数据字节:I2C1TRN =数据字节;

(8)等待从器件的应答:同(4);

(9)重复步骤(7)~(8),直到N个字节依次写入24C02芯片内;

(10)发送停止信号:I2C1CONbits.PEN = 1。

说明1:发送起始信号前应检查总线是否为“释放”状态,若寄存器I2C1CON<4:0>这5个位均是“0”,则总线是“释放”的。

说明2:另外需注意,I2C模块不允许事件排队。例如,在启动条件结束前,不允许写I2CxTRN寄存器来启动传输。在这种情况下,对I2CxTRN的写无效,且状态寄存器中的写冲突位IWCOL将被置“1”。

2.读芯片24C02的N个字节(不跨页,Sequential Read)

根据报文协议,启动后(发送起始信号“S”)先是写器件地址、存储单元单元地址,然后重新启动转入接收,每接收一个字节产生一次应答,但对接收的最后一个字节不应答,而是产生停止信号。下面是编程的主要步骤,图8-7为其流程示意,例8-1中的 xRead( )为其代码。

(1)初始化:根据波特率设置好I2C1BRG寄存器,使能I2C模块,I2C1CON=0x8000(位

I2CEN=1,ACKDT=0,应答期间发送ACK);

(2)发送起始信号:I2C1CON bits.SEN=1;

(3)发送从器件地址(写:R/W=0):I2C1TRN =cC02Addr;

(4)等待从器件的应答:先等待发送状态位TRSTAT变“0”,然后检查应答状态位

ACKSTAT是否为“0”,若不为“0”,置出错标志,转(10)。

(5)发送存储器单元地址:I2C1TRN =cMEMaddr;

(6)等待从器件的应答:同(4);

(7)重新启动:I2C1CON bits.RSEN=1;

(8)发送从器件地址(读:R/W=1):I2C1TRN =cC02Addr|0x01;

(9)使能接收:I2C1CONbits.RCEN = 1;

(10)接收数据:若2C1STATbits.RBF为“1”,则读取接收寄存器I2C1RCV中的数据,

反之等待;

(11)产生应答:若是最后一个字节置I2C1CONbits.ACKDT为“1”(NACK).产生应答

位:I2C1CONbits.ACKEN = 1。

(12)重复步骤(10)~(11),直到接收到N个字节;

(13)发送停止信号:I2C1CONbits.PEN = 1。

例8-1本例是用PIC24的I2C模块1的引脚(SCL1/RG2和SDA1/RG3)与芯片24C02接口,测试芯片24C02的Page Write和Sequential Read功能。先调用xWrite()将是常数字符串cTXdata[]的ASCII码写入芯片24C02中地址为0x30开始的单元中,然后调用xRead()将它们读回到数组RXdata[]中。注意,只能“页”内连续写数据,地址不能跨“页”,读也是一样,详见24C02芯片的技术手册。程序用查询法实现报文协议,未用I2C1模块的中断。设指令时钟为16MHz。

typedef unsigned char Uchar;

#define cC02Addr 0xA0 //芯片24C02的地址,设其引脚 A0、A1和A2均接地(逻辑”0”)。

#define cMEMaddr 0x30 //待写入24C02的存储单元首地址

const char cTXdata[]={"IICTest"}; //待写数据(ASCII码)

int main ( void )

{ char n,RXdata[sizeof(cTXdata)];

I2C1BRG = 79; //I2C1时钟速率为100kHz(16MHz指令)

I2C1CON = 0x8000; //使能IIC1模块

n=xWrite(cC02Addr,cMEMaddr, &cTXdata,sizeof(cTXdat a));

Delayus(5000); //延时5ms

n= xRead(cC02Addr,cMEMaddr, &RXdata,sizeof(cTXdata));

while (1) { ; } //循环

}

//写 24C02:ICaddr-IC地址, MEMaddr-单元地址, DataPtr-单元首址, Nbyte-字节数。char xWrite( Uchar ICaddr, Uchar MEMaddr, Uchar *DataPtr, Uch ar Nbyte)

{ char Flag; Uchar xAddr;

I2C1CONbits.SEN = 1; Delayus(2); //起动总线

while(I2C1CONbits.SEN); //等待启动结束

xAddr=ICaddr; Flag=WriteI2C1( &xAddr,1 );

if( Flag !=0 ) return Flag; //出错返回

xAddr=MEMaddr ; Flag=WriteI2C1(&xAddr ,1 );

if( Flag !=0 ) return Flag;

Flag=WriteI2C1( DataPtr,Nbyte );

I2C1CONbits.PEN = 1; //产生停止信号

while(I2C1CONbits.PEN); //等待停止信号结束

return 0;

}

//写24C02:指针data-待写数据的首地址,Nbyte-待写字节数.

//返回: 0-OK,-1-有总线冲突,-2-从器件无应答

char WriteI2C1(Uchar *data, Uchar NByte )

{ while(NByte!=0)

{ I2C1TRN = *data;

if(I2C1STATbits.IWCOL) return-1; //有写冲突返回-1

while(I2C1STATbits.TRSTAT); //等待发送状态位TRSTAT变“0”

NByte--; data++;

if (I2C1STATbits.ACKSTAT) return-2; //从器件无应答位返回-2

}

return 0;

}

//读24C02:ICaddr-芯片地址,MEMaddr-单元地址, DataPtr-存数据首址, Nbyte-字节数. char xRead( Uchar ICaddr,Uchar MEMaddr,Uchar *DataPtr,Uchar Nbyte)

{ char Flag; Uchar xAddr;

I2C1CONbits.SEN = 1; Delay us(10); //启动总线

while(I2C1CONbits.SEN); //等待启动结束

xAddr=ICaddr; Flag=WriteI2C1( &xAddr,1 );

if( Flag !=0 ) return 1;//出错返回

xAddr=MEMaddr; Flag=WriteI2C1( &xAddr,1 );

if( Flag !=0 ) return 2;

I2C1CONbits.RSEN = 1; //重启动总线

while(I2C1CONbits.RSEN); //等待重启动结束

xAddr=cC02Addr+1; //地址中的位R/W=1,发读指令 Flag=WriteI2C1(&xAddr,1 );

if( Flag !=0 ) return 3;

while(Nbyte!=0)

{ I2C1CONbits.RCEN = 1;//启动接收

while( !I2C1STATbits.RBF ) ; //等待接收缓冲器满

*DataPtr= I2C1RCV;

DataPtr++; Nbyte--;

if(Nbyte>0)

{ I2C1CONbits.ACKDT = 0;} //应答ACK=0

else

{I2C1CONbits.ACKDT = 1; } //应答NACK=1

I2C1CONbits.ACKEN = 1; //发送应答

while(I2C1CONbits.ACKEN ); //等待应答发送完

}

I2C1CONbits.PEN = 1; //产生STOP

while(I2C1CONbits.PEN ); //等待STOP结束

return 0;

}

下面是汇编文件ASM.S中的延时子程序:

.global _Delayus

_Delayus: ;延时子程序,供C调用.单位us

Delayus1:REPEAT #11

Nop ;1T(指令周期,1/16us)

SUB #1,W0 ;1T

BRA NZ,Delayus1 ;2T

RETURN

.end

例8-2用中断方式(I2C模块1)实现对24C02芯片进行Page Write和Sequential Read。在中断服务程序中,用变量RWflag的赋值0或1来指示“写”或“读”的流程,用变量 IICfun 的赋值来切换报文序列,从而实现报文协议,如表8-5所示。其余同上例。

表8-5中断服务程序中产生报文序列的流程控制

IICfun:

RWflag=0件地址元首址数据信号总线

:RWflag=1件地址元首址启动指令接收

=1:存储接收

,发送ACK;

RBF=0:启动接收

NACK信号总线

#define cC02Addr 0xA0 //芯片24C02的地址,设其引脚 A0、A1和A2均接地(逻辑”0”)。#define cMEMaddr 0x30 //待写入芯片24C02的单元首地址

const char cTXdata[]= {"testInt"}; //待写数据(ASCII码)

char ICaddr,MEMaddr,RWflag,IICfun,Index,xLen,TXd ata[8],RXdata[8];

int main ( void )

{ char n;

I2C1BRG = 79; //I2C1时钟速率为100kHz(16MHz指令)

I2C1CON = 0x8000; //使能IIC1模块

IFS1bits.MI2C1IF=0; IEC1bits.MI2C1IE=1; //允许主模式中断

SRbits.IPL = 3; IPC4bits.MI2C1P=4; // CP U优先级为3,主模式优先级为4 //----------写操作:将字符串cTXdata[]写入24C02----------

for(n=0;n

ICaddr=cC02Addr; MEMaddr=cMEMaddr; xLen=sizeof(cTXdata);

RWflag=0;Index=0; IICfun=0;

I2C1CONbits.SEN=1;//启动

while(IICfun<4){ ; } //等待n字节写完成

//-------读操作:将前面所写字符串读回到数组RXdata[]中-------

Delayus(5000); Index=0;

ICaddr=cC02Addr; MEMaddr=cMEMaddr; xLen=sizeof(cTXdata);

RWflag=1; IICfun=0;

I2C1CONbits.SEN=1; //启动

while(IICfun<8){; } //等待n字节读完成

while (1) { ; } //循环

}

//======== IIC1主模式中断 ===========

void __attribute__((__interrupt__,no_auto_psv)) _MI2C1Interrupt(void)

{ IFS1bits.MI2C1IF=0;

if(I2C1STATbits.BCL ) //总线冲突

{I2C1STATbits.BCL=0; IICfun=0x80; return;}

if(I2C1STATbits.IWCOL ) //写冲突

{I2C1STATbits.IWCOL=0; IICfun=0x81; return;}

if(RWflag==0) //写操作(Page Write)

{ if(IICfun==0)

{ I2C1TRN =ICaddr; IICfun++; } //发送从器件地址

else if(IICfun==1)

{if (I2C1STATbits.ACKSTAT)

{IICfun=0x82; return;} //从器件无应答,返回

I2C1TRN =MEMaddr; IICfun++; }

else if(IICfun==2)

{if (I2C1STATbits.ACKSTAT)

{IICfun=0x82; return;} //从器件无应答,返回

if(Index

else

{ IICfun=3; I2C1CONbits.PEN=1; } //产生停止信号

}

else IICfun=4;

}

else //读操作(Sequential Read)

{ if(IICfun==0)

{if (I2C1STATbits.ACKSTAT)

{IICfun=0x82; return;} //从器件无应答,返回

I2C1TRN=ICaddr; IICfun++; } //发送从器件地址

else if(IICfun==1)

{ if (I2C1STATbits.ACKSTAT)

{IICfun=0x82; return;} //从器件无应答,返回

I2C1TRN=MEMaddr; IICfun++; } //发送存储单元首址

else if(IICfun==2)

{ I2C1CONbits.RSEN=1;IICfun++;} //重启动总线

else if(IICfun==3)

{ I2C1TRN=ICaddr+1; IICfun++;} //发送读寻址

else if(IICfun==4)

{ I2C1CONbits.RCEN=1;IICfun=5; Delayus(10); } //启动接收;

else if(IICfun==5)

{ if(I2C1STATbits.RBF )

{ RXdata[Index++]=I2C1RCV ; //存储接收的数据

if(Index>=xLen )

{ IICfun=6;I2C1CONbits.ACKDT=1; } //应答NACK

else I2C1CONbits.ACKDT=0;

I2C1CONbits.ACKEN=1; //发送应答

}

else

I2C1CONbits.RCEN=1; //继续接收;

}

else if(IICfun==6)

{ IICfun=7;I2C1CONbits.PEN=1; } //产生停止信号

else IICfun=8;

}

}

上面2个例程的main()中未对出错情况处理,实际应用程序应对出错情况编写相关代码,作出相应的响应。

8.5.2.在多主系统中作为主控器的编程

I2C协议允许在总线上连接多个主控器,每个主控器均可启动报文事务和产生总线时钟。但在每一时刻只能有一个主控器在工作,因此协议应有对多个主器件试图控制总线的仲裁规则,使得只有一个符合规则的主控器保留总线控制权,其余的主控器则退出总线控制。控制总线的仲裁规则主要由总线时钟同步和总线冲突监测构成。从表8-2的控制寄存器I2CxCON各位定义可知,PIC24系列芯片的I2C模块没有相应的设置位来使能多主机操作,但模块具有时钟同步和总线冲突监测的仲裁功能,这是基于接口电路的如下特点:

●SDAx、SCLx为漏极开路结构,借助于外部的上拉电阻实现信号的“线与”逻辑;

●引脚在输出信号的同时还对引脚上的电平进行检测,检测是否与输出一致。这为“时

钟同步”和“总线仲裁”提供了硬件基础。

1.主控器时钟同步

在多主机系统中,各主控器的时钟是独立的,它们的时间参考点和波特率可能不尽相同。总线时钟同步可确保多个主控器能同步它们的 SCL时钟,并在总线的 SCL上形成公共的时钟,以便实现总线仲裁。

前叙所知,I2C总线上所有器件的SDA、SCL引脚均为漏极开路结构,其高电平是由其释放SDA、SCL引脚后被外接电阻上拉到V DD所获。这种结构使总线上所有节点的SDA、SCL 信号实现“线与”逻辑关系。另外,作为总线上主控器的波特率发生器还有一个重要特点:当一个主控器的时钟由低电平转高电平时,若出现由于“线与”的关系被其它时钟信号拉成低电平,则该主控器的波特率发生器处在等待状态,直到时钟SCL线变成“高”时才产生时钟脉冲的的正半周(高电平,半个时钟周期)。

设一个I2C总线系统中有两个主控器,其时钟信号分别为SCK1、SCK2,它们都具有控制总线的能力。当两者都产生时钟信号欲控制总线进行通信时,由于“线与”的作用,实际的

SCL的波形如图 8-8所示。从图可见,速度快的主控器 1等待落后的主控器 2,在总线的 SCL上形成公共的时钟,即实现了时钟信号的同步。

图8-8 SCL时钟信号的同步

当然,PIC24芯片的I2C模块波特率发生器也具有时钟信号同步功能。在 SCLx引脚被释放时(SCLx由“0”欲变“1”时),波特率发生器(BRG计数器)将暂停计数,直到实际采样到 SCLx引脚为高电平为止。当采到SCLx引脚变为高电平时,BRG计数器重载波特率寄存器I2CxBRG的值并开始计数。这可以保证即使有外部器件将时钟拉低时,SCLx始终保持一个计数周期的高电平脉冲。显然,这种时钟信号同步特性实际上是利用SCL线的“线与”逻辑协调不同器件之间的速度问题,同时为总线仲裁奠定了基础。

2.总线仲裁和总线冲突

对于I2C总线系统的多主机(主控器)结构,总线上的主控器之间没有优先级,没有中心主机的特权。当多个主机竞争总线时,基于时钟同步、SDA信号的“线与”逻辑和“输出一致”检测,各主控器自动判别是否发生总线冲突,实现“总线仲裁”功能。由“总线仲裁”机制确保系统中任何一个主控器都可以掌握总线的控制权。

当主控器甲发送数据“1”(释放其SDA引脚),但主控器乙发送数据“0”时,由于SDA信号的“线与”作用使得SDA信号实际为“0”。输出的不一致使主控器甲产生总线冲突,在总线仲裁中失败,从而放弃总线的控制权。而主控器乙在总线仲裁中获胜,仍掌握总线的控制权,可继续发送数据。

PIC24的I2Cx模块具有总线仲裁功能。若模块期望输出在 SDAx引脚上的数据是“1”,但实际采样到 SDAx引脚上的数据却是“0”,则将总线冲突状态位 BCL(I2CxSTAT<10>)置“1”,并产生主模式中断,同时模块将SDAx和SCLx复位为空闲状态。

可能产生总线冲突的发送操作有:起始信号、重新启动、发送地址、发送数据或应答位和产生停止信号。

PIC24的I2Cx模块作为主控器工作时始终执行时钟同步和总线仲裁。在单主机系统中,若从器件的工作速度比主控器慢,则从器件可以用拉低时钟脉冲的方法来使得主控器时钟同步。但这种情况很少见到,因为现在的器件一般都可达到常规的通信速率。尽管总线仲裁主要是用于多主系统,但单主机系统在非正常工作情况也可能发生总线冲突,例如干扰信号,或者从器件发生故障并影响到SDA引脚时。这些问题在实际编程中都应该考虑。

根据以上的分析和说明,“时钟同步”与“总线仲裁”可简单归纳如下:

(1)主控器通过检测SCL上的电平来调节与从器件或多主控器之间的速度同步问题——时钟同步;

(2)主控器通过检测SDA线上与自身发送的电平的一致性来判断是否发生总线冲突——总线仲裁。因此,I2C总线的“时钟同步”与“总线仲裁”是靠器件本身接口

的特殊结构得以实现的。

(3)各个主控器没有对总线实施控制的优先权,他们遵循“低电平优先”的原则,即谁先发送低电平谁就会掌握对总线的控制权。

3.多主系统的主控器编程

只要I2Cx模块检测到总线冲突,则中断当前的操作,SDAx和 SCLx引脚复位成空闲状态,同时总线冲突状态位 BCL(I2CxSTAT<10>)置“1”、主模式中断标志位MI2CxIF置“1”、发送缓冲器的状态位TBF(I2CxSTAT<0>)清零。如果在启动、重新启动、停止和应答期间发生总线冲突,则I2CxCON寄存器中的相应控制位清零。

总的来说,多主系统中主控器编程步骤和单主系统的基本相同。只是由于可能发生总线竞争,因此用户程序中应在报文发送过程中检测总线冲突位BCL的状态。在传输一个报文帧时,软件需检查 BCL位来确定主控器所发起的事件是成功完成(BCL=0)还是发生了冲突(BCL=1)被中止。如果发生冲突,软件必须中止当前报文的操作,并且当前报文帧的已作操作无效,需在总线返回到空闲状态时从起始信号开始重新发送整个报文帧。

用户程序可以通过监视启动位S(I2CxSTAT<3>)和停止位P(I2CxSTAT<4>)的状态来等待总线空闲。若S位为“1”,说明总线上有其它主控器控制着总线;若P位为“1”则表明总线当前为空闲状态(复位时,S位和P位均为“0”,总线为空闲状态),这时可重新开始发送报文帧。当然,重新开始发送报文帧仍需对主控器发起的每个事件进行判断,看是否发送总线冲突。

8.5.3.作为从器件通信

1.从器件通信的基本过程

在处理某些比较复杂的实时事务系统中,可以采用多MCU结构,它们可以通过I2C总线相连交换信息。这时,可用一个PIC24芯片作为主控器,其余的PIC24芯片作为从器件工作。

I2Cx模块作为从器件工作时,它不能主动启动报文传输,只能被动地响应由主控器发送的报文序列,并且只有与主控器寻址相匹配的从器件可以响应报文序列。总线SCL的时钟脉冲始终是由主控器产生,即使从器件发送数据时也是如此。

使能I2Cx模块后,模块的从器件逻辑部件(以后简称为从模块)进入工作状态,等待主控器产生启动条件。在时钟(SCLx)线的上升沿采样SDAx线上所有的输入位。I2Cx模块为从器件的工作过程如下(主要讨论 7位器件地址方式(A10M位(I2CxCON<10>)=0):

(1)当检测到主控器产生启动条件时,启动状态位S(I2CxSTAT<3>)置“1”,从模块进入下面的地址匹配环节。

(2)地址匹配:当接收到一个字节X时,从模块检查X<7:1>是否与地址寄存器I2CxADD<6:0>匹配。

◆如果X<7:1>与 I2CxADD<6:0>的内容不匹配,从模块将返回到空闲状态并忽

略此后所有的总线事件,直到检测到停止条件(停止状态位P(I2CxSTAT<4>)

为“1”)为止。

◆若X<7:1>与 I2CxADD<6:0>的内容匹配,则从模块产生应答信号 ACK,同时

将X<0>送状态寄存器中的R/W位(I2CxSTAT<2>)、状态寄存器中的D/A位

(I2CxSTAT<5>)清“0”,从模式中断标志位SI2CxIF置“1”,模块产生从模

式中断。R/W位指定了其后的数据传输方向。

(3)R/W位(I2CxSTAT<2>)=0:主控器是写操作,从模块等待主器件发送数据。

◆在主控器的时钟作用下,从模块将SDAx引脚上的数据(0/1状态)移入到不

可访问的移位寄存器 I2CxRSR。当I2CxRSR接收到一个完整字节时,将该数

据传送到 I2CxRCV寄存器,同时置状态寄存器的RBF位(I2CxSTAT<1>)为

“1”、D/A位置“1”,从模式中断标志位SI2CxIF置“1”(产生从模式中

断)。

◆模块自动产生应答信号 ACK或 NACK。然后等待下一个数据字节。

(4)R/W 位(I2CxSTAT<2>)=1:主控器是读操作,从模块需向主器件发送数据。此时,

主器件等候从器件发送数据字节。

◆用户程序将待发送的数据送寄存器I2CxTRN。当数据写入I2CxTRN 寄存器时,

发送缓冲器的状态位的TBF(I2CxSTAT<0>)置“1”,同时在主控器的时钟作

用下启动发送。

发送完成后(经8个SCLx 时钟脉冲), TBF 位自动清“0”。从模块在第 9个

SCLx 时钟的上升沿检测来自主器件的应答。如果 SDAx 线为低电平(ACK),

模块产生从模式中断(标志位SI2CxIF 置“1”),表明报文尚未完成,需继

续发送。若SDAx 线为高电平(NACK),则表明数据传输已完成。此时不会

产生中断。从模块返回空闲状态,直到检测到下一个启动位。(5)若从模块检测到停止信号,则置停止状态位P (I2CxSTAT<4>)为“1”、启动状

态位S(I2CxSTAT<3>)清“0”,模块返回空闲状态。

图8-9所示为写从器件(7位地址模式)时的地址检测时序,图8-10为读从器件(7位地址模式)时的地址检测工作时序。

2.有关从模块工作过程的几点说明

(1)发送哪些数据和接收到的数据如何处理,即应用系统的报文协议,完全由用户自

检测到起使能接收地址R/W =1主器为读操作,从

块发送应答A

从模式中断标

位SI2CxIF

“1,从模块

低时钟线

⑤,用户

(2)正常情况下,从模块接收一个字节后在第 9个 SCLx时钟发送应答信号 ACK。但如果发生接收缓冲器溢出(溢出位 I2COV(I2CxSTAT<6>)为“1”),则从模块不会产生ACK。用户程序应尽可能使用模块的从模式中断,及时读取I2CxRCV中的接收数据,避免发生接收缓冲器溢出问题。

(3)若模块在处理接收时的速度慢于主控器,可令SCLx时钟延长使能位STREN (I2CxCON<6>)为“1”,启用总线时钟同步功能。若STREN=1,则在接收一个字节的第9个时钟下沿,时钟的释放控制位SCLREL(I2CxCON<12>)自动清零,使 SCLx线下拉成低电平,从而在 I2C总线上产生等待周期。当软件准备好继续接收时只要将SCLREL位置“1”,则模快释放SCLx线,使得主控器结束等待,恢复时钟信号。

(4)向主控器发送时,从模块将自动产生总线等待。模块检测到相匹配地址或发送数据的第 9个 SCLx时钟的下降沿,时钟的释放控制位SCLREL(I2CxCON<12>)自动清零,使得SCLx线下拉成低电平,从而在 I2C总线上产生等待周期(即总线时钟同步)。用户程序将数据写入I2CxTRN寄存器后应将SCLREL位置“1”,使模块释放SCLx线,从而主器件恢复时钟信号。

(5)从器件地址屏蔽

对于地址屏蔽寄存器中I2CxMSK为“1”的那些地址位从模块不作匹配检查。例如,设I2CxADD=0b0010110(7位地址模式),I2CxMSK=0b0011100,则地址0b00XYZ10与I2CxADD匹配。这里X、Y、Z的值可以为“0”或“1”。

要使能地址屏蔽,必须清零 IPMIEN位(I2CxCON<11>)禁止 IPMI(智能外设管理接口)。

(6)全局呼叫

全局呼叫操作是主控器以一个特定的全局地址向总线上所有的从器件发送数据,也称为广播方式发送。I2C协议保留地址0b0000000为全局地址(10位地址模式时,全局地址也是7位),且读/写位 R/W = 0。

将全局呼叫使能位 GCEN(I2CxCON<7>)置“1”,使能从模块响应全局呼叫地址。从模块在检测到主控器产生的启动条件后,对接收的常规地址和全局地址均进行地址匹配检查。若是全局地址产生地址匹配,则将全局呼叫状态位GCSTAT(I2CxSTAT<9>)置“1”,其余的操作与常规从器件寻址的地址匹配处理相同。

用户程序可以通过GCSTAT位的状态,来确定是响应自身的器件地址匹配还是响应全局呼叫地址匹配。

(7)10位寻址模式

在 10位寻址模式下(10位从器件地址位AM10(I2CxCON<10>)=1),从器件必须接收两个字节的器件地址。第一个字节X1应为“11110 A9 A8 0”,其中X1<7:3>=0b11110为10位寻址的标识,X1<2:1>为器件地址的A9、A8位,X<0>位(R/W位)必须是写操作“0”,第二个字节X2<7:0>为器件地址的低8位(A7~A0)。

检测到启动条件后,当有 8位数据移入 I2CxRSR寄存器时,模块将I2CxRSR<7:3>位与“11110”进行比较,同时将I2CxRSR<2:1>与地址寄存器的I2CxADD<9:8>比较(仅比较未屏蔽的位)。如果两者均匹配,则产生应答信号ACK,同时D/A和 R/W位清零、在第 9个SCLx时钟的下降沿置中断标志SI2CxIF为“1”。

I2CxRSR接收到第二字节X2时,若I2CxRSR<7:0>与I2CxADD<7:0>匹配,则模块将状态位ADD10置“1”、产生应答信号 ACK、在第 9个 SCLx时钟的下降沿置中断标志SI2CxIF 为“1”,之后等待主器件发送数据或重新启动。

若报文为主控器的读操作,主器件需要发送重新启动条件并重复发送地址的第一字节X1,这时R/W位(即X1<0>)应为读操作“1”。检测到重复启动后,从模块只匹配第一个地址字节X1<7:1>的 7位地址“11110 A9 A8”。

在 10位寻址模式下I2CxMSK 寄存器可以屏蔽 10位地址中的任一位。

8.6.I 2C 总线的电气规范

I 2C 总线上的器件为“线与”连接,总线上需要接有公共的上拉电阻Rp,如图8-11所示。器件中串连电阻Rs 是可选的,用于提高 ESD(静电保护)性能,不过在实际应用中很少有接Rs 的。图中的CB 是总线等效电容,例如连接线的对地分布电容、各器件输入端的电容。

电阻 Rp 和 Rs 的取值与电源电压、总线电容、所连器件数量和逻辑电平值等参数有关。在芯片引脚输出低电平时,流过Rp 的电流应小于I/O 端口的允许电流。例如,设电源电压V DD 为3V ,且可上浮10%,I/O 端口的允许电流为6.6mA,并忽略低电平的电压值,由此可算得Rp 的最小值为:Rpmin=3.3V/6.6mA=500Ω 。

I 2C 总线对最小上升时间t R (即时钟和数据位的上沿)有规定。400 kHz 系统的t R 为 300ns,100 kHz 系统t R 为 1000 ns。

当器件由低电平释放总线时,需在t R 时间内将总线电压拉高到逻辑“1”的高电平(0.7V DD )。最小上升时间t R 与Rp 、总线等效电容C B 和器件的输入阻抗有关。记Rp 的最大取值为Rpmax,忽略低电平的电压值和假设器件的输入阻抗很大,由电工原理可得下式:

Rpmax =-t R /(C B *ln(0.7))=2.8*t R /C B

例如,设总线等效电容C B 为100pF ,t R 为 300 ns(400 kHz 系统)。带入上式可算的Ppmax=8.4k Ω 。

Rs 的最大值由低电平时能容忍的噪声容限决定。取值原则是 Rs 上的电压降加上芯片输出低电平电压V oL 之和应该小于总线V iL (逻辑“0”电压)的最大允许值。即

I 2Cx 模块的SCLx 和SDAx 引脚具有输入毛刺滤波器。100 kHz 和400 kHz 速率的I 2C 总线系统上的器件都要求有此滤波器。

在速率为400 kHz 系统中, I 2

C 规范要求对器件引脚输出能进行边沿斜率控制。PIC24

系列芯片的I 2Cx 模块具有边沿斜率控制功能。如果将控制寄存器中的边沿斜率控制位

DISSLW(I2CxCON<9>)清“0”,则使能边沿斜率控制功能。对于其他较低的总线速度, I 2C

规范不要求边沿斜率控制,可将DISSLW 位置“1”。

I 2C 总线的逻辑电平输入值也有一定的规定。在常规的 I 2C 总线系统中,低电平的最高电压值V IL (max)为0.3V DD ,高电平的最小电压值V IH (min)为0.7V DD 。m a x m a x m a x ()*D D O L P i L S i L S P S D D O L i L V

V R V R V R R R V V V -<<+--,→

8-11 I 2C 总线示意连接图

在 SMBus(系统管理总线)系统中,逻辑电平为固定值。低电平V IL(max)为0.8V,高电平V IH(min)为2.1V。

控制寄存器中SMEN位(I2CxCON<8>)控制输入电平。若将 SMEN置“1”,则输入电平为SMBus规范。

8.7.在 CPU休眠和空闲模式下的I2C模块工作情况

当CPU执行 PWRSAV#0(C30中为 Sleep();)时,芯片进入休眠状态。这时,系统时钟冻结,I2C模块和其它外设模块一样立即停止工作,模块复位。当CPU被唤醒退出休眠时,模块将处于空闲状态。

无论是作主控器还是从器件,I2C模块在休眠期间均不监视I2C总线。因此不能指望I2C总线的事件产生主模式和从模式中断,也就是说I2C模块在休眠期间不能唤醒CPU。

当CPU执行PWRSA V#1(C30中为Idle();)指令时,芯片进入空闲待机低功耗模式。这时,模块将根据I2CSIDL位(I2CxCON<13>)的设置值决定是否进入低功耗模式。如果I2CSIDL = 1,则模块进入低功耗模式,立即停止工作,模块复位,相当于进入休眠模式。如果I2CSIDL = 0,则模块不进入低功耗模式,将继续正常工作。

若不使用I2Cx模块,并且希望I2Cx模块处于最低功耗时,可将外设模块禁止寄存器(PMD)中的相应控制位置“1”。这时I2Cx模块的时钟源被禁止,I2Cx模块的的控制和状态寄存器也被禁止,读写这些寄存器的操作都无效,模块处于最低功耗状态。例如PIC24FJxxGA006

芯片,I2C1模块的外设模块禁止位是I2C1MD(PMD1<7>)或C30中已定义的 PMD1bits.I2C1MD;I2C2模块的外设模块禁止位是I2C2MD(PMD3<1>)或C30中的 PMD3bits.I2C2MD.

文本预览
相关文档 最新文档