首页 > 其他分享 >Arduino - ESP8266和ESP32的I2C接口使用(超全)

Arduino - ESP8266和ESP32的I2C接口使用(超全)

时间:2024-02-02 12:23:46浏览次数:35  
标签:ESP8266 Arduino 主机 ESP32 从机 Serial I2C 连接 设备

简介

深入讲解I2C通信协议,以及,Arduino和ESP8266微控制器通过I2C连接设备需要哪些引脚、该通信协议的优缺点以及如何使用I2C多路复用器

详解

Arduino/ESP8266与其他设备通信,例如OLED显示器、气压传感器等,

可以使用I2C通信协议。

也可以使用两外两个通信协议:SPI和UART

I2C全称是Inter-Integrated Circuit,是1982年由飞利浦半导体公司(现在为NXP Semiconductors)发明的。I2C具有多种功能:

  • 同步(Synchronous):通过主机和从机之间共享的时钟信号,位输出与位采样同步。
  • 多主机(Multi-master):您可以有多个主机控制一个或多个从机。
  • 多从机(Multi-slave):您可以将多个从机连接到单个主机,类似于SPI。
  • 数据包交换(Packet switched):传输的数据分为包/消息,由数据头和有效负载组成。
  • 单端(Single-ended):数据通过单线传输。
  • 串行连接(Serial connection):数据通过单线一位一位地传输

I2C参考设计

在Arduino/ESP8266上,您将找到用于I2C通信的两个GPIO(SDA和SCL)。

如果不确定是否找到相应的引脚,请参见以下图片

ESP8266(NodeMCU):SDA:D2(I2C->数据);SCL:D1(I2C->时钟)

Arduino Nano开发板:SDA:A4;SCL:A5

I2C通信所需的两个引脚如下:

  • SDA(串行数据):主站和从站之间的连接,用于发送和接收数据。
  • SCL(串行时钟):在主机和从机之间共享时钟信号,其中主机始终控制时钟信号。

串行数据线和串行时钟线通过电阻上拉。

因此,当总线上没有数据传输时,SDA和SCL处于高电平状态。

典型电压为+ 5V和+ 3.3V,设备可以100 kHz或400 kHz进行通信。

所有I2C器件都通过集电极开路或漏极开路引脚连接到总线,以将总线拉低。

主机和从机之间的通信是通过拉低和释放高电平来切换总线而发生的。此外,位在时钟下降沿计时。

对于给定的总线设备,可能有四种潜在的操作模式,但是大多数设备仅使用单个角色,并且使用两种模式:

  • 主机发送 – 主机正在向从机设备发送数据,
  • 主节接收 – 主机正在从从机设备接收数据,
  • 从机发送 – 从机设备正在向主机发送数据,
  • 从机接收 – 从机设备正在从主机接收数据。

 

I2C消息协议

I2C消息协议根据位的电平分成固定的状态。在本文的以下部分,我们将仔细研究协议的六个不同状态。

  1. 开始条件:SCL为高电平时,SDA:高→低
  2. 停止条件:SCL为高电平时,SDA:低→高
  3. 地址帧:地址帧是7或10位序列,用于标识主机的每个从机。该标识符在所有从站上都是唯一的。每个从机将从主机发送的地址与其自己的地址进行比较。如果地址匹配,它将向主机发送一个ACK位→0。如果地址不匹配,则从站不执行任何操作,并且SDA线保持高电平。
  4. 读/写位

    写入:主机正在向从机发送数据:0

    读取:主机正在向从机请求数据:1

  5. ACK / NACK位。如果成功接收到地址帧或数据帧,则会从机设备向发送方返回ACK位→0。
  6. 数据帧:主机检测到来自从机的ACK位后,即可发送第一个数据帧。数据帧始终为8位长,后跟ACK / NACK位以验证是否已成功接收到该帧。主机将以固定间隔继续产生时钟脉冲。

I2C写入通讯时序

I2C读取通讯时序

 

 

重复启动条件

时钟延长

在某些情况下,主机数据速率将超过从机提供所需数据的能力。因此,从机可以在主机释放SCL线后按住SCL线。主机将等待从机释放点击线,然后再继续下一帧。

物理层

  与UART或SPI连接不同,I2C总线驱动器是“漏极开路”的,这意味着它们可以将相应的信号线拉低,但不能将其拉高。因此,当一台设备试图将线路驱动为高电平而另一台设备将其拉低时,则无法进行通信。这种架构避免了通信中的错误。

  但是如何将信号线拉高?每条信号线都有一个上拉电阻,可在没有器件将其置为低电平时将信号恢复为高电平。根据经验,选择一个电阻为4.7kΩ。连接到I2C通信的设备越多,电阻就必须越小。

  I2C在连接具有不同I / O电压的设备时具有一定的灵活性。对于以5V电压电平作为主设备的Arduino开发板,可以正常连接一个3.3V电压的从设备。但是,如果从机的电压低于3.3V(例如2.5V),则有可能需要I2C电平转换器。

I2C速度模式

  • 低速模式:10 kbit / s
  • 标准模式:100 kbit / s
  • 快速模式:400 kbit / s
  • 快速模式+:1 Mbit / s
  • 高速模式:3.4 Mbit / s
  • 超快速模式:5 Mbit / s

I2C通讯的优缺点

  • 优点:仅使用两根电线;支持多个主机和多个从机;众所周知且被广泛使用的协议。
  • 缺点:数据传输速率比SPI慢,数据帧的大小限制为8位

I2C示例

接下来,我们在以下章节不再介绍理论知识,而是介绍一些实际用例。

在控制一台I2C设备之前,我们首先必须找出其十六进制地址。

因此,我们的第一个示例是I2C HEX地址扫描器。

找到I2C LCD显示器的十六进制地址后,我们将相应地控制该显示器,以通过I2C从Arduino或NodeMCU向LCD显示器发送消息。

下图显示了I2C LCD显示屏分别与Arduino Uno和NodeMCU之间的硬件连接。

下表列出了Arduino Uno和LCD显示屏之间的硬件连接关系。

下表列出了Node MCU和LCD显示屏之间的硬件连接关系。

如何找到I2C设备的十六进制地址?

#include "Wire.h"
//“ Wire.h”库允许微控制器与I2C设备通信。因此,每当您要使用I2C通信时,该库都是必不可少的。
void setup(){
  Serial.begin(115200); 
  while(!Serial){} // Waiting for serial connection
 
  Serial.println();
  Serial.println("Start I2C scanner ...");
  Serial.print("\r\n");
  byte count = 0;

//该草图代码仅使用setup函数,因为我们只需要一次扫描所有连接的设备。

首先,我们将波特率定义为115200,然后记住将串口监视器的波特率设置为相同的值。

然后我们等到建立串行连接后,我们才能够扫描设备。

在串口监视器上定义了一些很酷的打印之后,我们将变量计数定义为零。找到I2C设备后,该变量将增加,该变量是连接的I2C设备的总和。

Wire.begin();
  for (byte i = 8; i < 120; i++)
  {
    Wire.beginTransmission(i);
    if (Wire.endTransmission() == 0)
      {
      Serial.print("Found I2C Device: ");
      Serial.print(" (0x");
      Serial.print(i, HEX);
      Serial.println(")");
      count++;
      delay(1);
      }
  }
//通过Wire.begin()函数,微控制器可以作为主机或从机加入I2C总线。
如果在Wire.begin()之类的函数中未提供地址,该设备将像我们希望的那样作为主机设备加入。
要扫描所有可能的I2C HEX地址,我们使用for循环。为了开始传输到可能的I2C从设备,我们使用Wire.beginTransmission(address)函数。
如果存在有效的I2C从设备,则通过Wire.endTransmission()结束到从设备的传输,我们将得到0。
我们在串口监视器上打印所连接设备的十六进制地址。同样,如果找到I2C设备,则在将计数器连接到下一个设备之前,将计数器增加1并稍加延迟。
  Serial.print("\r\n");
  Serial.println("Finish I2C scanner");
  Serial.print("Found ");
  Serial.print(count, HEX);
  Serial.println(" Device(s).");
}

void loop() {}
//在代码的末尾,我们打印找到的I2C设备的总数。我们没有使用循环函数。

如果我们看一下串口监视器,结果如下:

我们发现已连接的I2C LCD显示器的十六进制地址为0x27。下一个示例将需要此地址。

控制LCD液晶显示器

  使用I2C HEX扫描仪,我们发现LCD显示屏的HEX地址为0x27。

现在,我们可以对脚本进行编程以与LCD显示器进行通讯了。对于此草图代码,我们需要LiquidCrystal_I2C库。

  首先,我们必须包含Wire库和LiquidCrystal_I2C库,该库做了大量工作,并且向我们提供了用于LCD显示器的易于使用的接口。

  我们需要定义显示器的十六进制地址以及正在使用的显示器,例如16×2或20×4。在此示例中,我使用20×4显示屏。

  在setup函数中,我们使用lcd.init()初始化微控制器和显示器之间的连接。初始化后,我们使用lcd.backlight()打开背光灯。

  设置好显示后,我们可以将光标设置到位置(列= 1,行= 0),并写入文本的第一部分。然后,将光标置于下一行,并写入其余字符串。

#include "Wire.h"
#include "LiquidCrystal_I2C.h"

// set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 20, 4); 

void setup()
{
  lcd.init();

  lcd.backlight();
  lcd.setCursor(1, 0);
  lcd.print("This is");
  lcd.setCursor(1, 1);
  lcd.print("DIYI0T.com");
}

void loop(){}

I2C多路复用器

  如果您想将许多传感器连接到Arduino,并且您的常规I2C连接不能满足要求?

传感器可能具有相同的I2C地址。您的问题的解决方案是PCF8574 1对8 I2C扩展器。

PCF8574 Breakout支持与具有相同地址的多个I2C器件进行通信,从而使其易于与它们进行连接器。

PCF8574是一个八通道I2C扩展器,它允许八个独立的I2C器件由单个主机I2C总线控制。

PCF8574是用于两线双向总线(I2C)的8位输入/输出(I / O)扩展器,设计用于2.5V至6V的工作电压。待机电流消耗仅为10μA,非常低。

P0…P7是具有推挽设计结构的P端口输入/输出。在这里,将I2C设备连接到PCF8574。我们将LED连接到P0。

A0…A2是PCF8574本身的地址输入。我们不需要它们,因此将它们连接到GND。

多路复用器的程序代码和设备的控制与上述相同。

标签:ESP8266,Arduino,主机,ESP32,从机,Serial,I2C,连接,设备
From: https://www.cnblogs.com/citrus/p/18002874

相关文章

  • NanoFramework操作ESP32(一)_基础元器件篇(三十九)_ TCRT5000红外寻迹模块
    产品用途:1、电度表脉冲数据采样2、传真机碎纸机纸张检测3、障碍检测4、黑白线检测产品介绍:1、采用TCRT5000红外反射传感器2、检测反射距离:1mm~25mm适用3、工作电压:5V4、输出形式:数字信号(0和1)5、设有固定螺栓孔,方便安装6、小板PCB尺寸:3.5cmx1cm7、单重:4.5g功能介绍......
  • NanoFramework操作ESP32(一)_基础元器件篇(三十二)_ KY-002震动传感器
    一、元器件介绍  本开关在静止时为开路(OFF)状态,当受到外力碰触而达到适当震动力时,或移动速度达到适当离(偏)心力时,导电接脚会发生瞬间导通(ON)状态,使电气特性改变,而当外力消失时电气特性恢复开路(0FF)状态。可使用数字信号接收。1、针脚用途编号名称功能1GND电......
  • NanoFramework操作ESP32(一)_基础元器件篇(三十三)_ KY-020倾斜开关
    一、元器件介绍  KY-020倾斜开关模块由一个10kΩ电阻器和一个具有双向导电性的金属球开关组成,该开关根据倾斜程度来打开/关闭电路。它不测量倾斜角。当电路向侧面倾斜时,只要以足够的力和倾斜度移动电路,即可激活内部的球开关,从而使电路闭合。以输出低电平电压信号。可使用数字......
  • Arduino - 使用ESP32-CAM
    简介准备工作:Arduino+ESP32-CAMdemo实现:使用ESP32-CAM实现拍照和视频流Arduino+ESP32开发环境搭建官网下载Arduinohttps://www.arduino.cc/en/software(建议不要下载beta版,可能会有问题)如果官网太慢可以在这里下载[Arduino中文社区-PoweredbyDiscuz!](https://www.a......
  • Arduino - Arduino/AVR/8051 和 ARM/STM32
    8051,AVR和ARM架构80518051是由Intel于1980年代初推出的一款8位单片机。它的架构基于哈佛结构(分离的程序和数据存储器),并使用8位数据总线和16位地址总线。8051内核是一个8位CISC(复杂指令集计算机)处理器,具有不同的寻址模式和指令。该内核具有四个寄存器组、两个16位计数器/定时器、一......
  • Arduino - 使用ESP32-CAM
    简介准备工作:Arduino+ESP32-CAMdemo实现:使用ESP32-CAM实现拍照和视频流Arduino+ESP32开发环境搭建官网下载Arduinohttps://www.arduino.cc/en/software(建议不要下载beta版,可能会有问题)如果官网太慢可以在这里下载[Arduino中文社区-PoweredbyDiscuz!](https://www.a......
  • ESP32 LVGL:使用图标解决图片过大存不下的问题
    原文:ESP32LVGL:使用图标解决图片过大存不下的问题_lvgl生成的图片太大-CSDN博客文章目录背景方法将PNG图片转为字库文件LVGL加载自定义字体图标参考背景在LVGL中,用将图片转为C语言数组的方式储存的时候,图片转换的数组过大,当图片过多时会出现存不下的问题。因此,可以使用字库图标解......
  • NanoFramework操作ESP32(一)_基础元器件篇(三十七)_ SD读卡器模块
    二、示例代码1、代码:元器件的针脚ESP32模块的针脚GND;供电脚-GND3v3;供电脚+3v3CS MOSI SCK MISO GND ......
  • Arduino库 <TFT_eSPI> 中文字库的制作与使用
    原文:Arduino库<TFT_eSPI>中文字库的制作与使用_anullpfontwaspassedtotextfont()-CSDN博客作者学习自以下博客,经过验证,并重新整理了步骤。https://www.cnblogs.com/deng1821333144/p/15307883.html#_label2如有需要,请访问原文章进行查看。目录一、TFT_eSPI基础配置二、字......
  • esp8266 no matching function for call to 'Ticker::Ticker()'
    这个错误表明在尝试创建一个Ticker对象时,编译器找不到适合当前调用的构造函数。Ticker可能是Arduino框架中的一个类,用于处理定时事件。解决方法:确认你已经包含了正确的头文件。例如,对于ArduinoESP8266核心库,你需要包含Ticker.h#include<Ticker.h> 确认......