- 什么是I2C通信协议?
- I2C通信如何工作?
- 在哪里使用I2C通讯?
- Arduino中的I2C
- 所需组件
- 电路原理图
- 工作说明
- Arduino中的I2C编程
- Arduino高级编程说明
- 从Arduino编程说明
在我们之前的教程中,了解了Arduino中的SPI通信。今天,我们将学习另一种串行通信协议:I2C(内部集成电路)。将I2C与SPI进行比较,I2C只有两条线,而SPI使用4条线,而I2C可以具有多个主控和从属,而SPI只能具有一个主控和多个从属。因此,在一个项目中需要一个以上的微控制器作为主机,然后使用I2C。I2C通信通常用于与陀螺仪,加速度计,气压传感器,LED显示器等进行通信。
在本Arduino I2C教程中,我们将使用两个arduino板之间的I2C通信,并通过电位计相互发送(0到127)值。值将显示在连接到每个Arduino的16x2 LCD上。在这里,一个Arduino将充当Master,另一个将充当Slave。因此,让我们从有关I2C通信的介绍开始。
什么是I2C通信协议?
IIC一词代表“内部集成电路”。在某些地方,它通常表示为I2C或I平方C或什至表示为2线接口协议(TWI),但它们的含义相同。I2C是同步通信协议,这意味着共享信息的两个设备必须共享一个公共时钟信号。它只有两根导线可以共享信息,其中一根用于塞子信号,另一根用于发送和接收数据。
I2C通信如何工作?
I2C通信最初是由Phillips引入的。如前所述,它有两条线,这两条线将跨两个设备连接。在这里,一个设备称为 主机 ,另一设备称为 从机。通讯应该并且将始终在两个 主机和一个从机之间进行。I2C通信的优势在于,一个主设备可以连接多个从设备。
完整的通信通过这两条线进行,即串行时钟(SCL)和串行数据(SDA)。
串行时钟(SCL): 与从机共享主机产生的时钟信号
串行数据(SDA): 在主机和从机之间发送数据。
在任何给定时间,只有主站才可以发起通信。由于总线中有多个从站,因此主站必须使用不同的地址引用每个从站。当被寻址时,只有具有该特定地址的从站将回复信息,而其他从站则退出。这样,我们可以使用同一条总线与多个设备进行通信。
I2C的电压电平未预定义。I2C通信非常灵活,这意味着由5v电压供电的设备可以将5v用于I2C,而3.3v设备可以将3v用于I2C通信。但是,如果两个运行在不同电压下的设备需要使用I2C通信怎么办?甲5V I2C总线不能与3.3V装置连接。在这种情况下,电压转换器用于匹配两个I2C总线之间的电压电平。
有一些构成交易的条件。传输的初始化从SDA的下降沿开始,这在下图中定义为“ START”条件,在该图中,主机将SCL设置为高电平时将SCL保持为高电平。
如下图所示,
SDA的下降沿是START条件的硬件触发。此后,同一总线上的所有设备都进入监听模式。
以相同的方式,SDA的上升沿停止传输,如上图所示,状态为“ STOP”,主机将SCL置于高电平,同时释放SDA变为高电平。因此,SDA的上升沿停止了传输。
R / W位指示后续字节的传输方向,如果为高电平,则表示从机将发送;如果为低电平,则表示主机将进行发送。
每个位在每个时钟周期发送一次,因此发送一个字节需要8个时钟周期。在发送或接收每个字节之后,将为ACK / NACK(已确认/未确认)保留第9个时钟周期。ACK位由从机或主机根据情况产生。对于ACK位,主机或从机在第9个时钟周期将SDA设置为低电平。因此,它被认为是ACK否则为NACK较低。
在哪里使用I2C通讯?
I2C通信仅用于 短距离通信。它一定程度上是可靠的,因为它具有同步时钟脉冲以使其变得智能。该协议主要用于与必须向主机发送信息的传感器或其他设备进行通信。当微控制器必须使用最少的电线与许多其他从模块通信时,这非常方便。如果您要进行远程通信,则应尝试RS232;如果要寻找更可靠的通信,则应尝试SPI协议。
Arduino中的I2C
下图显示了Arduino UNO中存在的I2C引脚。
I2C线 | 固定在Arduino中 |
SDA | A4 |
SCL | A5 |
在我们开始使用两个Arduino进行I2C编程之前。我们需要了解Arduino IDE中使用的Wire库。
该库
1. Wire.begin(地址):
使用: 该库用于与I2C设备进行通信。这将启动Wire库,并以主机或从机的身份加入I2C总线。
地址:7位从站地址是可选的,如果未指定该地址,它将像这样作为主站加入总线。
2. Wire.read():
使用:此函数用于读取从主设备或从设备接收的字节,该字节是在调用 requestFrom() 之后从从设备传输到主设备,或者从主设备传输到从设备 。
3. Wire.write():
使用:此功能用于将数据写入从设备或主设备。
从机到主机:当在主机中使用 Wire.RequestFrom() 时,从机将数据写入主机。
主机到从机:对于从主到从设备传输 Wire.write() 是在两者之间用于呼叫 Wire.beginTransmission() 和 Wire.endTransmission()。
Wire.write()可以写为:
- Wire.write(值)
value:作为单个字节发送的值。
- Wire.write(string):
string:以一系列字节发送的字符串。
- Wire.write(数据,长度):
数据:以字节为单位发送的数据数组
length:要传输的字节数。
4. Wire.beginTransmission(地址):
使用:此功能用于使用给定的从机地址开始向I2C设备的传输。随后,使用 write() 函数构建要传输的字节队列, 然后通过调用 endTransmission() 函数来传输它们 。传输设备的7位地址。
5. Wire.endTransmission();
使用:该函数用于结束到从设备的传输,该从设备由 beginTransmission() 开始, 并传输由 Wire.write() 排队的字节 。
6. Wire.onRequest();
使用:当主机从属设备使用 Wire.requestFrom() 请求数据时,将调用此函数。在这里,我们可以包含 Wire.write() 函数以将数据发送到主机。
7. Wire.onReceive();使用:当从属设备从主设备接收数据时,将调用此函数。这里我们可以包含 Wire.read(); 功能读取主机发送的数据。
8. Wire.requestFrom(address,quantity);
使用:该功能在主机中用于向从机请求字节。函数 Wire.read() 用于读取从属设备发送的数据。
地址:从中请求字节的设备的7位地址
数量:请求的字节数
所需组件
- Arduino Uno(2-否)
- 16X2 LCD显示模块
- 10K电位器(4-Nos)
- 面包板
- 连接线
电路原理图
工作说明
为了演示Arduino中的I2C通信,我们使用两个彼此连接的Arduino UNO和两个16X2 LCD显示屏,并在两个arduino上使用两个电位计来确定从主机到从机以及从机到主机的发送值(0至127)。电位器。
我们使用电位计在arduino引脚A0上从(0至5V)获取输入模拟值,并将其转换为模拟至数字值(0至1023)。然后,这些ADC值将进一步转换为(0至127),因为我们只能通过I2C通信发送7位数据。I2C通信通过两个arduino的A4和A5引脚上的两条线进行。
从属Arduino LCD上的值将通过更改主端上的POT来更改,反之亦然。
Arduino中的I2C编程
本教程有两个程序,一个用于主Arduino,另一个用于从Arduino。双方的完整计划均在该项目的最后给出了演示视频。
Arduino高级编程说明
1.首先,我们需要包括使用I2C通信功能的Wire库和使用LCD功能的LCD库。同时为16x2 LCD定义LCD引脚。在此处了解有关将LCD与Arduino接口的更多信息。
#包括
2.在无效的setup()中
- 我们以9600波特率开始串行通信。
Serial.begin(9600);
- 接下来,我们在引脚(A4,A5)上开始I2C通信
Wire.begin(); //从引脚(A4,A5)开始I2C通信
- 接下来,我们将LCD显示模块初始化为16X2模式,并显示欢迎消息,并在五秒钟后清除。
lcd.begin(16,2); //初始化LCD显示屏 lcd.setCursor(0,0); //在Display lcd.print(“ Circuit Digest”)的 第一行设置光标 //在LCD lcd.setCursor(0,1);中 打印电路摘要 //在Display lcd.print(“ I2C 2 ARDUINO”)的 第二行设置光标 //以LCD延迟(5000) 打印I2C ARDUINO ; //延迟5秒钟lcd.clear(); //清除LCD显示
3.在void loop()中
- 首先,我们需要从从站获取数据,因此我们使用带有从站地址8的 requestFrom() 并请求一个字节
Wire.requestFrom(8,1);
使用Wire.read()读取接收到的值
字节MasterReceive = Wire.read();
- 接下来,我们需要从连接到引脚A0的主arduino POT中读取模拟值
int potvalue = AnalogRead (A0);
我们将该值以1字节的形式转换为0到127。
字节MasterSend = map(potvalue,0,1023,0,127);
- 接下来,我们需要发送这些转换后的值,因此我们开始使用8地址的从属arduino进行传输
Wire.beginTransmission(8); Wire.write(MasterSend); Wire.endTransmission();
- 接下来,我们以500微秒的延迟显示从从arduino接收到的那些值,然后连续接收并显示这些值。
lcd.setCursor(0,0); //在LCD lcd.print(“ >> Master <<”)的 第一行设置Currsor //在LCD lcd.setCursor(0,1); 打印>> Master << //在LCD lcd.print(“ SlaveVal:”)的第二 行设置光标 //打印SlaveVal:在LCD lcd.print(MasterReceive)中; //从从 设备 接收到的LCD中打印MasterReceive Serial.println(“从从设备接收到的Master”); //在串行监视器中打印Serial.println(MasterReceive); 延迟(500); lcd.clear();
从Arduino编程说明
1.与主机一样,首先我们需要包括用于使用I2C通信功能的Wire库和用于使用LCD功能的LCD库。同时为16x2 LCD定义LCD引脚。
#包括
2.在无效的setup()中
- 我们以9600波特率开始串行通信。
Serial.begin(9600);
- 接下来,我们在从机地址为8的引脚(A4,A5)上开始I2C通信。在这里,重要的是指定从机地址。
Wire.begin(8);
接下来,当从站从主站接收值并且从站从主站请求值时,我们需要调用该函数
Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent);
- 接下来,我们将LCD显示模块初始化为16X2模式,并显示欢迎消息,并在五秒钟后清除。
lcd.begin(16,2); //初始化LCD显示屏 lcd.setCursor(0,0); //在Display lcd.print(“ Circuit Digest”)的 第一行设置光标 //在LCD lcd.setCursor(0,1);中 打印电路摘要 //在Display lcd.print(“ I2C 2 ARDUINO”)的 第二行设置光标 //以LCD延迟(5000) 打印I2C ARDUINO ; //延迟5秒钟lcd.clear(); //清除LCD显示
3.接下来,我们有两个功能,一个用于请求事件,一个用于接收事件。
要求事件
当从机发出主机请求值时,将执行此功能。此功能的确从从机POT取得输入值并将其转换为7位,然后将该值发送给主机。
void requestEvent() { int potvalue = AnalogRead(A0); 字节SlaveSend = map(potvalue,0,1023,0,127); Wire.write(SlaveSend); }
对于接收事件
当主站使用从站地址(8)向从站发送数据时,将执行此功能。该函数从master读取接收的值,并将其存储在 byte 类型的变量中。
void receiveEvent(int howMany { SlaveReceived = Wire.read(); }
4.在Void loop()中:
我们在LCD显示模块中连续显示来自主站的接收值。
无效循环(无效) { lcd.setCursor(0,0); //在LCD lcd.print(“ >> Slave <<”);的 第一行设置Currsor //在LCD lcd.setCursor(0,1); 打印>> Slave << //在LCD lcd.print(“ MasterVal:”)的第二 行设置光标 //在LCD lcd.print(SlaveReceived)中 打印MasterVal://在从主机Serial.println(“从 主机接收到从站:”)接收的LCD中打印从站接收到的值。//在串行监视器中打印Serial.println(SlaveReceived); 延迟(500); lcd.clear(); }
通过旋转电位器的一侧,您可以在另一侧的LCD上看到变化的值:
这就是Arduino中I2C通信的方式,这里我们使用了两个Arduino来演示不仅通过I2C通信发送数据,而且还接收数据。因此,现在您可以将任何I2C传感器连接到Arduino。
下面是一个演示视频,给出了主从Arduino的完整编码