IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Arduino与Proteus仿真实例-两个Arduino之间I2C通信仿真 -> 正文阅读

[嵌入式]Arduino与Proteus仿真实例-两个Arduino之间I2C通信仿真

两个Arduino之间I2C通信仿真

1、I2C介绍

集成电路间 (I2C) 协议是一种旨在允许多个“外围”数字集成电路(“芯片”)与一个或多个“控制器”芯片进行通信的协议。它只需要两根信号线来交换信息。

在这里插入图片描述

  • SDA(串行数据):主机和从机发送和接收数据的线路。
  • SCL(串行时钟):传输时钟信号的线路。

与 SPI 一样,I2C 是同步的,因此位的输出通过主机和从机之间共享的时钟信号与位的采样同步。 时钟信号始终由主机控制。

2、I2C的数据组成

使用 I2C,数据以消息的形式传输。 消息被分解成数据帧。 每条消息都有一个地址帧,其中包含从站的二进制地址,以及一个或多个包含正在传输的数据的数据帧。 该消息还包括每个数据帧之间的开始和停止条件、读/写位和 ACK/NACK 位:

在这里插入图片描述

  • 启动条件:在 SCL 线从高电平切换到低电平之前,SDA 线从高电压电平切换到低电压电平。
  • 停止条件:SCL 线从低电平切换到高电平后,SDA 线从低电平切换到高电平。
  • 地址帧:每个从站唯一的 7 或 10 位序列,用于在主站想要与其通话时识别从站。
  • 读/写位:单个位指定主机是向从机发送数据(低电压电平)还是从它请求数据(高电压电平)。
  • ACK/NACK 位:消息中的每个帧后跟一个确认/不确认位。 如果成功接收到地址帧或数据帧,则从接收设备向发送方返回一个 ACK 位。

2)I2C寻址

I2C 没有像 SPI 那样的从机选择线,因此它需要另一种方式让从机知道正在向它发送数据,而不是另一个从机。 它通过寻址来做到这一点。 地址帧始终是新消息中起始位之后的第一帧。

主机将它想要与之通信的从机地址发送给与其相连的每个从机。 然后,每个从设备将主设备发送的地址与其自己的地址进行比较。 如果地址匹配,它会向主机发送一个低电压 ACK 位。 如果地址不匹配,从机什么也不做,SDA 线保持高电平。

3)读/写位

地址帧的末尾包含一个位,用于通知从机是要向其写入数据还是要从其接收数据。 如果主机要向从机发送数据,则读/写位为低电压电平。 如果主机向从机请求数据,则该位为高电压电平。

4)数据帧

在主机检测到来自从机的 ACK 位后,第一个数据帧准备好发送。

数据帧总是 8 位长,并以最高有效位在前发送。 每个数据帧后面紧跟着一个 ACK/NACK 位,以验证该帧是否已成功接收。 在发送下一个数据帧之前,主机或从机必须接收到 ACK 位(取决于谁在发送数据)。

发送完所有数据帧后,主设备可以向从设备发送停止条件以停止传输。 停止条件是在 SCL 线上从低到高转换之后 SDA 线上的电压从低到高转换,而 SCL 线保持高电平。

3、I2C通信过程

1)主机通过将 SDA 线从高电平切换到低电平,然后将 SCL 线从高电平切换到低电平,向每个连接的从机发送启动条件。

在这里插入图片描述

2)主机向每个从机发送它想要与之通信的从站的 7 位或 10 位地址以及读/写位:

在这里插入图片描述

3)每个从机将主机发送的地址与自己的地址进行比较。 如果地址匹配,从机通过将 SDA 线拉低一位来返回 ACK 位。 如果来自主机的地址与从机自己的地址不匹配,则从机将 SDA 线保持为高电平。

在这里插入图片描述

4)主机发送或接收数据帧:

在这里插入图片描述

5)传输完每个数据帧后,接收设备向发送方返回另一个 ACK 位以确认已成功接收该帧:

在这里插入图片描述

6)为了停止数据传输,主机通过在将 SDA 切换为高电平之前将 SCL 切换为高电平来向从机发送停止条件:

在这里插入图片描述

4、I2C连接模式

1)单主机多从机模式

由于 I2C 使用寻址,因此可以从单个主机控制多个从机。 对于 7 位地址,可以使用 128 (2^7) 个唯一地址。 使用 10 位地址并不常见,但可提供 1,024 (2^10) 个唯一地址。 要将多个从设备连接到单个主设备,请按如下方式连接它们,使用 4.7K 欧姆上拉电阻将 SDA 和 SCL 线连接到 Vcc:

在这里插入图片描述

2)多主机多从机模式

多个主机可以连接到一个从机或多个从机。 当两个主设备尝试通过 SDA 线同时发送或接收数据时,同一系统中的多个主设备就会出现问题。 为了解决这个问题,每个主设备在发送消息之前都需要检测 SDA 线是低还是高。 如果 SDA 线为低电平,则意味着另一个主机控制了总线,主机应等待发送消息。 如果 SDA 线为高电平,则传输消息是安全的。 要将多个主机连接到多个从机,请使用下图,使用 4.7K 欧姆上拉电阻将 SDA 和 SCL 线连接到 Vcc:

在这里插入图片描述

5、仿真电路原理图

在这里插入图片描述

6、仿真代码实现

1)主机代码

#include <Wire.h>

#define SLAVE_ADDRESS 0x12 // 从机地址
#define DATA_SIZE 8 // 数据缓冲大小

#define CMD_LED_OFF 0 // LED关命令
#define CMD_LED_ON 1 // LED开命令

void setup() {
  // 启动为主机模式
  Wire.begin(); 
  Serial.begin(9600);
}
void loop() {
  // 向从机发送数据
  Wire.beginTransmission(SLAVE_ADDRESS);
  Wire.write(CMD_LED_OFF);             
  Wire.endTransmission();  
  
  Serial.println("send led off cmd");
  // 向从机请求数据
  Wire.beginTransmission(SLAVE_ADDRESS);
  Wire.requestFrom(SLAVE_ADDRESS, DATA_SIZE);
  if (Wire.available()) {
    Serial.print("Data returned: ");
    while (Wire.available()) Serial.print((char) Wire.read());
    Serial.println();
  }
  Wire.endTransmission();
  
  delay(500);
  Wire.beginTransmission(SLAVE_ADDRESS);
  Wire.write(CMD_LED_ON);
  Wire.endTransmission();   
  Serial.println("send led on cmd");
  
  // 向从机发送数据
  Wire.beginTransmission(SLAVE_ADDRESS);
  Wire.requestFrom(SLAVE_ADDRESS, DATA_SIZE);
  if (Wire.available()) {
    Serial.print("Data returned: ");
    while (Wire.available()) Serial.print((char) Wire.read());
    Serial.println();
  }
  Wire.endTransmission();
  
  delay(500);
}

2)从机代码

#include <Wire.h>
int cmd_dat = 0;
int ledPin = 7; // LED引脚
#define SLAVE_ADDRESS 0x12 // 从机地址
#define CMD_LED_OFF 0 // LED关命令
#define CMD_LED_ON 1 // LED开命令

void setup() {
  // 设置LED引脚为输出
  pinMode (ledPin , OUTPUT);
  // 开始I2C总线,设置为从机模式
  Wire.begin(SLAVE_ADDRESS); 
  // 设置数据接收回调函数
  Wire.onReceive(receiveEvent);
  // 设置数据请求回调函数
  Wire.onRequest(requestEvent);
  // 初始化串口
  Serial.begin(9600);
}
void receiveEvent(int bytes) {
  cmd_dat = Wire.read();    // 读取数据
}

void requestEvent()
{
  switch (cmd_dat) {
    case CMD_LED_OFF:
      Serial.println("request led off");
      Wire.write("led off",SLAVE_ADDRESS);
      break;
    case CMD_LED_ON:
     Wire.write("led on",SLAVE_ADDRESS);
      Serial.println("request led off");
      break;
    default:
      Wire.write("nothing",SLAVE_ADDRESS);
  }
}

void loop() {
  if (cmd_dat == CMD_LED_OFF) {
    Serial.println("led off");
    digitalWrite(ledPin,LOW);
    cmd_dat = -1;
  }
  if (cmd_dat == CMD_LED_ON) {
    Serial.println("led on");
    digitalWrite(ledPin,HIGH);
    cmd_dat = -1;
  }
  
}

7、仿真结果

在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-23 12:39:15  更:2021-10-23 12:41:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:49:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码