I2C总线简介
I2C是两线式串行总线,用于连接微控制器及其外围设备。
I2C总线最主要的优点是其简单性和有效性。由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。I2C总线的另一个优点是,它支持多主控(multimastering), 其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。
单片机的通讯模块常用的有UART、SPI、I2C、CAN等等,当然还有无线模块这里不讨论。UART大多用于单片机与PC的通信,CAN总线常用于单片机与单片机通信,而SPI和I2C则用于单片机和外围设备、外围设备和其它外围设备的通信,根据自己的需要来设计通讯方式。
相比较SPI而言,I2C需要更少的接线,仅由数据线SDA和时钟SCL构成 。而SPI则需要四根引线,它们是SDI(数据输入),SDO(数据输出),SCLK(时钟),CS(片选)。但是常常因为I2C的通讯协议较为复杂,不容易在程序中实现而导致数据丢失、无应答、“死等”等问题。
I2C通信、读写数据过程
在通信之初,主从机必须根据自己的要求约定好通信规则:command的定义和位置、address的位数和位置。
以读写从机寄存器数据为例:
假设从机寄存器地址为8位、从机寄存器也位8位(被读取数据为8位);
约定读command为0x01,写command位0x02;
约定主机发起通信后,第一个slave address字节收到ack后,紧跟的一个字节为command,再下面一个字节为address。
1. 读寄存器数据步骤:
1.1 主机先发起一次通信,将读command(0x01)和需要读取的寄存器地址address写入从机;(主机发出写操作)
1.2 从机firmware的处理:
1.2.1 将command和address分别提取出来;
1.2.2 判断command的含义(本例中,是读指令还是写指令);
1.2.3 根据收到的的address,将对应寄存器的的数据放入从机I2C输出buffer;(这个步骤可以使用指针)
1.3 主机再次发起一次通信,读取从机的数据;(主机发出读操作)
2. 写操作步骤:
2.1 主机发起通信,按约定依次写入command、要写入的从机寄存器地址address和要写入的数据data;
2.2 从机firmware要做的处理:
2.2.1 分别提取command、address和data;
2.2.2 根据command做出判断(本例中则判断是写入还是读取);
2.2.3 将data写入与接收到的address对应的寄存器。(这个步骤可以使用指针)。
4、主机发送数据流程
(1)主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始
(2)主机接着发送一个命令字节。该字节由 7 位的外围器件地址和 1 位读写控制位 R/W组成(此时 R/W=0)
(3)相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK=0)
(4)主机收到从机的应答信号后开始发送第一个字节的数据
(5)从机收到数据后返回一个应答信号 ACK
(6)主机收到应答信号后再发送下一个数据字节
(7)当主机发送最后一个数据字节并收到从机的 ACK 后,通过向从机发送一个停止信号P结束本次通信并释放总线。从机收到P信号后也退出与主机之间的通信
注意:①主机通过发送地址码与对应的从机建立了通信关系,而挂接在总线上的其它从机虽然同时也收到了地址码,但因为与其自身的地址不相符合,因此提前退出与主机的通信;②主机的一次发送通信,其发送的数据数量不受限制。主机是通过 P 信号通知发送的结束,从机收到 P 信号后退出本次通信;③主机的每一次发送后都是通过从机的 ACK 信号了解从机的接收状况,如果应答错误则重发。
5、主机接收数据流程
(1)主机发送启动信号后,接着发送命令字节(其中 R/W=1)
(2)对应的从机收到地址字节后,返回一个应答信号并向主机发送数据
(3)主机收到数据后向从机反馈一个应答信号
(4)从机收到应答信号后再向主机发送下一个数据
(5)当主机完成接收数据后,向从机发送一个“非应答信号(ACK=1)”,从机收到ASK=1 的非应答信号后便停止发送
(6)主机发送非应答信号后,再发送一个停止信号,释放总线结束通信
注意:主机所接收数据的数量是由主机自身决定,当发送“非应答信号/A”时从机便结束传送并释放总线(非应答信号的两个作用:前一个数据接收成功,停止从机的再次发送)。
6、总线死锁原因分析
I2C总线写操作过程中,主机在产生启动信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平,在这个时候,从机输出应答信号,将SDA信号拉为低电平。如果这个时候主机异常复位,SCL就会被释放为高电平。此时,如果从机没有复位,就会继续I2C的应答,将SDA一直拉为低电平,直到SCL变为低电平,才会结束应答信号。而对于主机来说,复位后检测SCL和SDA信号,如果发现SDA信号为低电平,则会认为I2C总线被占用,会一直等待SCL和SDA信号变为高电平。这样,主机等待从机释放SDA信号,而同时从机又在等待主机将SCL信号拉低以释放应答信号,两者相互等待,I2C总线进人一种死锁状态。同样,当I2C进行读操作时,从机应答后输出数据,如果在这个时刻主机异常复位而此时从机输出的数据位正好为0,也会导致I2C总线进入死锁状态。
解决方案通常有如下几种:
(1)将从机的电源设计为可控,当发生总线死锁的时将从机复位
(2)可以在从机的程序中加入监测功能,如果总线长时间被拉低则释放对总线的控制
(3)在主机中增加I2C总线恢复程序。每次主机复位后,如果检测到SDA被拉低,则控制SCL产生《=9个时钟脉冲(针对8位数据的情况),每发送一个时钟脉冲就检测SDA是否被释放,如果SDA已经被释放就再模拟产生一个停止信号,这样从机就可以完成被挂起的读写操作,从死锁状态中恢复过来。这种方法有一定的局限性,因为大部分主机的I2C模块由内置的硬件电路来实现,软件并不能够直接控制SCL信号模拟产生需要时钟脉冲。
挂在I2C总线上的EEPROM设备
EEPROM称为电擦除式只读存储器,一般容量很小、用于保存产品的固化参数,此次跟我狭路相逢的是一款来自ATMEL公司的AT24C512B,总容量为64K,支持以页的方式写入数据,页大小128字节,以下是这款设备的相关信息和操作方法(其他型号类同):
硬件连接。在AT24C512B硬件连接中,跟软件编程相关的引脚有三个,除了连接在I2C总线上的时钟线(SCL)、数据线(SDA)引脚之外,还有一个写保护引脚(WP)连接在GPIO上。
寻址方式。EEPROM可以让你精确地访问到每一字节,AT24C512B采用16位的寻址方式共计可以访问65536字节的地址空间。
读写时序。AT24C512B支持的写操作有单字节写入、按页写入,支持的读操作有随机单字节或连接读取、当前位置单字节或连续读取,EEPROM一般在电路中做从设备,我此次面对的也是,以下是主设备对EEPROM进行各种操作的操作方法:
单字节写入:START -》 发送从设备地址(写控制码) -》 处理Ack -》 发送字节地址 -》 处理Ack [-》 发送1字节数据 -》 处理Ack] -》 STOP。
按页写入:将单字节写入的[ ]中的操作重复进行128次即可实现。
随机单字节读取:START -》 发送从设备地址(写控制码) -》 处理Ack -》 发送字节地址 -》 处理Ack -》 START -》 发送器件地址(读控制码) -》 处理Ack -》 接收1字节数据 -》 STOP。
随机连续读取:在随机单字节读取操作的STOP信号发送之前,加入若干个 [-》 发送Ack -》 接收1字节数据] 即可实现。
当前位置单字节读取:START -》 发送从设备地址(读控制码) -》 处理Ack -》 发送字节地址 -》 处理Ack -》 接收1字节数据 -》 STOP。当前指的是之前进行过读取操作但是没有发送STOP信号,EEPROM芯片内部指针所在的位置即为当前位置。
当前位置连续读取:在当前位置单节读取操作的STOP信号发送之前,加入若干个 [-》 发送Ack -》 接收1字节数据] 即可实现。
关于EEPROM的按页写入。为提高数据写入效率,有的EEPROM设备用一个内部的RAM来提供按页写入的功能,进行写操作的时候,先记录下要写入的首地址,然后将接收到的数据都缓存在RAM中,在接收到STOP信号时再把缓存数据一次性保存到先前记录的地址处。
有两个需要注意的问题:(a)、如果写入的数据超过一页的长度,将发生回卷,即从RAM的0地址处进行数据覆盖。(b)、如果页大小为128字节,即0-127字节为第一页、128-255为第二页,即页的边界位置是绝对的,而不是从写入数据的起始位置开始计算。
在进行数据读取操作没有页的问题,可以从任意位置开始读取任意大小的数据,超过EEPROM总容量时发生回卷。
评论
查看更多