【stm32】I2C(二)——Master和Slave之间的协议

目录

I2C协议

空闲状态

Master发送状态和停止状态

Master发送从设备地址

地址说明

Master写数据Slaver读的过程

Master读数据Slaver写的过程

为什么最后一次是NACK?------避免总线竞争

细节问题

设备主从的问题

Master(主设备)

Slave(从设备)

上篇文章了解了I2C如何发送数据的,但是还不够还需要了解I2C发送的数据格式------本质就是你学会了a,b,c,d的字母,但是还没有学单词。

I2C协议

主从设备通信之前默认处于空闲状态。

空闲状态

I2C的空闲状态默认是输出高电平的,因为复用开漏输出,默认N-MOS管都是断开的,因此输出高电平。

不管是通信开始还是结束,输出的都是高电平,总是处于空闲状态。

Master发送状态和停止状态

根据上篇文章,当SCL保持高电平的时候,可以选择 获取SDA数据,低电平的时候,不允许获取SDA的数据。

但是,这里接收方为了区分SDA发送数据的起始位在哪里,以及停止位在哪里,就产生了差异。

当SCL保持高电平的时候,SDA产生高到低 电平的变化------代表告诉接收方我要开始发数据了。

当SCL保持高电平的时候,SDA产生低到高 电平的变化------代表告诉接收方我要结束发数据了。

细节:在SCL是高电平的情况下,接收方获取的数据有四种情况高到低,0,1,低到高,分别代表起始条件,低电平,高电平,停止条件

Master发送从设备地址

由于从设备有多个,因此为了确定哪一个从设备,I2C的制造厂商会统一一个地址区分多个不同的从设备。

从设备的地址数据一般由7个或者10个比特位组成,一般情况下是7个,下面都是以7个举例说明。

下面是发送0x50,的样例

地址说明

这个地址中,由7位组成,其中最高比特位用不到,因此整体左移1位,去掉了最高位。

前七位是地址数据------决定了你要通信哪个I2C从设备。

其中第八位比特位决定了这个数据是读(1)的还是写(0)的。

为了让发送方知道接收方已经收到数据了,再第九位比特位又多了一个叫做ACK------应答,会主动拉低点位。

因此这个地址数据处理相应的地址以外,还有读写比特位,应答比特位。

其中这个应答位有两种情况,一个是ACK,一个是NACK。

ACK:表示数据成功接收。

NACK:可能表示接收方未准备好、地址不匹配、接收失败或读取结束信号等,具体后续会详细介
绍。

关于ACK和NACK的细节:

I2C是同步可靠性通信,需要应答保证可靠性(这里可靠性理解为接收方不管有没有接收数据,都会应答,跟数据有没有错误没有关系)

应答ACK和NACK都是通过SDA传递的,通过将SDA线拉低,这表示ACK应答,保持SDA线为高电平,这表示无应答。

接收方接收到了ACK,可以传输,但是怎么回馈给发送方的?

接收方在发送方发完8位数据后的第9个SCL时钟周期,主动拉低SDA线,发送方在第9个SCL高电平期间采样SDA,读到低电平就表示ACK。

Master写数据Slaver读的过程

步骤 谁发 内容 SCL周期 说明
第1步 Master 起始条件 --- SCL高时,SDA高→低
第2步 Master 7位地址 + 0(写) 8位 MSB先发,0x50<<1|0 = 0xA0
第3步 Slave ACK 第9位 从机拉低SDA
第4步 Master 数据0 8位 MSB先发
第5步 Slave ACK 第9位 从机拉低SDA
... ... ... ... 重复发送多个字节
第m步 Master 数据n 8位 最后一个字节
第m+1步 Slave ACK 第9位 从机拉低SDA
第m+2步 Master 停止条件 --- SCL高时,SDA低→高

每个字节后必须跟1位ACK,最后以停止条件结束。

最初的问题:SDA在停止条件之前,怎么保证是低电平?

发送方在发起停止条件之前,会主动把SDA拉低,确保停止条件有"低→高"的跳变。

Master读数据Slaver写的过程

场景:

Master:MCU,主动发起通信,产生SCL。

Slaver:EEPROM,被动响应,提供数据。

这里和Master写的情况不一样,EEPROM内部有存储地址,Master要先写一个内部地址,再读数据。

步骤 谁发 内容 SCL周期 说明
第1步 Master 起始条件 --- SCL高时,SDA高→低
第2步 Master 7位地址 + 0(写) 8位 0x50<<1|0 = 0xA0
第3步 Slave ACK 第9位 从机拉低SDA
第4步 Master 要读的内部地址 8位 比如0x00
第5步 Slave ACK 第9位 从机拉低SDA
第6步 Master 重复起始条件 --- 不释放总线,再发起始
第7步 Master 7位地址 + 1(读) 8位 0x50<<1|1 = 0xA1
第8步 Slave ACK 第9位 从机拉低SDA
第9步 Slave 数据0 8位 Slave发数据
第10步 Master ACK 第9位 Master拉低SDA,表示继续读
... ... ... ... 继续读多个字节
第m步 Slave 数据n 8位 最后一个字节
第m+1步 Master NACK 第9位 Master不拉低,表示读完了
第m+2步 Master 停止条件 --- SCL高时,SDA低→高

为什么最后一次是NACK?------避免总线竞争

bash 复制代码
如果Master发ACK:
  → Slave认为Master还要继续读
  → Slave继续发下一个数据
  → 同时Master想发停止条件
  → 两个设备同时控制SDA → 冲突

如果Master发NACK:
  → Slave知道Master读完了
  → Slave释放SDA
  → Master发停止条件
  → 不冲突

I2C 收发不对称:Master 写时没问题,Master 读时 SDA 归 Slave,Master 想发停止会和 Slave 抢 SDA。解决办法是约定 NACK:Master 读够了就发 NACK,让 Slave 释放 SDA,然后 Master 发停止条件。

细节问题

1、Master 接收数据会来不及吗?------一般不会

  • SCL 时钟信号由 Master 产生

  • Master 掌管数据发送的"节奏"

  • Slave 只是在这个节奏下发送数据

如果 Master 真的需要更多时间处理数据,它也可以用时钟拉伸:

  • Master 拉低 SCL,强制暂停

  • 处理完再释放 SCL,继续接收

2、从设备怎么知道主机要读取什么数据?

很多时候,在发完从设备地址后,还会再发操作码或二级地址,然后才进行数据读取。

因为需要先指定读什么数据、在哪里读 ,这就是应用层面的协议约定。

设备主从的问题

Master = 主导通信过程的设备。

Slave = 被动响应的设备。

能读写数据和主导通信过程是两码事。

Master(主设备)

职责 说明
发起通信 产生起始和停止条件
产生时钟 控制 SCL 线
寻址从设备 发送从设备地址
控制读写方向 发读写位(0写/1读)
主导整个过程 什么时候开始、什么时候结束,由它决定

典型设备: MCU、CPU、FPGA

Slave(从设备)

职责 说明
被寻址 等待 Master 发地址
响应命令 地址匹配后发 ACK
被动收发数据 在 Master 的时钟节奏下收发
不能主动发起通信 只能等 Master 来找它

典型设备: 传感器、EEPROM、RTC、ADC/DAC、IO扩展芯片

能读写 ≠ 是 Master

总结:Master 是主导通信过程的设备,负责发起通信、产生时钟、发送地址、控制读写方向。Slave 是被动响应的设备,但 Slave 也能读写数据。能读写数据和主导通信是两码事,谁主导通信谁就是 Master。角色可配置,可互换

相关推荐
硅基手札1 小时前
【串口技术系列文档 04】UART协议深度解析
驱动开发·stm32·单片机·嵌入式硬件·mcu·计算机外设
sramdram1 小时前
预付费电能表BLE蓝牙MCU方案
单片机·嵌入式硬件·ble蓝牙·蓝牙mcu·蓝牙mcu方案
weixin_690654742 小时前
龙迅#LT7911EXS 高性价比IC,功能适用于HDMI/DP/TPYE-C转单PORT MIPICSI/DSI ,分辨率高达4K60HZ。
嵌入式硬件·音视频·信号处理
Zw-awa2 小时前
陀螺小车传奇之00011000
c语言·stm32
Zhang.Yi2 小时前
STM32-BKP和RTC
stm32·嵌入式硬件·实时音视频
Yiran_G2 小时前
LoRa模块休眠后如何快速恢复通信?低功耗终端唤醒与数据交互实践
嵌入式硬件·物联网
意法半导体STM323 小时前
【官方原创】LAT1724 STM32CubeIDE for VSCode 修改链接文件中的起始地址无效?
vscode·stm32·单片机·嵌入式硬件·mcu·stm32cube
BSD_HY4 小时前
嵌入式薄膜开关中断去抖:中断优先级分层实战策略
单片机·嵌入式硬件·薄膜开关·源头工厂·薄膜按键
Zw-awa15 小时前
八路循迹模块的 DO:先让小车沿着线跑起来
stm32