掌握Arduino I2C通信:实战教程
本教程将讲解I2C通信协议的工作原理,并通过Arduino开发板与一个使用该协议的传感器进行实战演示。您可以观看以下视频或阅读下方文字教程。 I2C通信总线因易于实现,广泛应用于许多电子设备。它可实现主设备与多个从设备(甚至多主设备)之间的通信。实现简易的关键在于仅需两根线:使用7位寻址时最多可连接128(112)个设备,10位寻址时最多1024(1008)个设备。 如何仅用两根线实现这么多设备通信?每个设备都有预设的唯一设备地址,主设备可选择与哪个设备通信。 两根线分别称为串行时钟线(SCL)和串行数据线(SDA)。SCL由主设备产生时钟信号,同步总线上设备间的数据传输。SDA传输数据。 两根线均为“开漏”结构,需接上拉电阻使线路保持高电平(设备为低电平有效)。常用电阻值:2KΩ用于高速约400kbps,10KΩ用于低速约100kbps。 数据以8位序列传输。起始条件后,首个8位序列为从设备地址。每8位后跟一个应答位(ACK)。首个ACK后通常跟随从设备内部寄存器地址序列。随后为数据序列,直到数据发送完毕,以停止条件结束。 细看这些事件:起始条件发生在SCL高电平时SDA由高变低。随后时钟开始,每个时钟脉冲传输一位数据。 设备寻址序列从最高有效位(MSB)开始,到最低有效位(LSB)结束,实际由7位组成,第8位用于指示主设备写从设备(低电平)还是读从设备(高电平)。 接下来的ACK/NACK位由从设备用于指示是否成功接收前一个序列。此时主设备将SDA控制权交给从设备,若成功接收,从设备将SDA拉低表示ACK;若不拉低则为NACK,表示未成功接收(可能原因:从设备忙、不理解命令、无法接收更多数据等)。主设备决定后续处理。 随后是内部寄存器寻址。内部寄存器是从设备存储器中包含各种信息或数据的位置。例如ADXL345加速度计有唯一设备地址,以及X、Y、Z轴的内部寄存器地址。若要读取X轴数据,先发送设备地址,再发送X轴对应的内部寄存器地址。这些地址可从传感器数据手册获取。 寻址后开始数据传输序列,方向取决于R/W位选择的模式。数据发送完毕后,以停止条件结束:SCL高电平时SDA由低变高。 示例使用GY-80扩展板(含5个传感器)和GY-521扩展板(含3个传感器),通过I2C总线仅用两根线即可读取8个传感器数据。 所需组件: 连接方式:Arduino的SCL连接两块扩展板的SCL,SDA同理,GND和5V供电。注意此处未使用上拉电阻,因扩展板已自带。 需要知道各芯片/传感器的唯一地址,可从数据手册获取。GY-80四个地址:加速度计0x53、陀螺仪0x69、磁力计0x1E、气压/温度计0x77。GY-521仅一个地址0x68。也可用Arduino I2C Scanner扫描获取地址(Arduino官网提供)。上传运行该草图可获取I2C总线上连接设备的地址。 传感器型号 | I2C地址 三轴加速度计 ADXL345 | 0x53 | 数据手册 三轴陀螺仪 L3G4200D | 0x69 | 数据手册 三轴磁力计 HMC5883L | 0x1E | 数据手册 气压计+温度计 BMP085 | 0x77 | 数据手册 获取设备地址后,还需内部寄存器地址以读取数据。例如读取GY-80上ADXL345的X轴数据,需找到存储X轴数据的内部寄存器。数据手册显示X轴数据存储在两个寄存器:DATAX0 (0x32) 和 DATAX1 (0x33)。 编写读取X轴数据的代码。使用Arduino Wire库(需包含)。定义传感器地址和两个内部寄存器地址。Wire.begin()初始化Wire库,同时初始化串口通信以便串口监视器显示数据。 loop()中:Wire.beginTransmission()开始与特定传感器(三轴加速度计)通信。Wire.write()请求X轴两个寄存器的数据。Wire.endTransmission()结束传输并从寄存器传出数据。Wire.requestFrom()请求两字节数据。Wire.available()返回可用字节数,若匹配2字节,用Wire.read()读取两个寄存器字节。最后串口监视器打印数据。注意这是原始数据,需进一步数学处理才能得到正确的X轴值。详细处理请参考我的下一篇加速度计教程,本教程重点讲解I2C通信原理。概述

I2C如何工作

I2C协议



实例


Arduino I2C代码
代码语言: Arduino (arduino)
/*
* I2C通信协议工作原理 - Arduino I2C教程
* by Dejan, www.HowToMechatronics.com
*/
#include <Wire.h>
int ADXLAddress = 0x53; // 设备地址,包含第8位模式选择位(读模式)
#define X_Axis_Register_DATAX0 0x32
#define X_Axis_Register_DATAX1 0x33
#define Power_Register 0x2D // 电源控制寄存器
int X0,X1,X_out;
void setup() {
Wire.begin(); Serial.begin(9600); delay(100);
// 启用测量
Wire.beginTransmission(ADXLAddress);
Wire.write(Power_Register);
Wire.write(8); // Bit D3置高 (0000 1000)
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(ADXLAddress);
Wire.write(X_Axis_Register_DATAX0);
Wire.write(X_Axis_Register_DATAX1);
Wire.endTransmission();
Wire.requestFrom(ADXLAddress,2);
if(Wire.available()<=2) {
X0 = Wire.read(); X1 = Wire.read();
}
Serial.print("X0= "); Serial.print(X0);
Serial.print(" X1= "); Serial.println(X1);
}
制造工艺
- Arduino 与树莓派 2 I2C 通信集成:打造物联网传感器项目的最佳搭档
- 打造可靠的 Arduino 能源监测与数据记录仪——分步指南
- Arduino + DHT11 + 以太网盾板温湿度数据记录仪
- Python 3 控制 Arduino UNO - 串口通信点亮内置 LED 入门教程
- Arduino 连接 NMEA-0183 设备全攻略:从硬件接线到协议解析
- Arduino Nano 打造 JARVIS v1 家庭自动化:分步教程
- 掌握 Arduino 多任务编程:原型线程分步教程
- 掌握nRF24L01:无线通信、Arduino集成、电路与代码全攻略
- MPU6050 六轴 IMU 详解:Arduino 姿态解算与 3D 可视化
- ADXL345 三轴加速度计 Arduino 姿态追踪教程
- 使用 HC-12 模块构建可靠的远距离 Arduino 网络
- Arduino RFID 门禁系统:从原理到实战的完整指南