I2C通信¶
学习资料:
前言¶
线与:连接在总线上的设备只要有一个输出低电平(0)总线就为低电平(0),只有全部设备都为高阻态时总线才是高电平(1)
I2C简介¶
I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线
- 两根通信线:SCL(Serial Clock)、SDA(Serial Data)
- 同步,半双工
- 带数据应答
- 支持总线挂载多设备(一主多从、多主多从(可利用“线与”特性来执行时钟同步和总线仲裁))
I2C的硬件电路设计¶
- 所有I2C设备的SCL连在一起,SDA连在一起
设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
我主要学习的是I2C一主多从的模式,所以下面以一主多从的模式(一主 即 MCU(STM32)来当作主机 ,其它设备当作从机)来讲解I2C的硬件电路是如何设计出来的
解释:
-
对于 SCL 时钟线 来说 它是由主机控制的 所以它可以是 开漏输出 亦可以是 推挽输出 都可以 ,但为什么选择了 开漏输出模式 是因为 :多主多从模式下可利用“线与”特性来执行 时钟同步和总线仲裁
-
对于 SDA 时钟线 来说 它是通信数据的线 不仅主机需要它进行 输出数据 还需要 接收从机发送过来的 数据 ,即在在此期间需要频繁的切换GPIO的输入输出模式 还要兼顾 不能在一个设备输出高电平 另一个设备输出低电平 导致的电源短路现象 所以为了防止总线没有协调好而导致此现象的产生 I2C设计是禁止所有设备输出强上拉的高电平 采用 外置弱上拉电阻加开漏输出模式
-
那此时 你可能有所疑惑: 选择开漏输出模式 那岂不是不能输入了 其实然也 不知道你是否还记得 学习GPIO时,我们的STM32输出配置框图中 无论我们选择什么输出模式 都是可以进行输入的 不信?请看下图
STM32数据手册上写到 当I/O端口被配置为输出时
-
施密特触发输入被激活
-
在每个APB2时钟周期,出现在I/O脚上的数据被采样到输入数据寄存器
-
开漏模式时,读输入数据寄存器时可得到I/O口状态 -- 我们软件模拟I2C时就使用到了这个特性
GPIO_ReadInputDataBit
但是我们 硬件读写的时候使用的是复用开漏输出 复用功能输入,直接读写到我们的I2C的移位寄存器中
如果你对GPIO有所遗忘 可以去看我的另一篇关于STM32之GPIO外设 - Sakura_Ji - 博客园 的笔记
-
-
开漏输出模式: 设备输出1时是高阻态,在硬件电路设计图中即SCLKN1OUT/DATAN1OUT断开使引脚浮空,为了避免引脚浮空,通过外置的上拉电阻呈现弱上拉的高电平 但不影响数据的传输;设备输出0时是强下拉低电平
-
所有任何设备在任何时候 是都可以进行输入的 都可以通过一个数据缓冲器或者是施密特触发器,进行输入
通过上文可知:
- 设备在进行输出时: 低电平:强下拉的低电平 高电平: 弱上拉的高电平
- 设备在进行输入时: 可直接输出高电平(相当于高阻态 断开引脚) 然后观察总线的高低电平即可
I2C的软件设计¶
- 主机可以访问总线上的任何一个设备
- 要与那个设备进行通信 主机在起始条件后 需要先发送 该设备的地址
- 所有设备都会对这个地址进行判断,如果和自己的不一样会认为没有访问自己,之后的时序就不管了,如果一样会向主机发送应答,并准备响应之后主机的读写操作
- 同一条的I2C总线上的从机的设备地址要求不能相同
- 从机设备地址在I2C协议标准里分为7位地址和10位地址,7位地址应用最为广泛
- 以7位作为示例:厂商一般规定高4位是固定死的,但低3位是可以通过电路进行改变的,这样地址就可以不同,所以I2C总线可以搭载相同的设备
- 仲裁: 当有多个设备想跟主机通讯时,为防止数据冲突,会采用仲裁的方式决定由哪个设备占用总线。在通讯分点已经说明了一次通讯只能有一个主机和一个从机
I2C最大的一个特点就是有完善的应答机制,从机(主机)接收到主机(从机)的数据时,会回复一个应答信号来通知主机表示“我收到了”。
应答信号: 出现在1个字节传输完成之后,即第9个SCL时钟周期内,此时主机需要释放SDA总线,把总线控制权交给从机,由于上拉电阻的作用,此时总线为高电平,如果从机正确的收到了主机发来的数据,会把SDA拉低,表示应答响应。
非应答信号:当第9个SCL时钟周期时,SDA保持高电平,表示非应答信号。
非应答信号可能是主机产生也可能是从机产生,产生非应答信号的情况主要有以下几种:
- I2C总线上没有主机所指定地址的从机设备;
- 从机正在执行一些操作,处于忙状态,还没有准备好与主机通讯;
- 主机发送的一些控制命令,从机不支持;
- 主机接收从机数据时,主机产生非应答信号,通知从机数据传输结束,不要再发数据了;
I2C的时序机制¶
-
总线空闲状态: SCL和SDK同时处于高电平
-
起始条件: SCL高电平期间,SDA从 高电平 切换到 低电平
-
终止条件: SCL高电平期间,SDA从 低电平 切换到 高电平
-
发送一个字节: SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
-
接收一个字节: SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
-
发送应答:主机在接收完一个字节之后,在下一个 时钟发送一位数据,数据0表示应答,数据1表示非应答
-
接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
I2C的数据帧格式¶
I2C的数据帧格式有:指定地址写,当前地址读,指定地址读
PS:起始位和停止位 只是个状态通知 并不是1位数据 也就是设备感受到总线的变换所以不要把 它们当成 1位数据来对待 它们只是个信号通知
指定地址写¶
对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)
-
总线由空闲状态转为起始位:在SCL高电平的期间,SDA下降沿触发
-
主机控制SDA 发送从机设备地址(7位地址) + 发送 读(1)/写(0)指令(1位):
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
-
主机释放SDA 接收从机的应答位 从机控制SDA :
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当主机释放SDA后 立刻被从机拉下并控制 所以在RA(Receive Ack)处显示的像未被释放过一样
-
主机得到从机的应答 从机释放SDA 主机控制SDA 发送寄存器地址(8位)
- 因为从机要在低电平尽快变化数据(释放SDA),所以SCL的下降沿和SDA的上升沿几乎是同时发生的
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
主机释放SDA 接收从机的应答位 从机控制SDA :
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当主机释放SDA后 立刻被从机拉下并控制 所以在RA(Receive Ack)处显示的像未被释放过一样
-
主机得到从机的应答 从机释放SDA 主机控制SDA 发送数据(8位)
- 因为从机要在低电平尽快变化数据(释放SDA),所以SCL的下降沿和SDA的上升沿几乎是同时发生的
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
主机释放SDA 接收从机的应答位 从机控制SDA :
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当主机释放SDA后 立刻被从机拉下并控制 所以在RA(Receive Ack)处显示的像未被释放过一样
-
主机得到从机的应答 从机释放SDA 主机控制SDA 产生停止条件
- 因为从机要在低电平尽快变化数据(释放SDA),所以SCL的下降沿和SDA的上升沿几乎是同时发生的
- 数据变化:在SCL低电平期间,SDA进行数据变化
- 如果主机想结束通讯 就可以产生停止条件 在停止条件之前 ,先拉低SDA,为后续SDA的上升沿做准备
如果主机想要继续传输 就可以继续发送数据 它的数据会自动写入下一个寄存器地址的位置(单独的记录地址的指针变量会自增 在下文当前地址读中有解释为什么)
数据稳定:在SCL高电平期间,SDA保持不动
-
在SCL高电平的期间,SDA上升沿触发 产生停止位 转向 总线空闲状态
当前地址读¶
对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)
-
总线由空闲状态转为起始位:在SCL高电平的期间,SDA下降沿触发
-
主机控制SDA 发送从机设备地址(7位地址) + 发送 读(1)/写(0)指令(1位):
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
-
主机释放SDA 接收从机的应答位 从机控制SDA :
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当主机释放SDA后 立刻被从机拉下并控制 所以在RA(Receive Ack)处显示的像未被释放过一样
-
主机得到从机的应答 从机继续控制SDA 从机发送数据(8位) -- 数据传输方向 变换
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
那么问题来了 -- 此时从机是从将哪个寄存器的数据 传给主机的呢? 在I2C协议的规定中,在主机进行寻址时,一旦读写标志位给了1,下一个字节要立马转为读的时序,所以主机还来不及指定,我要读那个寄存器,就要开始接收数据了,所以这里没有指定地址这个环节,那从机该发哪一个寄存器的数据呢?
在从机中,所有的寄存器都被分配到了一个线性区域中,并且会有一个单独的记录地址的指针变量,指示着其中的一个寄存器,这个指针上电默认指向0地址,并且每写入一个字节和读出一个字节后,这个指针会自动自增一次,移动到下一个位置
那么在调用当前地址读的时序时,主机没有指定要读那个地址,从机就会返回当前 记录地址的那个指针变量的 指针指向的寄存器的值,举例 :
- 上一步刚刚调用了指定地址写的时序,在0X19的位置写入了0XAA,那么 记录地址的那个指针变量 就会自动加一 移动到 0X1A的位置
- 之后再调用当前地制读的时序,读取的就是0X1A这个地址的寄存器中的值
- 再继续读数据,读取的就是0X1B这个地址的寄存器中的值
- ···
- 以此类推
-
-
从机释放SDA 接收主机的应答位 主机控制SDA 产生停止条件
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当从机释放SDA后 由于主机是非应答 所以总线依旧处于上拉状态 所以在SA(Send Ack)处显示的像未被释放过一样
- 当从机未得到主机的应答时,从机将不会再继续发送给主机数据,由主机控制SDA
- 数据变化:在SCL低电平期间,SDA进行数据变化
- 如果主机想要结束通讯 就可以产生停止条件 在停止条件之前 ,先拉低SDA,为后续SDA的上升沿做准备
如果主机想要继续读取 上面就得应答从机 然后可以继续读取下一个寄存器地址中的数据
数据稳定:在SCL高电平期间,SDA保持不动
-
在SCL高电平的期间,SDA上升沿触发 产生停止位 转向 总线空闲状态
指定地址读¶
对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)
-
总线由空闲状态转为起始位:在SCL高电平的期间,SDA下降沿触发
-
主机控制SDA 发送从机设备地址(7位地址) + 发送 读(1)/写(0)指令(1位):
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
-
主机释放SDA 接收从机的应答位 从机控制SDA :
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当主机释放SDA后 立刻被从机拉下并控制 所以在RA(Receive Ack)处显示的像未被释放过一样
-
主机得到从机的应答 从机释放SDA 主机控制SDA 发送寄存器地址(8位)
- 因为从机要在低电平尽快变化数据(释放SDA),所以SCL的下降沿和SDA的上升沿几乎是同时发生的
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
主机释放SDA 接收从机的应答位 从机控制SDA :
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当主机释放SDA后 立刻被从机拉下并控制 所以在RA(Receive Ack)处显示的像未被释放过一样
-
主机得到从机的应答 从机释放SDA 主机控制SDA 重新起始SR(Start Repeat)
- 因为从机要在低电平尽快变化数据(释放SDA),所以SCL的下降沿和SDA的上升沿几乎是同时发生的
- 数据变化:在SCL低电平期间,SDA进行数据变化
- 产生重新起始条件,从机释放SDA后,主机依旧保持SDA上拉状态,为后续SDA的下降沿做准备
- 那么问题来了 -- 重新起始是什么鬼?为什么这么操作,上文说过 有一个单独的记录地址的指针变量 我们先像那个指定的寄存器地址进行写入操作(但不真正的写入 所以指针不会自增),重新起始,然后进行当前地址读操作,这样不就完美的实现了 指定地址读操作嘛 看不懂去看当前地址读中的举例
- 重新起始相当于另起一个时序,因为读写标志位只能是跟着起始条件的第一个字节,因此想要切换读写操作,只能再启动一次时序即重新起始
- 起始位:在SCL高电平的期间,SDA下降沿触发
-
主机控制SDA 发送从机设备地址(7位地址) + 发送 读(1)/写(0)指令(1位):
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
-
主机释放SDA 接收从机的应答位 从机控制SDA :
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当主机释放SDA后 立刻被从机拉下并控制 所以在RA(Receive Ack)处显示的像未被释放过一样
-
主机得到从机的应答 从机继续控制SDA 从机发送数据(8位) -- 数据传输方向 变换
-
数据变化:在SCL低电平期间,SDA进行数据变化
-
数据稳定:在SCL高电平期间,SDA保持不动
-
-
从机释放SDA 接收主机的应答位 主机控制SDA 产生停止条件
- 从机回复 0是应答 1为非应答
- 由于线与机制,当从机给予应答,从总线的现象上看 当从机释放SDA后 由于主机是非应答 所以总线依旧处于上拉状态 所以在SA(Send Ack)处显示的像未被释放过一样
- 当从机未得到主机的应答时,从机将不会再继续发送给主机数据,由主机控制SDA
- 数据变化:在SCL低电平期间,SDA进行数据变化
- 如果主机想结束通讯 就可以产生停止条件 在停止条件之前 ,先拉低SDA,为后续SDA的上升沿做准备
如果主机想要继续读取 上面就得应答从机 然后可以继续读取下一个寄存器地址中的数据
数据稳定:在SCL高电平期间,SDA保持不动
-
在SCL高电平的期间,SDA上升沿触发 产生停止位 转向 总线空闲状态
STM32之I2C外设¶
STM32内部集成了硬件I2C收发电路,可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能,减轻CPU的负担
支持多主机模型
支持7位/10位地址模式
支持不同的通讯速度,标准速度(高达100 kHz),快速(高达400 kHz)
支持DMA
兼容系统管理总线SMBus协议
10位地址的操作方式:起始位后 发送的第一个字节的 前5位必须是: 11110 然后是2位地址 + 读写位 第二个字节是 后8位地址 所以7位地址的前5位不能是11110
外设引脚:一般都是借用GPIO的复用模式和外界链接起来的,要想使用STM32的硬件电路,就只能使用它规定好的引脚 举例:
I2C引脚 | I2C1 | I2C2 |
---|---|---|
SCL | PB6-->可以重映射到PB8 | PB10 |
SDA | PB7-->可以重映射到PB9 | PB11 |
- 想要发送数据:可以把一字节的数据写到数据寄存器DR,当移位寄存器没有数据移位时(也就是空),这个数据寄存器的值就会进一步转到移位寄存器里,在上一个数据的移位过程中,我们就可以把下一个数据写到数据寄存器DR中等着了,一旦上一个数据移位成功,下一个数据就可以无缝衔接,继续发送了
- 当数据从数据寄存器 转移到 移位寄存器时,就会置状态寄存器 TXE 为1 表示发送数据寄存器为空
- 想要接收数据:输入的数据,一位一位的从引脚 移进 移位寄存器 ,当一个字节的数据接收完成,数据就整体从移位寄存器转到数据寄存器,同时置标志位RXNE为1,表示接收数据寄存器非空,这时我们就可以把数据寄存器DR里的数据都出来了
- PS:可对比串口USART那一章的的框图 -- 你就会发现串口的数据收发 也是由移位寄存器 和 数据寄存器 来实现的,只不过串口USART是全双工有两个数据和移位寄存器。而I2C是半双工只有一个数据和移位寄存器 可参考STM32之USART通信 - Sakura_Ji - 博客园
- 通过控制寄存器的对应位操作,就可以控制什么时候收发数据,对于起始条件,终止条件,和应答位的相关控制电路STM32的框图并没有详细画出,对于软件工程师的我们知道有相关电路可完成此操作就可以了
- 比较器和地址寄存器: 是从机模式使用的,由于STM32是基于可变多主机模型设计的,STM32不进行通信时就是从机模式,既然作为从机就要有从机地址,所以从机地址就可以由自身地址寄存器来指定,这个地址可以自定,然后写入到这个自身地址寄存器中,STM32作为从机被寻址时,可通过比较器来与自身地址寄存器进行比较,如果相同,STM32就可以响应外部主机的召唤。
- STM32可支持同时响应两个从机地址,所以就有自身地址寄存器和双地址寄存器 -- 多主机模式下的,但此次学习是以STM32做为主机,此模式 未待完续
- 帧错误校验(PEC): 当发送/接收一个多字节的数据帧时,硬件可自行执行CRC校验(是一种很常见的数据校验算法,可根据前面的数据就行各种数据的运算,然后会得到一个字节的校验位,附加到数据帧的后面),接收发送都可以启动这个CRC校验,如果数据出错,CRC校验就会通不过,就会置校验错误标置位
I2C之STM32发送流程¶
要学会读懂下发的序列图,要与对应相关寄存器的位进行互动学习,我已将重要的寄存器标志位放在了下方
默认情况下,STM32的I2C接口总是工作在从模式。从从模式切换到主模式,需要产生一个起始条件 也就是将 I2C的控制寄存器I2C_CR1中的START置1
EV可以理解为:组合了好几个标志位的 大标志位
EV5: SB = 1当检测EV5完成后,就可以发送一个字节的从机地址了,从机地址需要写入数据寄存器DR中,当这个字节写入到数据寄存器DR时,硬件电路就会自动将这一个字节转移到移位寄存器中,再把这一个字节发送到I2C的SDA总线上,之后硬件会自动接收应答位并判断,如果没有应答,硬件会置硬件失败的标志位,然后这个失败的标志位可以申请中断来告诉我们
EV6: ADDR = 1 地址发送结束
EV8_1: TXE = 1 移位和数据寄存器都是空,需要我们向数据寄存器写入数据
EV8: TXE = 1 移位寄存器非空,数据寄存器是空,也就是说 我们可以将新的数据写进 数据寄存器了 所以 当EV8产生的时候 也就是我们能将新数据写入到 数据寄存器的时候
EV8_2: TXE = 1; BTF = 1 此时是 移位和数据寄存器都是空,我们没有新数据要继续发送给从机了, BTF = 1字节发送结束
控制寄存器I2C_CR1👇
START:起始条件产生 (Start generation) 软件可以设置或清除该位,或当起始条件发出后或PE=0时,由硬件清除。
在主模式下:
0 : 无起始条件产生;
1:重复产生起始条件。
在从模式下:
0:无起始条件产生;
1:当总线空闲时,产生起始条件。
STOP:停止条件产生 (Stop generation)
软件可以设置或清除该位;或当检测到停止条件时,由硬件清除;当检测到超时错误时,硬件 将其置位。
在主模式下:
0:无停止条件产生;
1:在当前字节传输或在当前起始条件发出后产生停止条件。
在从模式下:
0:无停止条件产生;
1:在当前字节传输或释放SCL和SDA线。
注:当设置了STOP、START或PEC位,在硬件清除这个位之前,软件不要执行任何对 I2C_CR1的写操作;否则有可能会第2次设置STOP、START或PEC位。
ACK:应答使能 (Acknowledge enable)
软件可以设置或清除该位,或当PE=0时,由硬件清除。
0:无应答返回;
1:在接收到一个字节后返回一个应答(匹配的地址或数据)。
PE:I2C模块使能 (Peripheral enable)
0:禁用I 2 C模块;
1:启用I 2 C模块:根据SMBus位的设置,相应的I/O口需配置为复用功能。
注:如果清除该位时通讯正在进行,在当前通讯结束后,I 2 C模块被禁用并返回空闲状态。 由于在通讯结束后发生PE=0,所有的位被清除。
在主模式下,通讯结束之前,绝不能清除该位。
状态寄存器 1(I2C_SR1)👇
SB:起始位(主模式) (Start bit (Master mode))
0:未发送起始条件;
1:起始条件已发送。
– 当发送出起始条件时该位被置’1’。
– 软件读取SR1寄存器后,写数据寄存器的操作将清除该位,或当PE=0时,硬件清除该位。
TxE:数据寄存器为空(发送时) (Data register empty (transmitters))
0:数据寄存器非空;
1:数据寄存器空。
– 在发送数据时,数据寄存器为空时该位被置’1’,在发送地址阶段不设置该位。
– 软件写数据到DR寄存器可清除该位;或在发生一个起始或停止条件后,或当PE=0时由硬件 自动清除。
如果收到一个NACK,或下一个要发送的字节是PEC(PEC=1),该位不被置位。
注:在写入第1个要发送的数据后,或设置了BTF时写入数据,都不能清除TxE位,这是因为 数据寄存器仍然为空。
ADDR:地址已被发送(主模式)/地址匹配(从模式) (Address sent (master mode)/matched (slave mode))
在软件读取SR1寄存器后,对SR2寄存器的读操作将清除该位,或当PE=0时,由硬件清除该 位。
地址匹配(从模式)
0:地址不匹配或没有收到地址;
1:收到的地址匹配。
– 当收到的从地址与OAR寄存器中的内容相匹配、或发生广播呼叫、或SMBus设备默认地址 或SMBus主机识别出SMBus提醒时,硬件就将该位置’1’(当对应的设置被使能时)。
地址已被发送(主模式)
0:地址发送没有结束;
1:地址发送结束。
– 10位地址模式时,当收到地址的第二个字节的ACK后该位被置’1’。
– 7位地址模式时,当收到地址的ACK后该位被置’1’。
注:在收到NACK后,ADDR位不会被置位。
BTF:字节发送结束 (Byte transfer finished)
0:字节发送未完成;
1:字节发送结束。 当NOSTRETCH=0时,在下列情况下硬件将该位置’1’:
– 在接收时,当收到一个新字节(包括ACK脉冲)且数据寄存器还未被读取(RxNE=1)。
– 在发送时,当一个新数据将被发送且数据寄存器还未被写入新的数据(TxE=1)。
– 在软件读取SR1寄存器后,对数据寄存器的读或写操作将清除该位;或在传输中发送一个起始或停止条件后,或当PE=0时,由硬件清除该位。
注:在收到一个NACK后,BTF位不会被置位。 如果下一个要传输的字节是PEC(I2C_SR2寄存器中TRA为’1’,同时I2C_CR1寄存器中PEC 为’1’),BTF位不会被置位。
数据寄存器 1(I2C_DR)👇
DR[7:0]:8位数据寄存器 (8-bit data register)
用于存放接收到的数据或放置用于发送到总线的数据
发送器模式:当写一个字节至DR寄存器时,自动启动数据传输。一旦传输开始(TxE=1),如果 能及时把下一个需传输的数据写入DR寄存器,I 2 C模块将保持连续的数据流。
接收器模式:接收到的字节被拷贝到DR寄存器(RxNE=1)。在接收到下一个字节(RxNE=1)之 前读出数据寄存器,即可实现连续的数据传送。
注:在从模式下,地址不会被拷贝进数据寄存器DR;
注:硬件不管理写冲突(如果TxE=0,仍能写入数据寄存器);
注:如果在处理ACK脉冲时发生ARLO事件,接收到的字节不会被拷贝到数据寄存器里,因此 不能读到它。
I2C之STM32接收流程¶
下放的7位主接收时序,很明显是 当前地址读 的模式,并没有给我们 指定地址读所以还需要我们进行相对应的配置
默认情况下,STM32的I2C接口总是工作在从模式。从从模式切换到主模式,需要产生一个起始条件 也就是将 I2C的控制寄存器I2C_CR1中的START置1
EV可以理解为:组合了好几个标志位的 大标志位
EV5: SB = 1当检测EV5完成后,就可以发送一个字节的从机地址了,从机地址需要写入数据寄存器DR中,当这个字节写入到数据寄存器DR时,硬件电路就会自动将这一个字节转移到移位寄存器中,再把这一个字节发送到I2C的SDA总线上,之后硬件会自动接收应答位并判断,如果没有应答,硬件会置硬件失败的标志位,然后这个失败的标志位可以申请中断来告诉我们
EV6: ADDR = 1 地址发送结束
EV6_1:该事件发生时,其数据1其实还在移位,还没收到数据1,所以并没有标志位,当数据1接收完成,硬件会自动根据我们的配置将应答位发送出去,表示这个时序单元已经结束,说明移位寄存器已经成功移入了一个字节的数据1了,之后将这一个字节的数据1从 移位寄存器 发送给 数据寄存器
EV7:RXNE=1,表示数据寄存器非空,如果STM32对该数据寄存器进行读取,硬件会将RXNE位置零,当然数据还没有被读走的时候,数据2已经可以进入移位寄存器了
EV7_1:当不想在继续读取数据时,需要提前将最后一个读取数据的应答位ACK 写非应答 也就是置0,同时设置终止条件请求STOP
I2C的外设应用¶
MPU6050的介绍¶
MPU6050是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景
-
3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度
-
3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度
MPU6050的参数:
-
16位ADC采集传感器的模拟信号,量化范围:-32768~32767
-
加速度计满量程选择:±2、±4、±8、±16(g)
-
陀螺仪满量程选择: ±250、±500、±1000、±2000(°/sec)
-
可配置的数字低通滤波器
-
可配置的时钟源
-
可配置的采样分频
-
I2C的地址
- 1101000(AD0=0)
- 1101001(AD0=1)
未待完续之更详细的MPU6050的笔记
I2C的实战演习¶
为什么分 软件读写 和 硬件读写 ?
- 软件读写 是完全利用I2C的基本原理 时序来写的 ,也就是说无论使用那个 GPIO口都可以实现本操作,甚至你可以使用其它型号的MCU都可以的,只要逻辑和软件读写的一样,当然还要看一下双方支持最大的引脚接收翻转的频率
- 硬件读写 因为在这里学习的是STM32单片机,而且它内部已经拥有I2C外设,这样很方便快捷我们的操作,所以在了解I2C是什么的基础上我们学习STM32的I2C外设会更加快速方便助我们使用 -- 库函数
软件模拟I2C之MPU6050¶
MyI2C.h
MyI2C.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
|
可以在主函数中使用下面的代码 来检测I2C的代码逻辑是否有误 没有则 MPU6050会传给你一个0应答
MPU6050.h
MPU6050.c
main.c
硬件读写I2C之MPU6050¶
请结合STM32的发送流程和接收流程 进行研究以下代码 会更加的清晰
MPU6050.h
MPU6050.C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
|
main.c
I2C的库函数¶
Table 1. I2C 库函数
函数名 | 描述 | |
---|---|---|
I2C_DeInit | 将外设 I2Cx 寄存器重设为缺省值 | |
I2C_Init | 根据 I2C_InitStruct 中指定的参数初始化外设 I2Cx 寄存器 | |
I2C_StructInit | 把 I2C_InitStruct 中的每一个参数按缺省值填入 | |
I2C_Cmd | 使能或者失能 I2C 外设 | |
I2C_DMACmd | 使能或者失能指定 I2C 的 DMA 请求 | |
I2C_DMALastTransferCmd | 使下一次 DMA 传输为 后一次传输 | |
I2C_GenerateSTART | 产生 I2Cx 传输 START 条件 | |
I2C_GenerateSTOP | 产生 I2Cx 传输 STOP 条件 | |
I2C_AcknowledgeConfig | 使能或者失能指定 I2C 的应答功能 | |
I2C_OwnAddress2Config | 设置指定 I2C 的自身地址 2 | |
I2C_DualAddressCmd | 使能或者失能指定 I2C 的双地址模式 | |
I2C_GeneralCallCmd | 使能或者失能指定 I2C 的广播呼叫功能 | |
I2C_ITConfig | 使能或者失能指定的 I2C 中断 | |
I2C_SendData | 通过外设 I2Cx 发送一个数据 | |
I2C_ReceiveData | 返回通过 I2Cx 近接收的数据 | |
I2C_Send7bitAddress | 向指定的从 I2C 设备传送地址字 | |
I2C_ReadRegister | 读取指定的 I2C 寄存器并返回其值 | |
I2C_SoftwareResetCmd | 使能或者失能指定 I2C 的软件复位 | |
I2C_SMBusAlertConfig | 驱动指定 I2Cx 的 SMBusAlert 管脚电平为高或低 | |
I2C_TransmitPEC | 使能或者失能指定 I2C 的 PEC 传输 | |
I2C_PECPositionConfig | 选择指定 I2C 的 PEC 位置 | |
I2C_CalculatePEC | 使能或者失能指定 I2C 的传输字 PEC 值计算 | |
I2C_GetPEC | 返回指定 I2C 的 PEC 值 | |
I2C_ARPCmd | 使能或者失能指定 I2C 的 ARP | |
I2C_StretchClockCmd | 使能或者失能指定 I2C 的时钟延展 | |
I2C_FastModeDutyCycleConfig | 选择指定 I2C 的快速模式占空比 | |
I2C_GetLastEvent | 返回 近一次 I2C 事件 | |
I2C_CheckEvent | 检查 近一次 I2C 事件是否是输入的事件 | |
I2C_GetFlagStatus | 检查指定的 I2C 标志位设置与否 | |
I2C_ClearFlag | 清除 I2Cx 的待处理标志位 | |
I2C_GetITStatus | 检查指定的 I2C 中断发生与否 | |
I2C_ClearITPendingBit | 清除 I2Cx 的中断待处理位 |
函数 I2C_ Init¶
Table 2. 函数 I2C_Init
函数名 | I2C_Init |
---|---|
函数原形 | void I2C_Init(I2C_TypeDef I2Cx, I2C_InitTypeDef I2C_InitStruct) |
功能描述 | 根据 I2C_InitStruct 中指定的参数初始化外设 I2Cx 寄存器 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | I2C_InitStruct:指向结构 I2C_InitTypeDef 的指针,包含了外设 GPIO 的配置信息参阅 Section:I2C_InitTypeDef 查阅更多该参数允许取值范围 |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
I2C_InitTypeDef structure
参数 I2C_Mode¶
I2C_Mode 用以设置 I2C 的模式。Table 208. 给出了该参数可取的值
Table 3. I2C_Mode 值
I2C_Mode | 描述 |
---|---|
I2C_Mode_I2C | 设置 I2C 为 I2C 模式 |
I2C_Mode_SMBusDevice | 设置 I2C 为 SMBus 设备模式 |
I2C_Mode_SMBusHost | 设置 I2C 为 SMBus 主控模式 |
参数 I2C_DutyCycle¶
I2C_DutyCycle 用以设置 I2C 的占空比。Table 209. 给出了该参数可取的值
Table 4. I2C_DutyCycle 值
I2C_DutyCycle | 描述 |
---|---|
I2C_DutyCycle_16_9 | I2C 快速模式 Tlow / Thigh = 16/9 |
I2C_DutyCycle_2 | I2C 快速模式 Tlow / Thigh = 2 |
注意:该参数只有在 I2C 工作在快速模式(时钟工作频率高于 100KHz)下才有意义。
参数 I2C_OwnAddress1¶
该参数用来设置第一个设备自身地址,它可以是一个 7 位地址或者一个 10 位地址。
参数 I2C_Ack¶
I2C_Ack 使能或者失能应答(ACK),Table 210. 给出了该参数可取的值
Table 5. I2C_Ack 值
I2C_Ack | 描述 | |
---|---|---|
I2C_Ack_Enable | 使能应答(ACK) | |
I2C_Ack_Disable | 失能应答(ACK) |
参数 I2C_AcknowledgedAddress¶
I2C_AcknowledgedAddres 定义了应答 7 位地址还是 10 位地址。Table 211. 给出了该参数可取的值
Table 6. I2C_AcknowledgedAddres 值
I2C_AcknowledgedAddres | 描述 | |
---|---|---|
I2C_AcknowledgeAddress_7bit | 应答 7 位地址 | |
I2C_AcknowledgeAddress_10bit | 应答 10 位地址 |
参数 I2C_ClockSpeed¶
该参数用来设置时钟频率,这个值不能高于 400KHz。
例:
函数 I2C_ Cmd¶
Table 7. 函数 I2C_ Cmd
函数名 | I2C_ Cmd |
---|---|
函数原形 | void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState) |
功能描述 | 使能或者失能 I2C 外设 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | NewState: 外设 I2Cx 的新状态这个参数可以取:ENABLE 或者 DISABLE |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
例:
函数 I2C_ GenerateSTART¶
Table 217. 函数 I2C_ GenerateSTART
函数名 | I2C_ GenerateSTART |
---|---|
函数原形 | void I2C_GenerateSTART(I2C_TypeDef* I2Cx, FunctionalState NewState) |
功能描述 | 产生 I2Cx 传输 START 条件 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | NewState: I2Cx START 条件的新状态 这个参数可以取:ENABLE 或者 DISABLE |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
例:
函数 I2C_ GenerateSTOP¶
Table 218. 函数 I2C_ GenerateSTOP
函数名 | I2C_ GenerateSTOP |
---|---|
函数原形 | void I2C_GenerateSTOP(I2C_TypeDef* I2Cx, FunctionalState NewState) |
功能描述 | 产生 I2Cx 传输 STOP 条件 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | NewState: I2Cx STOP 条件的新状态 这个参数可以取:ENABLE 或者 DISABLE |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
例:
函数 I2C_ AcknowledgeConfig¶
Table 219. 函数 I2C_ AcknowledgeConfig
函数名 | I2C_ AcknowledgeConfig |
---|---|
函数原形 | void I2C_AcknowledgeConfig(I2C_TypeDef* I2Cx, FunctionalState NewState) |
功能描述 | 使能或者失能指定 I2C 的应答功能 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | NewState: I2Cx 应答的新状态 这个参数可以取:ENABLE 或者 DISABLE |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
例:
函数 I2C_ SendData¶
Table 225. 函数 I2C_ SendData
函数名 | I2C_ SendData |
---|---|
函数原形 | void I2C_SendData(I2C_TypeDef* I2Cx, u8 Data) |
功能描述 | 通过外设 I2Cx 发送一个数据 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | Data: 待发送的数据 |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
例:
函数 I2C_ ReceiveData¶
Table 226. 函数 I2C_ReceiveData
函数名 | I2C_ ReceiveData |
---|---|
函数原形 | u8 I2C_ReceiveData(I2C_TypeDef* I2Cx) |
功能描述 | 返回通过 I2Cx 近接收的数据 |
输入参数 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输出参数 | 无 |
返回值 | 接收到的字 |
先决条件 | 无 |
被调用函数 | 无 |
例:
函数 I2C_ Send7bitAddress¶
Table 227. 函数 I2C_ Send7bitAddress
函数名 | I2C_ Send7bitAddress |
---|---|
函数原形 | void I2C_Send7bitAddress(I2C_TypeDef* I2Cx, u8 Address, u8 I2C_Direction) |
功能描述 | 向指定的从 I2C 设备传送地址字 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | Address: 待传输的从 I2C 地址 |
输入参数 3 | I2C_Direction:设置指定的 I2C 设备工作为发射端还是接收端参阅 |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
I2C_Direction
该参数设置 I2C 界面为发送端模式或者接收端模式(见 Table 228.)。
Table 228. I2C_Direction 值
I2C_Direction | 描述 | |
---|---|---|
I2C_Direction_Transmitter | 选择发送方向 | |
I2C_Direction_Receiver | 选择接收方向 |
例:
函数 I2C_CheckEvent¶
函数名 | I2C_CheckEvent |
---|---|
函数原形 | ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT) |
功能描述 | 检查最后一个 I2Cx 事件是否等于传递的事件作为参数。 |
输入参数 1 | I2Cx:其中 x 可以是 1 或 2 以选择 I2C 外设 |
输入参数 2 | I2C_EVENT:指定要检查的事件 |
输出参数 | 无 |
返回值 | 错误状态枚举值: * 成功:最后一个事件等于I2C_EVENT * 错误:上一个事件与I2C_EVENT不同 |
先决条件 | 无 |
被调用函数 | 无 |
函数原型:
函数 I2C_ GetFlagStatus¶
Table 246. 函数 I2C_ GetFlagStatus
函数名 | I2C_ GetFlagStatus |
---|---|
函数原形 | FlagStatus I2C_GetFlagStatus(I2C_TypeDef* I2Cx, u32 I2C_FLAG) |
功能描述 | 检查指定的 I2C 标志位设置与否 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | I2C_FLAG:待检查的 I2C 标志位 参阅 Section:I2C_FLAG 查阅更多该参数允许取值范围 |
输出参数 | 无 |
返回值 | I2C_FLAG 的新状态 1. |
先决条件 | 无 |
被调用函数 | 无 |
- 读取寄存器可能会清除某些标志位
I2C_FLAG
Table 247. 给出了所有可以被函数 I2C_ GetFlagStatus 检查的标志位列表
Table 247. I2C_FLAG 值
I2C_FLAG | 描述 |
---|---|
I2C_FLAG_DUALF | 双标志位(从模式) |
I2C_FLAG_SMBHOST | SMBus 主报头(从模式) |
I2C_FLAG_SMBDEFAULT | SMBus 缺省报头(从模式) |
I2C_FLAG_GENCALL | 广播报头标志位(从模式) |
I2C_FLAG_TRA | 发送/接收标志位 |
I2C_FLAG_BUSY | 总线忙标志位 |
I2C_FLAG_MSL | 主/从标志位 |
I2C_FLAG_SMBALERT | SMBus 报警标志位 |
I2C_FLAG_TIMEOUT | 超时或者 Tlow 错误标志位 |
I2C_FLAG_PECERR | 接收 PEC 错误标志位 |
I2C_FLAG_OVR | 溢出/不足标志位(从模式) |
I2C_FLAG_AF | 应答错误标志位 |
I2C_FLAG_ARLO | 仲裁丢失标志位(主模式) |
I2C_FLAG_BERR | 总线错误标志位 |
I2C_FLAG_TXE | 数据寄存器空标志位(发送端) |
I2C_FLAG_RXNE | 数据寄存器非空标志位(接收端) |
I2C_FLAG_STOPF | 停止探测标志位(从模式) |
I2C_FLAG_ADD10 | 10 位报头发送(主模式) |
I2C_FLAG_BTF | 字传输完成标志位 |
I2C_FLAG_ADDR | 地址发送标志位(主模式)“ADSL” 地址匹配标志位(从模式)“ENDAD” |
I2C_FLAG_SB | 起始位标志位(主模式) |
注意:只有位[27:0]被函数 I2C_ GetFlagStatus 用来返回指定的标志位状态。值对应经计算的寄存器中的标志位位置,该寄存器包含 2 个 I2C 状态寄存器 I2C_SR1 和 I2C_SR2。
例:
函数 I2C_ ClearFlag¶
Table 248. 函数 I2C_ ClearFlag
函数名 | I2C_ ClearFlag |
---|---|
函数原形 | void I2C_ClearFlag(I2C_TypeDef* I2Cx, u32 I2C_FLAG) |
功能描述 | 清除 I2Cx 的待处理标志位 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | I2C_FLAG:待清除的 I2C 标志位参阅 Section:I2C_FLAG 查阅更多该参数允许取值范围 注意:标志位 DUALF, SMBHOST, SMBDEFAULT, GENCALL, TRA, BUSY,MSL, TXE 和 RXNE 不能被本函数清除 |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
I2C_FLAG
Table 249. 给出了所有可以被函数 I2C_ ClearFlag 清除的标志位列表
Table 249. I2C_FLAG 值
I2C_FLAG | 描述 |
---|---|
I2C_FLAG_SMBALERT | SMBus 报警标志位 |
I2C_FLAG_TIMEOUT | 超时或者 Tlow 错误标志位 |
I2C_FLAG_PECERR | 接收 PEC 错误标志位 |
I2C_FLAG_OVR | 溢出/不足标志位(从模式) |
I2C_FLAG_AF | 应答错误标志位 |
I2C_FLAG_ARLO | 仲裁丢失标志位(主模式) |
I2C_FLAG_BERR | 总线错误标志位 |
I2C_FLAG_STOPF | 停止探测标志位(从模式) |
I2C_FLAG_ADD10 | 10 位报头发送(主模式) |
I2C_FLAG_BTF | 字传输完成标志位 |
I2C_FLAG_ADDR | 地址发送标志位(主模式)“ADSL” 地址匹配标志位(从模式)“ENDAD” |
I2C_FLAG_SB | 起始位标志位(主模式) |
例:
函数 I2C_ GetITStatus¶
Table 250. 函数 I2C_ GetITStatus
函数名 | I2C_ GetITStatus |
---|---|
函数原形 | ITStatus I2C_GetITStatus(I2C_TypeDef* I2Cx, u32 I2C_IT) |
功能描述 | 检查指定的 I2C 中断发生与否 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | I2C_IT:待检查的 I2C 中断源 参阅 Section:I2C_IT 查阅更多该参数允许取值范围 |
输出参数 | 无 |
返回值 | I2C_IT 的新状态(SET 或者 RESET)1. |
先决条件 | 无 |
被调用函数 | 无 |
- 读取寄存器可能会清除某些标志位
I2C_IT
Table 251. 给出了所有可以被函数 I2C_ GetITStatus 检查的中断标志位列表
Table 251. I2C_IT 值
I2C_IT | 描述 |
---|---|
I2C_IT_SMBALERT | SMBus 报警标志位 |
I2C_IT_TIMEOUT | 超时或者 Tlow 错误标志位 |
I2C_IT_PECERR | 接收 PEC 错误标志位 |
I2C_IT_OVR | 溢出/不足标志位(从模式) |
I2C_IT_AF | 应答错误标志位 |
I2C_IT_ARLO | 仲裁丢失标志位(主模式) |
I2C_IT_BERR | 总线错误标志位 |
I2C_IT_STOPF | 停止探测标志位(从模式) |
I2C_IT_ADD10 | 10 位报头发送(主模式) |
I2C_IT_BTF | 字传输完成标志位 |
I2C_IT_ADDR | 地址发送标志位(主模式)“ADSL” 地址匹配标志位(从模式)“ENDAD” |
I2C_IT_SB | 起始位标志位(主模式) |
例:
函数 I2C_ ClearITPendingBit¶
Table 252. 函数 I2C_ ClearITPendingBit
函数名 | I2C_ ClearITPendingBit |
---|---|
函数原形 | void I2C_ClearITPendingBit(I2C_TypeDef* I2Cx, u32 I2C_IT) |
功能描述 | 清除 I2Cx 的中断待处理位 |
输入参数 1 | I2Cx:x 可以是 1 或者 2,来选择 I2C 外设 |
输入参数 2 | I2C_IT:待检查的 I2C 中断源 参阅 Section:I2C_IT 查阅更多该参数允许取值范围 |
输出参数 | 无 |
返回值 | 无 |
先决条件 | 无 |
被调用函数 | 无 |
I2C_IT
Table 253. I2C_IT 值
I2C_IT | 描述 |
---|---|
I2C_IT_SMBALERT | SMBus 报警标志位 |
I2C_IT_TIMEOUT | 超时或者 Tlow 错误标志位 |
I2C_IT_PECERR | 接收 PEC 错误标志位 |
I2C_IT_OVR | 溢出/不足标志位(从模式) |
I2C_IT_AF | 应答错误标志位 |
I2C_IT_ARLO | 仲裁丢失标志位(主模式) |
I2C_IT_BERR | 总线错误标志位 |
I2C_IT_STOPF | 停止探测标志位(从模式) |
I2C_IT_ADD10 | 10 位报头发送(主模式) |
I2C_IT_BTF | 字传输完成标志位 |
I2C_IT_ADDR | 地址发送标志位(主模式)“ADSL” 地址匹配标志位(从模式)“ENDAD” |
I2C_IT_SB | 起始位标志位(主模式) |
例:
创建日期: October 2, 2023