IIC(Inter-Integrated Circuit,IC之间总线)总线,即集成电路总线,是由飞利浦(Philips)半导体公司开发简单、两线式、同步串行总线,用于连接微控制器及其外围设备,是微电子通信控制领域广泛采用的一种总线标准。IIC总线是一个多向控制总线,多个器件(从机)可以同时挂载到一个主机控制的一条总线上,每个连接在总线上的设备都是通过唯一的地址和其他器件通信。与串口的一对一通信方式不同,总线通信通常有主机(Master)和从机(Slave)之分。通信时,主机负责启动和终止数据传送,同时还要输出时钟信号;从机会被主机寻址,并且响应主机的通信请求。
主机就是负责整个系统的任务协调与分配,从机一般是通过接收主机的指令从而完成某些特定的任务,主机和从机之间通过总线连接,进行数据通讯。
串口通信双方需要事先约定同样的波特率才能正常进行通信。而在IIC通信中,通信速率的控制由主机完成,主机会通过SCL引脚输出时钟信号供总线上的所有从机使用。 同时,IIC是一种半双工通信方式,即总线上的设备通过SDA引脚传输通信数据,数据的发送和接收由主机控制,切换进行。
IIC上的所有通信都是由主机发起的,总线上的设备都应该有各自的地址。主机可以通过这些地址向总线上的任一设备发起连接,从机响应请求并建立连接后,便可进行数据传输。IIC总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输。
软件IIC:软件IIC通信指的是用单片机的两个I/O端口模拟出来的IIC,用软件控制管脚状态以模拟IIC通信波形,软件模拟寄存器的工作方式。
硬件IIC:一块硬件电路,硬件IIC对应芯片上的IIC外设,有相应IIC驱动电路,其所使用的IIC管脚也是专用的,硬件(固件)IIC是直接调用内部寄存器进行配置。
硬件IIC的效率要远高于软件的,而软件IIC由于不受管脚限制,接口比较灵活。
物理拓扑结构
IIC总线是由数据线SDA和时钟线SCL以及GND构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbs以上。
时钟线SCL:在通信过程起到控制作用。
数据线SDA:用来一位一位的传送数据。
通信原理是通过对SCL和SDA线高低电平时序的控制,来产生IIC总线协议所需要的信号,从而进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。
想了解IIC协议、总线操作,请阅读:Arduino IIC协议、IIC(inter-integrated circuit)通信协议时序。
对于IIC总线的使用,Arduino IDE自带了一个第三方类库Wire。在Wire类库中定义了如下成员函数。
(1)begin()
begin()
begin(address) // 当没有填写参数时,设备会以主机模式加人IIC总线;当填写了参数时,设备会以从机模式加入IIC总线,address可以设置为0~127中的任意地址。
(2)requestFrom( )
requestFrom()
后,从机端可以使用 onRequest()
注册一个事件用以响应主机的请求;主机可以通过available()
和 read()
函数读取这些数据。Wire.requestFrom(address, quantity)
Wire.requestFrom(address, quantity, stop)
(3)beginTransmission()
write()
函数发送数据,并搭配endTransmission()函数结束数据传输。wire.beginTransmission(address)
(4) endTransmission( )
Wire.endTransmission()
Wire.endTransmission(stop)
(5)write()
Wire.write(value)
Wire.write(string)
Wire.write(data, length)
(6)available( )
Wire. available()
(7)read( )
requestFrom()
函数发送数据请求信号后,需要使用 read()
函数来获取数据;在从机中需要使用该函数读取主机发送来的数据。Wire.read()
(8)onReceive( )
Wire.onReceive(handler)
void myHandler(int numBytes)
。(9) onRequest()
Wire.onRequest(handler)
voidmyHandler()
。如图2所示,在Arduino UNO上,可以通过将A4、A5和Arduino MEGA 2560的SCL、SDA接口一一对应连接来建立IIC连接。如果有更多的IIC设备,也可以将它们连人总线中来。
将两个Arduino分别配置为主机和从机,主机向从机传输数据,从机接收到数据再输出到串口显示。主从机两端的IIC程序实现流程图如图3所示。
1、主机写入
// 直接在Arduino IDE选择“文件”→“示例”→Wire→master_writer可以打开该文件
#include
void setup() {
Wire.begin(); // Wire初始化,作为主机加入到IIC总线
}
byte x = 0; // 定义一个byte变量以便串口调试
void loop() {
Wire.beginTransmission(8); // 向地址为8的从机传送数据
Wire.write("x is "); // 发送5B的字符串
Wire.write(x); // 发送1B的数据
Wire.endTransmission(); // 结束传送
x++;
delay(500);
}
2、从机接收
// 直接在Arduino IDE选择“文件”→“示例”→Wire→slave_receiver,可以打开该文件
#include
void setup() {
Wire.begin(8); // Wire初始化, 并以从设备地址8的身份加入IIc总线
Wire.onReceive(receiveEvent); // 注册一个IIC事件,用于响应主机的数据发送
Serial.begin(9600); // 初始化串口并设置波特率为9600
}
void loop() {
delay(100);
}
// 当主机发送的数据被收到时,将触发 receiveEvent() 事件
void receiveEvent(int howMany) {
// 循环读取收到的数据,最后一个数据单独读取
while (1 < Wire.available()) {
char c = Wire.read(); // 以字符形式接收数据
Serial.print(c); // 串口输出该字符串
}
int x = Wire.read(); // 以整型形式接收数据
Serial.println(x); // 串口输出该整型变量
}
3、效果演示
主、从机两端的IIC程序实现流程图如图5所示。
1、主机读取
// 直接在Arduino IDE选择“文件”→“示例”→Wire→master_reader,可以打开该文件
#include
void setup() {
Wire.begin(); // Wire初始化,作为主机加入到IIC总线
Serial.begin(9600); // 初始化串口并设置波特率为9600
}
void loop() {
Wire.requestFrom(8, 6); // 向8号机请求6B的数据
// 等待从机发送数据
while (Wire.available()) {
char c = Wire.read(); // 以字符形式接受并读取从机发来的一个字节的数据
Serial.print(c); // 串口输出该字符
}
Serial.println(); // 换行
delay(500);
}
2、从机发送
// 直接在Arduino IDE选择“文件”→“示例”→Wire→slave_sender,可以打开该文件
#include
void setup() {
Wire.begin(8); // Wire初始化, 并以从设备地址#8的身份加入i2c总线
Wire.onRequest(requestEvent); // 注册一个IIC事件,用于响应主机的数据请求
}
void loop() {
delay(100);
}
//每当主机请求数据时,该函数便会执行
//在setup()中,该函数被注册为一个事件
void requestEvent() {
Wire.write("hello "); // 用6B的信息回应主机的请求,hello后带一个空格
}
3、效果演示
补充
小结
对比项 | UART | SPI | I2C |
信号线数目 | 3根,RX、TX、GND | 4根,SDO、SDI、SCLK、SS | 2根,SDA、SCLK |
设备从属关系 | —— | 存在主从设备。SPI用片选信号选择从机 | 存在主从设备。IIC用地址选择从机。 |
通信方式 | 全双工通信 | 全双工通信 | 半双工通信 |
通信速率 | 速度慢 | 比I2C总线要快,速度可达到几Mbps | I2C的速度比SPI慢 |
应用领域 | 1、UART常用于控制计算机与串行设备的芯片 2、就是我们经常所说的串口,基本都用于调试。 |
主要应用在EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间 | I2C一般是用在同一个板子上的2个IC之间的通信 ,它可以替代标准的并行总线,连接各种集成电路和功能模块。 |
传输距离 | I2C需要有双向IO的支持,而且使用上拉电阻,抗干扰能力较弱,一般用于同一板卡上芯片之间的通信,较少用于远距离通信 | ||
通信特征 | 异步,一帧可以传5/6/7/8位 | 同步,SPI允许数据一位一位的传送,甚至允许暂停。从最高位开始传。 | 同步,电平信号,一次连续8bit。从最高位开始传 |
协议复杂度 | 结构比较复杂 | SPI实现要比UART简单,UART需要固定的波特率,就是说两位数据的间隔要相等,而SPI则无所谓,因为它是有时钟的协议。 | 协议比SPI复杂,但是连线比标准的SPI要少 |
对比 | 在点对点的通信中,SPI接口不需要进行寻址操作,且为全双工通信,显得简单高效。 在多个从器件的系统中,每个从器件需要独立的使能信号,硬件上比I2C系统要稍微复杂一些。 |