I2C为了解决多设备共用总线,同时不烧毁芯片,GPIO口采用了开漏输出的方式,配合上拉电阻就可以完整的输出高低电平,这个上拉电阻的取值一般在几千欧姆,总线设备多且通信速率要求高的话电阻就小一些,反之电阻就可以大一些。也正是因为采用了开漏输出加上拉电阻的模式,所以I2C信号的抗干扰能力是比较弱的,只适合板上的芯片之间进行通信,并不适合超过40cm电路板之间的通信,下面详细介绍一下I2C硬件方面的问题:

I2C总线主要解决一对多通信的问题,通过构建一条信息通道只需要两个IO端口,两条线就可以把电路板上的所有芯片串联起来,利用这个信息通道相互传输数据,比起UART通信方式大大节约了芯片的IO口资源,同时也降低了PCB的布线成本,不过像汽车在公路上行驶需要遵守交通规则一样,既然所有的设备共用一条总线,那么就需要遵守一些通信规则,而这些通信规则也就让很多的人觉得学习I2C通信的时候会有点吃力。

I2C两天线分别是时钟和数据线,其中时钟是用来同步信号的,发送端在时钟的高电平发出数据,接收端会在时钟的高电平去取数据,那么问题就来了,某一时刻如果有两个设备同时要发送数据,要怎么办,比如说一个设备发送一个高电平,另一个设备发送低电平,最终会发生什么呢?数据线上是高电平?还是低电平?

这其实也是I2C总线硬件设计中最精髓的地方,为了彻底搞清楚这个问题,我们先要弄明白芯片是如何输出高低电平的,在芯片IO口的内部一般会有两颗MOS管,上面的MOS管导通就输出高电平,下面的MOS管导通就输出低电平,这个时候我们把两个IO口都挂在一根总线上,如果一个芯片输出高电平,一个芯片输出低电平,那么电流就之间从高电平流向低电平到地,这条通路其实就是短路了,后果就是必定会有一个元器件烧毁,

那么为了避免这种情况的发生,所以I2C总线对于设备的IO口做了阉割,去掉了上面的MOS管,这样就不可能存在短路的情况了

不过这样就带来另一个问题,设备只能输出低电平,无法输出高电平,那解决的办法就是在总线上加入一颗电阻,称为上拉电阻

加入这个电阻之后,这根总线默认就处于高电平的状态,这颗芯片想输出低电平,把MOS管打开,把总线信号拉低,想要输出高电平只需要关闭MOS管,总线就被上拉电阻拉到高电平了,其实这就是典型的GPIO开漏输出。

回到之前的问题,两颗芯片同时发送信号怎么办?假设都要输出高电平,等于说两个MOS管都关闭,总线默认处于高电平状态,这没有任何的问题,两个芯片都要输出低电平时,等于说两个MOS管都打开,那么总线处于低电平状态也没有问题,一个输出高电平,一个输出低电平,总线处于低电平状态,虽然输出高电平的芯片不能输出高电平,但是任何芯片不会损坏,整个电路是安全的,至于解决输出高电平芯片的问题,那就是软件协议要思考的问题

对于上拉电阻取值是一个比较重要的问题,电阻不能太大,也不能太小,一般是几千欧姆,比较常用的是4.7K、10K,如果电阻太小,比如说50欧姆,那么在总线低电平时,这条通路的电流比较大,可能烧毁芯片,导通的MOS管不完全为0欧姆,这样下拉的MOS无法把电平拉到低电平状态,如果电阻取值太大会出现什么问题呢!GPIO口总会有一些寄生电容,从低电平往高电平转换的过程中,需要通过这颗电阻给这些电容充电

所有I2C通信时,信号沿会有一个爬坡的过程,电阻越大,爬坡沿越缓,严重的话信号就会失真,所有电阻的选择要合适,稳妥的话可以用示波器测量一下信号,看一下波形