第23课 两根数据线实现无限连接 初识 I2C

我是潘,曾经是个工程师。这是为 Ardui.Co 制作的 “Arduino 公开课” 系列的入门教程。本课开始将介绍 I2C 通信协议,利用该协议 Arduino 将获得极大的扩展,我们将深入了解 I2C 各类应用和细节。有任何疑问请在评论区提出,我会逐一回答。

Arduino UNO 扩展接口并不多,但它有一项必杀技:I2C(全称“Inter-Integrated Circuit”,也叫
“IIC” )。这个通信协议已经存在了将近40年,由飞利浦半导体(现在的 NXP)所定义。它将连接数百个设备或传感器的复杂电路,简化为2根数据线(SDA —— 数据 和 SCL —— 时序)。我们可以看看 NXP 的官方介绍:

I2C 的优势

现在已有成千上万使用 I2C 协议的设备或传感器,通过 Arduino 开发板都能控制它们。常见的如。外部精密时钟(DS1307)、数字电位器、温度计、指南针、FM收音模块、外部存储、I/O扩展,液晶显示屏、数字放大器等等。只需一条总线(即两条数据线)就可以连接所有的设备,上限是112个。

Arduino UNO 的I2C端口是 A4(SDA)、A5(SCL):

如果你使用的是 Mega2560,那么SDA 和 SCL 分别是 20、21,其他开发板请参考官方DataSheet。如果使用 DIY系统 则 SDA、SCL 分别为27脚和28脚。I2C 总线接线方式很简单:

如果只连接一个 I2C 设备,那么上拉电阻就不是必须的。如果连接多个设备,那么要接两个 10KΩ 上拉电阻,但也有些设备会要求 4.7KΩ 上拉电阻。没关系,按要求连接即可。I2C 总线可以达到 1 米左右,但要注意导线寄生电容对数据传输的影响。另外,使用 NXP P82B715 等IC,可以将总线长度延长至20米以上,这个以后我们会讲到。

I2C 设备分 master 和 slave 两类定义,Arduino 开发板一般就是 master,总线连接的设备和传感器是 slaves 。问题出现了,总线上设备那么多,读写数据时怎样才能区分它们?我们想对A设备写入数据,但如何保证不会写进了B设备?

实际上,每个 I2C 设备都有一个唯一的地址。利用地址信息就可以区分它们。

首先,I2C 需要使用库 wire.h,同时要用到方法 Wire.begin(),要把它放到 void setup() 中。然后,向I2C设备发送数据必须具备两个元素,设备的唯一地址(16进制)和至少一个字节的数据。

地址会向 SDA 线发送,提醒对应的设备,数据来了:

根据地址找到设备后,向其发送数据。这期间,这个设备会张开手臂迎接数据的到来,而其他设备则会无视,因此一次只能操作一个I2C设备。

此语句表示本次通信结束。否则,无法进行下一个设备的数据传输。

我们需要从设备接受数据,同时也知道了有多少数据将会反馈回来。比如,要求某个设备一次性反馈3个寄存器的信息,每个信息需要一个变量来存储:

这告诉设备,向 Arduino 反馈3个寄存器的信息,后面立刻跟上3个指针变量:

获得设备的数据反馈后,将指针变量 *a、*b、*c 视作普通变量使用即可。实际上,用普通变量接受数据也没有问题,但一些操作中,使用指针变量会带来意想不到的好处,比如利用 sizeof(指针变量类型) 的方法,跳转到前后一个字节。

更多 I2C 的细节可以参考 NXP 的官方文档

现在利用上面的知识,通过 I2C 控制 MCP4725 (12bits DAC )模块的电压输出。其实,MCP4725是一个能将参考电压分成 4096 份(12bits)的精密电压 IC。在 Arduino 上,可以输出0~5V之间的电压,每级电压为 5/4096V :

在 Arduino UNO 上,模块 SDA 接 A4,SCL 接 A5,VCC 是参考电压,接5V或3.3V都可以,输出范围分别为 0~5V 和 0~3.3V,GND 接 GND。

学习操作一个模块时,首先要做的事情是查阅其 DataSheet,MCP4725 的在这里。第19页有一个表格(FIGURE 6-2: Write Commands for DAC Input Register and EEPROM.)很重要:

表格告诉我们,操作这个模块要给出4个字节:
1st byte 是地址;
2nd byte 为操作字节。前三位C2=0、C1=1、C0=0 时,只对 DAC 操作,如果C0=1,还会对EEPROM写入。
3rd byte 是 12bits DAC 的前8bits;
4th byte 前4位为 DAC 总数据的后4位,最后4位没有定义。

现在写一个程序,输出 0~ 3.3V 任意一个电压值,精度位 3.3/4096 V:

此时测量MCP4725 上的 OUT 和 GND 之间的电压:

Vout =  VCC * val/4095 = 3.3V * 3000/4095 ≈ 2.418V。

不过,由于仪器的测量误差和 LDO 的输出精度,VCC不一定等于3.3V,此时,先测量一下VCC,再做运算。实际测得 VCC = 3.274V,因此 Vout = 3.274V * 3000/4095 = 2.398V

Arduino 是没有内置 DAC 的,但 DAC 的用途很广,比如结合第13课的旋转编码器,就能制作一个连续可以调的数字电源;也可以利用各种数学函数,输出任意波形的信号。

Leave a Reply

Your email address will not be published. Required fields are marked *