亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

I2C 通信如何工作? Arduino 和 I2C 教程

在本教程中,我们将学习 I2C 通信协议的工作原理,并且我们将使用 Arduino 板和使用该协议的传感器来做一个实际示例。您可以观看以下视频或阅读下面的书面教程。

概览

I2C通信总线非常流行并被许多电子设备广泛使用,因为它可以很容易地在许多需要主设备和多个从设备甚至多个主设备之间通信的电子设计中实现。简单的实现伴随着这样一个事实,当使用 7 位寻址时,多达近 128 (112) 个设备之间的通信只需要两条线,而使用 10 位寻址时,多达近 1024 (1008) 个设备之间的通信只需要两条线。

I2C 工作原理

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

这两条线或线称为串行时钟(或 SCL)和串行数据(或 SDA)。 SCL 线是时钟信号,用于同步 I2C 总线上设备之间的数据传输,由主设备生成。另一行是承载数据的SDA线。

这两条线是“漏极开路”,这意味着需要将上拉电阻连接到它们,以便这些线处于高电平,因为 I2C 总线上的设备处于低电平有效状态。电阻的常用值是从 2K (约 400 kbps 的较高速度)到 10K(约 100 kbps 的较低速度)。

I2C 协议

数据信号以 8 位序列传输。所以在一个特殊的开始条件发生后,前 8 位序列表示数据发送到的从设备的地址。在每个 8 位序列之后跟随一个称为确认的位。在大多数情况下,在第一个确认位之后是另一个寻址序列,但这次是从设备的内部寄存器。在寻址序列之后紧跟数据序列,直到数据完全发送并以特殊的停止条件结束。

让我们更仔细地看看这些事件。当数据线下降而时钟线仍然为高时,就会出现启动条件。此后,时钟启动,每个数据位在每个时钟脉冲期间传输。

设备寻址序列以最高有效位 (MSB) 开头,以最低有效位 (LSB) 结束,它实际上由 7 位组成,因为第 8 th 位用于指示主机是写入从机(逻辑低)还是读取从机(逻辑高)。

从设备使用下一个比特 AKC/NACK 来指示它是否已成功接收到先前的比特序列。因此,此时主设备将 SDA 线的控制权交给从设备,如果从设备成功接收到先前的序列,它将把 SDA 线拉低到称为确认的状态。如果从机没有拉下 SDA 线,这种情况称为 Not Acknowledge,表示它没有成功接收到前面的序列,这可能是由多种原因引起的。例如,从机可能很忙,可能无法理解接收到的数据或命令,无法接收更多数据等等。在这种情况下,主设备将决定如何进行。

接下来是内部寄存器寻址。内部寄存器是从机内存中包含各种信息或数据的位置。例如,ADX345 加速度计具有唯一的设备地址和 X、Y 和 Z 轴的附加内部寄存器地址。因此,如果我们要读取 X 轴的数据,首先我们需要发送设备地址,然后发送 X 轴的特定内部寄存器地址。这些地址可以从传感器的数据表中找到。

寻址后,数据传输序列从主机或从机开始,具体取决于在 R/W 位选择的模式。数据发送完毕后,传输将以停止条件结束,此时 SDA 线由低电平变为高电平,而 SCL 线为高电平。

示例

例如,我将使用由 5 个不同传感器组成的 GY-80 分线板和由 3 个不同传感器组成的 GY-521 分线板。所以我们可以通过 I2C 总线的两条线从 8 个不同的传感器获取数据。

您可以从以下任何网站获取这些组件:

  • ADXL345 三轴加速器………………………………………………………………
  • 二合一:MPU6050 6轴陀螺仪和加速度计……………………
  • 三合一:GY-80 9 轴磁场加速陀螺仪…………亚马逊
  • 三合一:GY-86 10DOF MS5611 HMC5883L MPU6050 模块…………Banggood  / 速卖通

以下是我们将如何连接电路板。 Arduino 板的串行时钟引脚将连接到两个分线板的串行时钟引脚,串行数据引脚也是如此,我们将使用 Arduino 板的 Gnd 和 5V 引脚为板供电。注意这里我们没有使用上拉电阻,因为分线板已经有了。

现在为了与这些芯片或传感器进行通信,我们需要知道它们的唯一地址。我们可以从传感器的数据表中找到它们。对于 GY-80 分线板,我们有以下 4 个地址:3 轴加速度计传感器的十六进制 0x53、3 轴陀螺仪的十六进制 0x69、3 轴磁力计的十六进制 0x1E 和气压计和温度计的十六进制 0x77传感器。

对于 GY-521 分线板,我们只有一个地址,即十六进制 0x68。我们还可以使用 Arduino I2C 扫描仪草图获取或检查地址,该草图可从 Arduino 官方网站上找到。所以在这里,如果我们上传并运行该草图,我们将获得 I2C 总线上连接设备的地址。


传感器                               零件编号                        I2C地址

3 轴加速度计              Analog Devices ADXL345             0x53            数据表

3 轴 GyroST                        微电子 L3G4200D          0x69             数据表

三轴磁力计             霍尼韦尔 MC5883L                  0x1E            数据表

气压计 + 温度计      博世 BMP085                          0x77            数据表


在我们找到设备的地址之后,我们还需要找到它们内部寄存器的地址,以便从中读取数据。例如,如果我们想从 GY-80 分线板的 3 Axis Accelerometer 传感器读取 X 轴的数据,我们需要找到存储 X 轴数据的内部寄存器地址。从传感器的datasheet中我们可以看到X轴的数据实际上存储在两个寄存器中,DATAX0的十六进制地址为0x32,DATAX1的十六进制地址为0x33。

Arduino I2C 代码

现在让我们编写将获取 X 轴数据的代码。所以我们将使用必须包含在草图中的 Arduino Wire 库。首先,我们必须定义传感器地址和我们之前找到的两个内部寄存器地址。 Wire.begin() 函数将启动 Wire 库,我们还需要启动串行通信,因为我们将使用串行监视器来显示来自传感器的数据。

loop() 我们将从 Wire.beginTransmission() 开始 函数将开始传输到特定传感器,在我们的例子中是 3 轴加速度计。然后用 Wire.write() 函数我们将从 X 轴的两个寄存器中请求特定数据。 Wire.endTransmission() 将结束传输并从寄存器传输数据。现在使用 Wire.requestFrom() 函数我们将从两个寄存器请求传输的数据或两个字节。

Wire.available() 函数将返回可用于检索的字节数,如果该数字与我们请求的字节匹配,在我们的例子中为 2 个字节,使用 Wire.read() 函数我们将从 X 轴的两个寄存器中读取字节。最后,我们将数据打印到串行监视器中。这是数据,但请记住,这是原始数据,需要进行一些数学运算才能获得 X 轴的正确值。您可以在我的下一篇教程中找到更多详细信息,了解如何将加速度计与 Arduino 板一起使用,因为我不想过多介绍本教程,因为它的主要目标是解释 Arduino I2C 通信的工作原理。

/*  
 *  How I2C Communication Protocol Works - Arduino I2C Tutorial
 *  
 *   by Dejan, 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);
}Code language: Arduino (arduino)

制造工艺

  1. Arduino I2C 与 Raspi 2 WIOT 的通信
  2. 如何构建 Arduino 能源监视器和数据记录器
  3. 温湿度数据记录仪
  4. Python3 和 Arduino 通信
  5. 如何在 Arduino 中使用 NMEA-0183
  6. Arduino 教程:JARVIS v1 |如何制作家庭自动化
  7. 如何对 Arduino 进行多线程(原线程教程)
  8. nRF24L01 – 工作原理、Arduino 接口、电路、代码
  9. Arduino 和 MPU6050 加速度计和陀螺仪教程
  10. 如何使用 Arduino 和 ADXL345 加速度计跟踪方向
  11. Arduino 和 HC-12 远程无线通信模块
  12. RFID 的工作原理以及如何制作基于 Arduino 的 RFID 门锁