I2C,又叫IIC。标准写法应当是I2C,读作“I方C”。
两根线、双向传输数据、一对多传输数据、速度不快、通用性很强。
适用场景:各种传感器、小IC、小MCU等。控制指令和小数据量的传输
说到两根线的数据传输方式,大家可能会对串口(UART)最熟悉,TX、RX两根线即可传输数据,常用的跑到115200bps的速度毫无问题。
那么为什么还需要I2C这样的同样是两根线的传输方式呢?
I2C能够1对多,UART只能1对1。因此I2C又叫I2C总线。
I2C接口能够用软件模拟来扩充接口,UART则不行。
I2C接口带有同步时钟,对时钟稳定性要求远没有UART那么高。
由此可见,I2C存在的最大原因在于简单且灵活性高。
例如一个主控要接5个外设,但是通常的主控都不可能有5个UART口。如果用UART就需要硬件扩展。
但是用I2C的话,只需要1组I2C接口即可。即使没有硬件I2C接口,也可以有软件模拟I2C的源代码可以调用。(I2C源码网上随便就可以搜到很多)。嵌入式开发初学者都可以在一周之内自己独立写一套出来。
I2C使用范例
单独输出传输
这个没什么好讲的,硬件连好了,软件配置好了,数据就可以顺利传输了。
这种连接方式,仅限于CPU需要控制外设,而外设永远不会自己主动发数据给CPU的情况。如果外设需要主动要求发数据个CPU,需要采用下面一种方式。
带中断的数据传输
为什么要加中断?
I2C只能由CPU(主机)去找外设(从机)索取数据,外设不能主动发送数据给CPU。
但是CPU不能定期去问外设“你有没有数据要发给我?”,这样耗CPU的计算资源,也耗电,且无法进入睡眠状态。
因此需要外设有办法通知CPU,“我有数据要发了”。I2C配合的中断信号就是这个作用。外设有数据要发了,先发个中断给CPU,CPU再来通过I2C读取外设想要发过来的数据。
对于低功耗应用的场景、能够触发的外设场景,都需要这么来设计。例如电容触摸屏,平时CPU是休眠的,点击一下就唤醒系统。再例如G-Sensor运动传感器,一旦被晃动了就唤醒CPU。
一个控制多个设备:
如何一对多?
一根I2C总线上挂载多个设备,那么岂不是CPU发个什么数据,所有的外设都可以看得到?
是的,就这样子的。只不过CPU先会发一个地址,所有的外设都会收到这个地址。这个地址就好比外设的名字。叫了你了,你就答应,没叫你就别答应。
地址总共能有127个,不同的I2C接口的外设的地址通常是不会重复的。
对于如果我需要在一根I2C总线上挂载多个相同的外设呢?例如上面的一组I2C控制几个灯控IC。这种情况下,IC厂家通常都会未卜先知,知道大家可能会一口气用好几个,在IC上预留地址脚,通过不同的拉高和拉低的状态,把设备的I2C的地址配置成不同的值。
通过地址选择脚,选择不同的I2C地址
I2C协议简单介绍
讲了,这么多,硬件工程师们知道什么是I2C以及怎么使用了,但是还是不能愉快的和软件工程师交流,因为还不知道传输的详情。
I2C时序图
具体的I2C工作时序,记住这么几条就可以理解了:
只能由主机(Master)发起数据传输请求,从机(Slave)只能被动响应。
通常MCU是主机,外围设备是从机。
主机和从机都不说话的时候,两根线都是高电平。(被外部上拉电阻拉高的)
主机先发送地址(Address),I2C上挂载的所有的设备都会收到这个地址,只有这个地址和自己的地址一致,才会响应(ACK)。
主机发送地址的时候顺带还会说本次操作是读还是写(RW)。从机收到这个读写信号,如果是读,从机就准备好要被读取的数据等着主机来读,如果是写,从机就做好接收数据的准备。
从机响应了,主机才会继续发数据。如果没有人响应,要么是从设备都挂了,要么是地址不对,总之就是有问题。
如果上面的都ok了,接下来就是按部就班的传输数据了。