串口是传感器、外设常用的接口,在低速器件中可以通过串口传输数据。高速复杂的器件,往往内部存在很多寄存器,这些寄存器的配置一般也是采用串口通信,可以节省IO口。
常用串口大致分为UART、IIC、SPI三种,其中IIC时序稍微复杂,却是最好用的串行接口。如下图所示,主机通过两根数据线,就可以与多个外设通信。
主机想要通过UART与N个外设双向通信,一般需要2*N个IO口。主机想要通过SPI与N个外设双向通信,一般需要使用N+3个IO口。而如果使用IIC接口,那么只需要2个IO口。
因此IIC对于节省IO有较大优势,劣势在于UART可以全双工通信,SPI的时钟线与数据线分开,传输速度最快,且UART和SPI的驱动设计一般比较简单。而IIC由于只靠两根线驱动多个传感器,所以需要确认主机与哪个传感器建立连接(传输器件地址),然后在对器件内部寄存器进行读写,导致通信速度不可能很高。
1、I2C硬件接口
IIC主机或者从机的硬件接口如下图所示,使用一个开漏/开集(如果是MOS管则漏极开路,如果是三极管则集电极开路)开路,在同一条线上有一个输入缓冲区,允许数据线用于双向传输数据。
三角形代表输入缓冲器,准确的说该接口只能通过FET输出低电平,高电平依靠外部上拉电阻完成。
下图是该接口输出低电平的信号示意图,当需要输出低电平时,FET导通,VBUS下拉与GND连接,此时总线呈现低电平,如图中红色部分。
当从机或主机希望发送逻辑高电平时,只能通过关闭下拉场效应管来释放总线。使得总线浮动,上拉电阻将把电压拉到电压轨,表现为高电平。
2、I2C通信
IIC总线是一个标准的双向接口,除非从机已被主机寻址,否则从机不能传输数据。IIC总线上的每个设备都有一个特定的设备地址,以区分同一IIC总线上的其他设备。 许多从设备在启动时需要配置来设置设备的行为,通常是在主机访问从机的内部寄存器时完成。
物理IIC接口由串行时钟(SCL)和串行数据(SDA)线组成,SDA和SCL线路都必须通过上拉电阻连接到VCC。 只有当总线空闲时才可以开始数据传输,如果SDA和SCL线在停止条件后都为高电平,则总线空闲。
先总体看下经典的IIC读、写器件寄存器时序,然后在具体分析起始位、停止位、应答、传输数据的SCL和SDA波形。
下图是主机通过IIC写从机寄存器数据的步骤,首先主机向从机发送起始位,然后发送7位从机器件地址,之后会发送一位读写操作信号,从机应答主机(ACK为低电平)后,向从机发送寄存器地址(这个寄存器地址为8位,但是有的器件可能会有16位或者24位寄存器地址,就需要发送三次这种时序)。等待从机应答之后,主机把需要写入寄存器的数据输出,等待从机应答后,主机发送停止条件,结束本次通信。注意不管是器件地址还是寄存器地址,亦或者是数据,都是先传输高位数据。
上图中灰色方块表示主机发送数据,白色表示从机发送数据。
下图是主机通过IIC读取从机寄存器数据的步骤,主机依次向从机发送起始位、器件地址、寄存器地址,等待从机应答之后,在次向从机发送起始信号,然后发送器件地址,此时读写位位高电平,表示读出数据,然后从机就会把该器件该寄存器地址的数据依次输出,数据接收完成后,主机向从机发送不应答指令(如果发送应答指令,则从机会把下个寄存器地址的数据继续输出到总线上,实现连续读取寄存器数据),然后发送停止位,完成寄存器数据的读取。
上图中灰色方块表示主机发送数据,白色表示从机发送数据。
在了解了读写寄存器的步骤后,在来查看IIC的一些细节时序,由于主机和从机都会在时钟SCL的高电平采集SDA的状态,因此在传输数据时,SDA在SCL的低电平的时候更新数据,在SCL高电平阶段尽量保持不变。
只有两种情况,SDA会在SCL的高电平期间电平发生变化,即起始位和停止位,时序图如下所示:
起始位:SCL为高电平,SDA从高电平变为低电平表示起始位(因为空闲时SDA是高电平,SDA变为低电平代表开始传输数据)。
停止位:SCL为高电平时,SDA从低电平变为高电平表示停止位。
重复起始条件(图6中红色字体的时序):时序与起始条件一样,用于代替连续的停止然后开始条件。当总线未空闲时,主机希望启动新的通信,但不希望发送停止信号释放总线,就可以直接发送重复起始条件,开启信号通信。 因为停止条件有可能使主机失去对总线的控制(在多主机环境中)。
如图8所示,在SCL的每个时钟脉冲期间传输一个数据位,每次传输8位数据后需要从机应。8位数据可以是设备地址、寄存器地址,也可以是写入或读取从机的数据。
数据首先传输最高有效位(MSB)。在START和STOP条件之间,可以将任意字节的数据从主机传输到从机。在传输数据过程中SDA必须在SCL低电平时更新状态,在SCL为高电平时SDA线上的数据必须保持稳定,因为当SCL高时,SDA的变化被解释为控制命令(START或STOP)。
每个字节(包括地址字节)后面都有一个来自接收方的ACK位,ACK位允许接收方与发送方通信,表明该字节已成功接收,并且可以发送下一个字节数据。
在接收方发送ACK之前,发送方必须释放SDA线。 如下图9所示,为了发送ACK位,接收方需要在ACK/NACK相关时钟周期(周期9)的低电平期间拉低SDA线,使SDA线在ACK/ NACK相关时钟周期的高相位稳定在低电平。设置和保持时间必须考虑在内。
当SDA在与ACK/NACK相关的时钟周期内保持高位时,则不应答(NACK)。 有几个条件会导致NACK的产生:
1. 从机无法接收或发送,因为它正在执行一些实时功能,还没有准备好开始与主机通信。
2. 在传输过程中,接收方接收到它不理解的数据或命令。
3. 在传输过程中,接收方不能再接收任何数据字节。
4. 主机读取从机寄存器数据后,通过NACK表示终止从机寄存器数据的读取。
3、总结
IIC接口是开漏/开集输出的硬件接口,只能主动输出低电平。当需要输出高电平时,会释放总线(对外表现高阻态),被外部上拉电阻上拉到VCC,从而实现高电平,所以上拉电阻必须存在。
SDA在传输数据时只能在SCL的低电平期间变化,如果SCL为高电平,SDA从高电平变为低电平,则表示起始位或者重复起始位,SDA从低电平变为高电平则便是停止位。
每当传输一字节数据后,接收方需要产生一个应答位(ACK低电平表示应答),之后发送方才能传输下一字节数据。
在起始位和停止位之间,可以传输任意字节数据,数据可以是器件地址、寄存器地址、写入或读取从机的数据。
上述的总结来自于TI的IIC总线手册,需要该手册的可以在公众号后台回复“IIC手册”(不包括引号)。