I2C通信如何工作以及如何使用与Arduino一起使用

在本教程中,我们将学习了I2C通信协议如何工作的,也是我们将它的一个实际例子与Arduino板和使用这一协议的传感器。你可以看下面的视频或阅读以下的书面教程。

概观


在I2C通信总线是很受欢迎,由许多电子设备广泛地使用,因为它可以在需要一个主设备和多个从设备或甚至多个主设备之间的通信的许多电子设计容易地实现。易实现带有只有两根导线,用10比特寻址时所需要的通信使用7比特寻址时之间高达几乎128(112)的设备到几乎1024(1008)的设备的事实。

I2C-通信Overview1

怎么运行的


这怎么可能,只有到电线这么多设备之间的通信?那么每个设备都有一个预设ID或唯一的设备地址,以便主可以选择哪些设备进行通信。

两线或线被称为串行时钟(SCL或)和串行数据(或SDA)。SCL线是同步I2C总线上的设备之间的数据传输时钟信号,它是由主设备产生的。另一条线是SDA线,携带数据。

这两条线是“开漏”,这意味着上拉电阻需要连接到他们,使线条很高,因为I2C总线上的设备都是低电平有效。对于电阻器常用的值是从2K为更高的速度在约400 kbps的,以10K为较低速度在约100 kbps的。

I2C-通信 - 如何-IT-WORKS

协议


数据信号中的8位的序列被传送。所以经过一个特殊的启动条件时谈到正在被送到这表明从站的地址的前8位的序列数据。每8位后的序列如下一点叫应答。在大多数情况下,第一应答位来自另一个解决序列,但这次是从设备的内部寄存器。在寻址序列之后如下因为许多数据序列,直至数据被完全发送,并将其与一个特殊的停止条件结束。
I2C-通信电子协议

让我们来看看这些事件甚至一探究竟。当数据线降到低,时钟线仍然会出现高的启动条件。在此之后,时钟启动,并在每个时钟脉冲在每个数据比特被传送。该设备寻址序列分最显著位(MSB)的第一和用最少显著位结束(LSB)并且由于8它实际上是由7比特第位用于指示主是否会写到从(逻辑低),或者从它读(逻辑高电平)。

I2C-位协议

下位AKC / NACK用于由从设备,以指示是否已经成功地接收的比特的前序列。所以此时主设备的手的SDA线到从设备,并且如果从站装置的控制已成功地接收到先前的序列,将拉SDA线向下到称为应答的条件。如果从机不拉SDA线下来,这种情况称为无应答,并表示它没有成功接收到可能由几个原因造成以前的序列。例如,从可能会很忙,可能不理解所接收到的数据或命令,不能接收任何更多的数据等。在这样的情况下,主设备决定将如何进行。

I2C-位-Protocol_ADXL-X轴为例

接下来是内部寄存器寻址。内部寄存器是包含各种信息或数据从内存中的位置。例如ADX345加速度具有用于在X,Y和Z轴的唯一的装置地址和除了内部寄存器的地址。所以,如果我们要读取X轴的数据,首先我们需要发送设备地址,然后将特定的内部寄存器地址为X轴。这些地址可以发现传感器的数据表。

寻址后,数据传输序列开始无论是从船长或依赖于R / W位选择的模式的奴隶。数据完全发送后,传输将发生停止条件结束时,SDA线由低电平变为高电平,而SCL线为高。

I2C和Arduino的


作为一个例子,我将使用GY-80接口板它由5个不同的传感器和它由3个不同的传感器GY-521接口板。因此,我们可以从8个不同的传感器只有两个I2C总线导线中获取数据。

GY --- 80和GY --- 521地址

你可以购买从ICStation,推荐的零售商通过HowToMechatronics这些组件:

*请注意:这是联盟链接。如果通过这些链接购买组件我可能使佣金。
我希望用这种方式您的支持!

下面是我们将如何连接板。在Arduino板的串行时钟引脚将被连接到两个分场板的串行时钟引脚,同样适用于串行数据引脚,我们将电源与GND和从Arduino板的5V引脚板。注意,在这里我们没有使用上拉电阻,因为突破板已经有了。

I2C-和Arduino的电路,原理图

现在为了与这些芯片或传感器,我们需要知道他们的唯一地址通信。我们可以从传感器的数据表中找到它们。对于GY-80接口板,我们有以下4个地址:十六进制0x53的3轴加速度传感器,十六进制0×69的3轴陀螺仪,一个十六进制0X1E的3轴磁力计和气压计和温度计的十六进制0x77传感器。对于GY-521接口板,我们只有一个地址,这是一个十六进制为0x68。我们还可以获取或使用I2C扫描器草图可以从Arduino的官方网站上找到检查地址。所以在这里,如果我们上载和运行的草图,我们将得到I2C总线上连接的设备的地址。


传感器型号I2C地址

3轴加速度计ADI公司ADXL345 0x53                   数据表

3轴GyroST微电子L3G4200D×69                   数据表

3轴磁力霍尼韦尔MC5883L 0X1E                   数据表

晴雨表+温度计博世BMP085 0x77                   数据表


之后,我们已经找到了设备的地址,我们还需要找到其内部寄存器的地址,以从中读取数据。例如,如果我们想读取从GY-80接口板的3轴加速度传感器X轴的数据,我们需要找到其中X轴的数据存储在内部寄存器地址。从传感器的数据表,我们可以看到,数据X轴实际上是存储在两个寄存器,DATAX0用十六进制地址0x32和DATAX1用十六进制地址0x33。

源代码


现在,让我们的代码,将得到的数据为X轴。因此,我们将使用Arduino的电线库里面有草图被包括。在这里,我们首先必须定义传感器地址和我们以前发现的两个内部寄存器地址。所述Wire.begin()函数将启动导线库,也需要以引发串行通信,因为我们将使用串行监视器,以显示来自所述传感器的数据。

在循环() ,我们将与启动Wire.beginTransmission()将开始传送到特定的传感器,3轴加速度计在我们的例子功能。然后用Wire.write()函数中,我们将要求从X轴的两个寄存器的特定数据。所述Wire.endTransmission()将结束传输和从寄存器传送数据。现在用Wire.requestFrom()函数,我们将请求从两个寄存器发送的数据或两个字节。所述Wire.available()函数将返回可用于检索和如果该号码匹配与我们的请求的字节的字节数,在我们的情况下,2个字节,使用Wire.read()函数,我们将从两个寄存器中读取的字节X轴。在最后,我们将打印数据转换为串行监视器。这里有一个数据,但请记住,这是原始数据,并且需要一些数学,以获得X轴的正确的价值观做。你可以找到在我的下一个教程更详细的信息使用与Arduino板加速度计,因为我不想超载这个教程,因为它的主要目标是解释I2C通信是如何工作的。

/*  
 *  How I2C Communication Protocol Works - Example01
 *  
 *   by Dejan Nedelkovski, www.HowToMechatronics.com 
 *   
 */

#include <Wire.h>

int ADXLAddress = 0x53; // Device address in which is also included the 8th bit for selecting the mode, read in this case.

#define X_Axis_Register_DATAX0 0x32 // Hexadecima address for the DATAX0 internal register.
#define X_Axis_Register_DATAX1 0x33 // Hexadecima address for the DATAX1 internal register.
#define Power_Register 0x2D // Power Control Register

int X0,X1,X_out;

void setup() {
  Wire.begin(); // Initiate the Wire library
  Serial.begin(9600);
  delay(100);
  // Enable measurement
  Wire.beginTransmission(ADXLAddress);
  Wire.write(Power_Register);
  // Bit D3 High for measuring enable (0000 1000)
  Wire.write(8);  
  Wire.endTransmission();
}

void loop() {
  Wire.beginTransmission(ADXLAddress); // Begin transmission to the Sensor 
  //Ask the particular registers for data
  Wire.write(X_Axis_Register_DATAX0);
  Wire.write(X_Axis_Register_DATAX1);
  
  Wire.endTransmission(); // Ends the transmission and transmits the data from the two registers
  
  Wire.requestFrom(ADXLAddress,2); // Request the transmitted two bytes from the two registers
  
  if(Wire.available()<=2) {  // 
    X0 = Wire.read(); // Reads the data from the register
    X1 = Wire.read();   
  }
  
  Serial.print("X0= ");
  Serial.print(X0);
  Serial.print("   X1= ");
  Serial.println(X1);
}


编译自:http://howtomechatronics.com/tutorials/arduino/how-i2c-communication-works-and-how-to-use-it-with-arduino/

标签