Arduino中进行I2C通信发送数据案例分析
时间:2023-10-13 16:07:02
在之前的文章中,我们介绍了它Arduino之间的SPI通信。今日我们将学习另一种串行通信协议:I2C(内部集成电路)。比较I2C和SPI,I2C而且,只有两条线SPI使用四条,I2C可以有多个主机和从机,SPI只有一个主机和多个从机。因此,如果项目中需要使用多个微控制器作为主机,则应使用它I2C。I2C通信通常用于陀螺仪、加速度计、气压传感器LED通信显示器等。
本文将使用I2C总线在两个arduino在开发板之间进行通信,并使用电位计相互发送值(0-127)。这些值将显示连接到每个值Arduino1602液晶显示屏。在文章中,一个Arduino以开发板为主机,以另一个开发板为从机。现在让我们谈谈I2C开始介绍通信。
什么是I2C通信协议?
术语IIC代表“InterIntegratedCircuits”。它通常表示I2C或IIC,在某些地方,它甚至表示为2线接口协议(TWI),但它们代表的含义是一样的。I2C是同步通信协议,即共享信息的设备必须共享公共时钟信号。共享信息只有两条线,一条用于时钟信号,另一条用于发送和接收数据。
I2C如何工作通信?
I2C通信最初由Phillips介绍。正如前面提到的,它有两根导线,它们将连接到两个设备上。这里的一个设备叫主机,另一个设备叫从机。通信应该始终发生在一个主机和一个从机之间。I2C通信的优点是可以将多个从机连接到主机。
通过这两条导线进行完整的通信,即串行时钟(SCL)和串行数据(SDA)。
●串行时钟(SCL):与主设备共享主设备生成的时钟信号
●串行数据(SDA):在主机和从机之间发送数据。
在任何给定的时间内,只有主机才能启动通信。由于总线中有多个站,主站必须使用不同的地址来引用每个站。当地址被搜索时,只有具有特定地址的机器将响应信息,其他地址将继续退出。这样,我们就可以使用相同的总线与多个设备进行通信。
I2C未预定义的电压电平。I2C通信灵活意味着5v供电设备可使用5v用于I2C,3.3v可使用3个装置v进行I2C通信。但是,如果需要两个在不同电压下运行的设备I2C通信呢?VI2C总线不能与3.3V设备连接。在这种情况下,电压移位器用于匹配两个I2C总线之间的电压电平。
有一些条件可以构成传输。SDA下图定义为下降沿START”条件,其中主机将SCL同时设置为高电平SDA设置为低电平。如下图所示,
SDA的下降沿是START硬件触发条件。此后,同一总线上的所有设备都进入监控模式。
同样的,SDA上图显示上升沿停止传输STOP条件,主机会SCL它被放置为高电平并释放SDA因此,SDA上升沿会阻止传输。
R/W位表示后续字节的传输方向,如果为高电平表示从机将发送,如果为低则表示主机将发送。
每个人都在每个时钟周期发送,所以传输一个字节需要8个时钟周期。发送或接收每个字节后,保持第九个时钟周期ACK/NACK(确认/未确认)。ACK位置由从机或主机根据情况生成。ACK位,SDA主机或从机在第九个时钟周期设置为低电平。因此,它被认为是低的,否则NACK。
在哪里使用I2C通信?
I2C短距离通信仅用于通信。它必须在某种程度上是可靠的,因为它有同步的时钟脉冲来使它智能化。该协议主要用于通信传感器或其他必须向主设备发送信息的设备。当微控制器必须使用最少的导线与许多其他模块通信时,它非常方便。如果你在寻找远程通信,你应该试试RS如果你在寻找更可靠的通信,你应该试试SPI协议。
Arduino中的I2C
下图显示了ArduinoUNO中的I2C引脚。
I2C总线Arduino中的引脚
SDAA4
SCLA5
开始用两个Arduino编程I2C以前,我们需要知道ArduinoIDE中使用的Wire库。
库《Wire.h》用于使用以下程序I2C通信函数。
1.Wire.begin(address):
用途:用于和I2C通信设备。Wire加入库作为从机或主机I2C总线。
address:如果没有指定地址,7位从机地址是可选的,类似Wire.begin(),作为主机加入总线。
2.Wire.read():
用途:该函数用于读取从主机或从机接收的字节,并调用requestFrom()从一个从机到主设备的字节,或从主设备到从机的字节。
3.Wire.write():
用途:该函数用于将数据写入从机或主机。
从机到主机:主站使用时Wire.RequestFrom()从机器将数据写入主机。
从主机到从机:从主机到从机的传输,Wire.write()用于调用Wire.beginTransmission()和Wire.endTransmission()之间。
Wire.write()可写成:
?Wire.write(value)
value:作为单字节发送的值。
?Wire.write(string):
string:要作为一系列字节发送的字符串。
?Wire.write(data,length):
data:作为字节发送的数据数组
length:要传输的字节数。
4.Wire.beginTransmission(address):
用途:该函数用于从地址传输到给定I2C设备。然后,使用write()通过调用函数构建用于传输的字节队列endTransmission()函数传输。
address:发送设备的位地址。
5.Wire.endTransmission();
用途:该函数用于结束beginTransmission()发起的从机传输,由Wire.write()排队字节。
6.Wire.onRequest();
用途:主设备使用Wire.requestFrom()请求来自从设备的数据时,将调用此函数。这里我们可以包含Wire.write()函数向主机发送数据。
7.Wire.onReceive();
用途:从主设备接收数据时,从设备中调用此函数。这里我们可以包括Wire.read();读取从主站发送的数据的函数。
8.Wire.requestFrom(addres,quantity);
用途:该函数用于从设备请求字节。Wire.read()用于读取从设备发送的数据。
address:要求字节设备的7个地址
quantity:要求的字节数
需要的组件
●ArduinoUno开发板
●1602LCD显示模块
●10K电位器
●面包板
●连接导线
电路原理图
工作过程
在这里演示Arduino中的I2C我们用两个通信ArduinoUNO和两个1602LCD两个显示器相互连接arduino在开发板上使用两个电位器来通过改变电位器来确定从主设备到发送值(0到127)。
我们用电位器arduino引脚A输入模拟值从0到5V)转换为模拟到数字值(0到1023)。然后,这些ADC因为我们只能通过值进一步转换为(0到127)I2C通信发送7位数据。I2C通信通过arduino的A4和A5引脚上的两条线。
从机器通过改变主机的电位器Arduino开发板的LCD值会改变,反之亦然。
Arduino中的I2C编程
本文有两个程序,一个用于主机Arduino,另一种用于从机Arduino。
主机Arduino编程介绍
1.首先,我们需要使用它I2C通信功能的Wire用于使用的库和LCD功能的LCD还需要1602LCD定义LCD引脚。
#include《Wire.h》
#include《LiquidCrystal.h》
LiquidCrystallcd(2、7、8、9、10、11)
2.在voidsetup()函数中,
串行通信由波特率9600启动。
Serial.begin(9600);
接下来是引脚(A4,A5)上启动I2C通信
Wire.begin();//BeginsI2Ccommunicationatpin(A4,A5)
接下来,我们将在1602模式下初始化LCD显示模块并显示欢迎信息,然后在五秒后清除。
lcd.begin(16,2)InitilizeLCDdisplay
lcd.setCursor(0,0);///SetsCursoratfirstlineofDisplay
lcd.print(“CircuitDigest”);//PrintsCIRCUITDIGESTinLCD
lcd.setCursor(0,1)//SetsCursoratsecondlineofDisplay
lcd.print(“I2C2ARDUINO”);//PrintsI2CARDUINOinLCD
delay(5000);//Delayfor5seconds
lcd.clear();//ClearsLCDdisplay
3.在voidloop()函数中
首先,我们需要从Slave获取数据,因此我们使用requestFrom()和从地址8,我们请求一个字节
Wire.requestFrom(8,1);
使用Wire.read()读取接收的值
byteMasterReceive=Wire.read();
接下来,我们需要读取连接到引脚A0的主机arduino电位器的模拟值
intpotvalue=analogRead(A0);
我们将该值转换为0到127的字节。
byteMasterSend=map(potvalue,0,1023,0,127);
接下来我们需要发送转换后的值,使用8地址开始从机sarduino的传输
Wire.beginTransmission(8);
Wire.write(MasterSend);
Wire.endTransmission();
接下来,我们显示来自从机arduino的接收值,延迟为500微秒,我们不断接收并显示这些值。
lcd.setCursor(0,0);//SetsCurrsoratlineoneofLCD
lcd.print(“》》Master《《”);//Prints》》Master《《atLCD
lcd.setCursor(0,1);//SetsCursoratlinetwoofLCD
lcd.print(“SlaveVal:”);//PrintsSlaveVal:inLCD
lcd.print(MasterReceive);//PrintsMasterReceiveinLCDreceivedfromSlave
Serial.println(“MasterReceivedFromSlave”);//PrintsinSerialMonitor
Serial.println(MasterReceive);
delay(500);
lcd.clear();
从机Arduino编程介绍
1.与主机设备相同,首先我们需要包含用于使用I2C通信功能的Wire库和用于使用LCD功能的LCD库。还为1602LCD定义LCD引脚。
#include《Wire.h》
#include《LiquidCrystal.h》
LiquidCrystallcd(2,7,8,9,10,11);
2.在voidsetup()函数中,
我们以波特率9600启动串行通信。
Serial.begin(9600);
接下来在引脚(A4,A5)上启动I2C通信,从地址设定为8。这里指定从地址非常重要。
Wire.begin(8);
接下来,当从机从主机接收值并且主机请求从机的值时,我们需要调用该函数
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
接下来我们在16X2模式下初始化LCD显示模块并显示欢迎信息,然后在五秒后清除。
lcd.begin(16,2);//InitilizeLCDdisplay
lcd.setCursor(0,0);//SetsCursoratfirstlineofDisplay
lcd.print(“CircuitDigest”);//PrintsCIRCUITDIGESTinLCD
lcd.setCursor(0,1);//SetsCursoratsecondlineofDisplay
lcd.print(“I2C2ARDUINO”);//PrintsI2CARDUINOinLCD
delay(5000);//Delayfor5seconds
lcd.clear();//ClearsLCDdisplay
3.接下来,我们有两个函数,一个用于请求事件,另一个用于接收事件
对于请求事件
当主机从从机请求值时,将执行该函数。此函数从从机电位器获取输入值并以7位转换,然后将该值发送给主机。
voidrequestEvent()
{
intpotvalue=analogRead(A0);
byteSlaveSend=map(potvalue,0,1023,0,127);
Wire.write(SlaveSend);
}
对于接收事件
当主机通过从机地址(8)向从机发送数据时,将执行该函数。此函数从主机读取接收的值并存储在byte类型的变量中。
voidreceiveEvent(inthowMany)
{
SlaveReceived=Wire.read();
}
4.在voidloop()函数中:
我们在LCD显示模块中连续显示主设备的接收值。
voidloop(void)
{
lcd.setCursor(0,0);//SetsCurrsoratlineoneofLCD
lcd.print(“》》Slave《《”);//Prints》》Slave《《atLCD
lcd.setCursor(0,1);//SetsCursoratlinetwoofLCD
lcd.print(“MasterVal:”);//PrintsMasterVal:inLCD
lcd.print(SlaveReceived);//PrintsSlaveReceivedvalueinLCDreceivedfromMaster
Serial.println(“SlaveReceivedFromMaster:”);//PrintsinSerialMonitor
Serial.println(SlaveReceived);
delay(500);
lcd.clear();
}
通过旋转一侧的电位器,您可以在另一侧看到LCD上的变化值:
以上就是在Arduino中进行I2C通信的方式,这里我们不仅使用两个Arduino开发板来演示通过I2C通信发送数据,而且还演示了接收数据。所以现在你可以将任何I2C传感器连接到Arduino。
编辑:hfy