EBU5476 Microprocessor System Design 知识点总结_8 I2C

news2024/11/23 2:43:26

I2C

连接多个模块的传输方案:I2C,使用两根总线。

image-20230622000302459

两根总线分别是时钟总线 SCL 和数据总线 SDA。

通信过程

现在我们串一遍I2C上一个模块(master)要给另一个模块(slave)发消息的过程。

1687363434463

  1. MCU 使用一定的方法标识自己开始传输了。
  2. MCU 发送 LCD slave 的地址+一位读写位,其他模块接收到发现地址不是自己的,就不做处理。
  3. LCD 接收到后知道目标是自己,于是返回 ack。
  4. MCU 收到 ACK 后发送一帧数据。
  5. 发送完 MCU 等着 ACK,收到 ACK 后继续发送下一帧数据。
  6. 一直发送到发送停止位 stop 结束。

image-20230622000920336

数据长度可以设置,比如789.

总线上的器件是开漏输出的半双工通信。

image-20230713135505107

默认总线是上拉电阻拉成高电平。

当器件输出 out 为低电平时,总线导通到接地,总线被拉低(整条总线都被拉低)。江协科技老师举的例子很好,就像公交车上的一根横杆,有人拉住横杆拽下来,整条横杆都被拉低了,其他人都知道“横杆被一个人拉低了,说明有人正在使用总线”。

然后是总线传输数据的方式,SCL SDA 两根总线在何种情况下表示 start stop 0 1 bit?

image-20230713140225426

首先都是 SCL 为高电平时 SDA 的数值才有意义。

SDA 从高到低,表示 start 位。从低到高,表示 stop 位。

start 位后,SDA 高电平表示1,低电平表示0.

发送完 1byte 数据后,总线保持拉高状态。如果接收方把总线拉低了,发送方发现总线1→0了(不是发送方自己拉的,是接收方给他拉下来的,但是发送方能察觉到),说明接收方成功接收了并且拉了拉总线以示“收到”。如果 SDA 还是保持在高电平,说明接收方没有成功收到或者成功发送 ACK。

image-20230713140822834

问题处理

I2C 是一种很简单的主从通信协议了,但是局限性也很多,比如7 bit 的地址线只允许 2^7 个设备;一次顶多两个设备主从通信;一个设备的快慢会影响到整条总线的通信等。

问题1:从设备处理速度太慢了,赶不及在下一个时钟周期接收新数据帧怎么办?

方法:clock stretching, 拉低一段时间 SCL 假装下一个时钟周期还没到。

image-20230713141906054

问题2:多个设备同时发数据冲突了怎么办?

方法:Bus Aribitation,前面我们知道总线被一个设备拉低了,所有设备都能接收到总线拉低的信号。因此如果两个设备同时开始发信息,前面数据一致都无所谓,等到第一次数据不一致的时候,一个设备发送数据0,一个发送数据1,这时 SDA 总线被 DATA2 的0拉低了。

image-20230713142029471

发送 DATA1 数据的设备就明白了:有人同时在和我一起发数据,因此总线不是我预期的1而是被他拉低为0了。那我 quit,你发吧。然后就只有 DATA2 发送的数据了。

问题3:以上发送的数据每次都是 1byte 8bits 很正好。那如果要发送的地址不是 8bits 呢?

方法:少于 8bits 用一些固定的额外的 start 位填充,多于 8bits 的地址用两个 bytes,不够的也是用额外的 start 位填充。

image-20230713143052018

问题3:如果我 master 发完数据,想紧接着再收数据,变成 slave,可行吗?

方法:通过一个 sr 信号,也就是 repeat start 重发 start 位,来标识自己是 read 而不再是 write 了重新开始通信。

image-20230713143601570

编址格式

slave 地址编址有一些固定格式。

image-20230713143744619

0000 000 0:广播,对所有 slave 结点讲话。如果 slave 无视(NACK),就不会参与广播。如果返回 ACK 就参与进来了。不过多个 slave 都返回 ACK 的话 master 是不知道都有谁回应了的。

第二个 byte 发送一些行为相关,比如:start,clear,reset software

编程应用

slave mode:

  • I2C 设备默认工作在 slave mode。
  • 外设时钟在 I2C_CR2 寄存器中编程。频率介于 2kHz~100kHz。
  • 硬件自动等待发过来的 start 和 addr 信息。
  • 如果 addr 信息和 OAR1 中存储的地址相同,说明目标是自己。如果 ACK 位为1,则发送 ack pulse。
  • 设置 ADDR 位,1表示匹配。
  • 如果 ITEVFEN 就是中断事件 flag 为1,则生成中断。
  • TRA 位标明 slave 是 R 还是 T 模式(收 or 发)。
  • BTF 位标识收没收完。

1689255491311

image-20230713214410998

这么说起来还是有点混乱 I2C 到底经历了哪些才顺利发送了数据?

首先,从主模式的概念。master 主模式驱动时钟信号,发起传输;slave 从模式响应传输。

主模式

用于主发送数据的 I2C 传输序列图

发送:

所有 EV 事件都会拉低 SCL,直到相应软件序列执行完成。

S:start 事件。比如CR2 寄存器中设置外设时钟,配置时钟寄存器,上升时钟寄存器,使能 CR1 来启用时钟,CR1 中设置 start 位,等待总线被拉低表示就绪,发送启动信号,并切换为主模式。

EV5:启动事件成功进行,设置 SB 寄存器=1. SB 寄存器=1后才可以进行地址阶段,执行完地址阶段会自动清除 SB 和 EV5 事件。

Address:地址阶段。传输7位地址+1位读写位,然后等待从机的 ack。收到 ack 进入 EV6.

EV6:设置 addr 位=1代表地址阶段顺利执行, master 收到 ack了。清除 EV6 后自动进入 EV8.

EV8:设置 TxE ,准备写入主机要传入的数据。TxE 表示数据寄存器为空可以写入。每次数据写入 DR 都会清空 TxE 和 EV8 事件。写完数据数据传过去了,主机收到 ack 后继续传输。以 BTF=1 表示数据传输的结尾。

void i2c_write(uint8_t address, uint8_t *buffer, int buff_len) {
	int i = 0;
    // Send in sequence: Start bit, Contents of buffer 0..buff_len, Stop
    while (((I2C1->SR2>>1)&1)); // wait until I2C1 is not busy anymore
    I2C_GenerateSTART(I2C1, ENABLE); // Send I2C1 START condition
    // wait for I2C1 EV5 --> Slave has acknowledged start condition
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    // Send slave Address for write then wait for EV6
    I2C_Send7bitAddress(I2C1, address, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    while (i < buff_len){
        I2C_SendData(I2C1, buffer[i]); // send data then wait for EV8_2
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
        i++;
    }
    I2C_GenerateSTOP(I2C1, ENABLE); // send stop bit
}

image-20230714110003657

接收:

前面和 master transmit 都一样。

TxE 改为 RxE 了,=1标识接收到了数据。

master 自己设置 stop 事件后(发送 NACK)停止接收。

void i2c_read(uint8_t address, uint8_t *buffer, int buff_len) {
    int i = 0;
    // Start bit, Contents of buffer from 0..buff_len, sending a NACK
    // for the last item and an ACK otherwise, Stop bit
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5
    // Send slave Address for write then wait for EV6
    I2C_Send7bitAddress(I2C1, address, I2C_Direction_Receiver);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    I2C_AcknowledgeConfig(I2C1, ENABLE); // going to send ACK
    while (i < buff_len - 1){
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7
        buffer[i] = I2C_ReceiveData(I2C1); // get data byte
        i++;
    }
    I2C_AcknowledgeConfig(I2C1, DISABLE); // going to send NACK
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7
    buffer[i] = I2C_ReceiveData(I2C1); // get the last byte
    I2C_GenerateSTOP(I2C1, ENABLE); // send stop
}

从模式

1689259086166

发送:

start 启动事件由 master 发起。从机校验地址并决定是否发送 ack 位。

EV1:设置 addr 位表示地址匹配。

EV3-1:设置 TxE 位,开始传入数据。一直到主机返回 NACK 表示不想再要数据了,或者 AF=1 说明 ack 失败了为止。

1689259113895

接收:

前面到 EV1 和 slave transmit 都一样。

  1. 数据从 DR 寄存器中读。
  2. 读入一个 byte 后,如果 ack 位已经设置,则返回 ack 信息。
  3. RxE 位是接收数据的状态寄存器。
  4. 主机生成停止条件时停止。

异常情况:

总线错误,NACK,仲裁失败,时钟异常超时。

image-20230714110916968

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/752214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玩转代码|Linux中Thread Local Storage(线程局部存储)

目录 pthread的内存结构 __thread pthread specific API __thread和pthread specific API对比 存储区域/寻址方式不同 性能/效率不同 能存储的数据不同 支持的数据个数不同 在C/C程序中&#xff0c;全局变量默认是所有线程共享的&#xff0c;开发者需要处理多线程竞争问…

如何在短时间内提高亚马逊关键词排名?

搜索购买可以在短时间内提高亚马逊关键词排名&#xff0c;操作方法是通过独立买家账号搜索关键词&#xff0c;找到商品&#xff0c;点击购买&#xff0c;提高关键词的相关性和保留率&#xff0c;让关键词排名自然提高&#xff0c;从而达到上首页的目的。不过要操作这一个方法还…

储能协调控制器装置|储能协调控制设备|储能系统功率控制器|源网荷储互动终端这种装置是什么?应用实施方案如何?

什么是储能协调控制器装置|储能协调控制设备|储能系统功率控制器|源网荷储互动终端及其应用实施方案 一&#xff1a;新型电力系统背景 以新能源为主体的新型电力系统是以新能源为供给主体、以确保能源电力安全为基本前提、以满足经济社会发展电力需求为首要目标&#xff0c;以…

Spring - 更简单的存取 Bean 对象(使用注解)

目录 一、类注解是什么 二、使用类注解 存取 Bean 对象 1. 准备工作 2. 所以使用五大类注解的规则&#xff1a; 三、五大类注解之间的关系 1. 首先可以查看 类注解的源码如下图&#xff1a; 2. 为什么需要五个类注解&#xff1f; 3. 为什么使用类注解的方式不能使用原类…

挖矿记录+解决方案:利用GitLab组件对服务器进行挖矿导致CPU占用200%

文章目录 什么是云服务器挖矿?事件记录事件分析产生影响解决方案后期预防什么是云服务器挖矿? 云服务器挖矿是指利用云服务器从事赚取比特币的活动。比特币是一种虚拟数字货币,挖矿是将一段时间内比特币系统中发生的交易进行确认,并记录在区块链上形成新区块的过程。 用于…

青岛大学_王卓老师【数据结构与算法】Week05_06_栈的顺序表示_学习笔记

本文是个人学习笔记&#xff0c;素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享&#xff0c; 另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权&#xff0c;请留言作删文处理。 课程视频链接&#xff1a; 数据结构与算法基础…

【数据结构】之红黑树

红黑树 红黑树的概念红黑树的性质红黑树的插入操作&#xff08;核心&#xff09;情况一&#xff1a;uncle存在且为红情况二&#xff1a;uncle不存在/存在且为黑&#xff08;在同一侧&#xff09;情况三&#xff1a;uncle不存在/存在且为黑&#xff08;在两侧&#xff09;总结 红…

三、学习分类 - 基于图像大小进行分类

天下一半剑仙是我友 谁家娘子不娇羞 我以醇酒洗我剑 谁人说我不风流 1 设置问题 根据图片的尺寸&#xff0c;把图片分为纵向图像和横向图像。这种把图像分成两种类别的问题&#xff0c;就是二分类问题。 纵向图片示例&#xff1a; 横向图片示例&#xff1a; 这样就有了两个…

【Go语言开发】简单了解一下搜索引擎并用go写一个demo

写在前面 这篇文章我们一起来了解一下搜索引擎的原理&#xff0c;以及用go写一个小demo来体验一下搜索引擎。 简介 搜索引擎一般简化为三个步骤 爬虫&#xff1a;爬取数据源&#xff0c;用做搜索数据支持。索引&#xff1a;根据爬虫爬取到的数据进行索引的建立。排序&#xf…

Wsl 错误 0x80004002 解决

wsl2安装教程&#xff1a;https://www.jianshu.com/p/6e7488440db2 我安装的过程中出现了如下错误&#xff1a; 解决办法&#xff1a; 已管理员身份运行Powershell运行以下命令以获取包的全名 Get-AppxPackage |? { $_.Name -like "*WindowsSubsystemforLinux*"…

(33)(33.3) 连接实例

文章目录 前言 33.3.1 嵌入在集体PPM/总信号通道中的RSSI 33.3.2 模拟电压型RSSI被输送到一个专用引脚 33.3.3 PWM类型的RSSI输送到一个专用引脚 前言 以下是典型的 RC 接收机 RSSI 连接方案示例&#xff1a; 33.3.1 嵌入在集体PPM/总信号通道中的RSSI 通常的做法是在一根…

NLog写日志到数据库

需求&#xff1a;NLog写日志到数据库 一、必须要安装&#xff1a; System.Data.SqlClient 二、 NLog配置&#xff1a; <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"http://www.nlog-project.org/schemas/NLog.xsd" …

存css实现动态时钟背景

代码实现 <!DOCTYPE html> <html lang"en"> <head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><title>Title</title><meta name"referrer" content"no-referrer…

Spring的控制翻转(IOC)与依赖注入(DI)

SpringIOC 即 Inversion of Control&#xff0c;缩写为 IOC&#xff0c;就是由 Spring IoC 容器管理对象&#xff0c;而非传统实现中由程序代码直接操控. 使用IOC容器管理bean&#xff08;IOC&#xff09; 在IOC容器中将有依赖关系的bean进行关系绑定 最终达到的目的&#…

【C】回调函数和qsort详解

回调函数概念 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另一 个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;我们就说这是回调函数。回调函数不是由该 函数的实现方直接调用&#xff0c;…

七大排序算法——快速排序,通俗易懂的思路讲解与图解(完整Java代码)

文章目录 一、排序的概念排序的概念排序的稳定性七大排序算法 二、快速排序核心思想Hoare法挖坑法前后指针法(选学) 三、性能分析四、算法优化优化基准的选取优化少量数据时的排序方案优化后的完整代码 五、七大排序算法 一、排序的概念 排序的概念 排序&#xff1a;所谓排序…

基于ChatGPT和私有知识库搭建Quivr项目

准备工作 安装docker和docker-compose申请supabase账号 拉取Quivr代码 git clone https://github.com/StanGirard/Quivr.git 复制.XXXXX_env文件 cp .backend_env.example backend/.env cp .frontend_env.example frontend/.env 更新backend/.env和frontend/.env文件 ba…

靶场的安装

sqli-lab 1.将安装包解压放到WWW目录下 2.修改 db-creds.inc文件里面的数据库的用户名密码为自己的用户名密码 路径&#xff1a;D:\phpStudy_64\phpstudy_pro\WWW\sqli-labs-master\sql-connections\db-creds.inc 3. 更改php版本位5.9版本&#xff0c;不然会报错 4.安装数…

【采用有限元法技术计算固有频率和欧拉屈曲荷载】使用有限元法的柱子的固有频率和屈曲荷载(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Android JNI 异常处理 (十一)

🔥 Android Studio 版本 🔥 🔥 创建包含JNI的类 JNIException.java 🔥 package com.cmake.ndk1.jni;public class JNIException {static {System.loadLibrary("exception-lib");}public native void nativeInvokeJavaException();public native void nativ…