I2C(smbus、pmbus)和SPI协议分析

本文详细介绍了I2C和SPI两种常用低速外部总线的技术特点及应用场景,对比了它们之间的主要区别,包括数据传输方式、时序控制等,并探讨了SMBUS和PMBUS等基于I2C的扩展协议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

I2C和SPI作为两种非常常用的低速外部总线,已经不是什么新新技术了。 
有些知识点,明白了,一段时间不用了,又忘记了。所以决定乘最近正好碰过这两个东西,还是写下来以备后患。

I2C

I2C是以前的飞利浦半导体制定的标准,也就是如今的NXP。

I2C总线由一条数据线(SDA)和一条时钟线(SCL)组成。设备分主从,主设备提供时钟,并发起操作。 
这里写图片描述

看一下这张I2C协议必须和可选的功能表。最简单的模式的话,只需要实现4个功能,start、stop、ack、7bit address。 
这里写图片描述

当scl为高时,sda下拉表示start。当scl为低时,sda上拉表示stop。 
这里写图片描述

根据下面这个图,我们来讨论这4个基本功能。

  • master控制sda、scl:发起一个start标记
  • master控制sda、scl:start之后的1-7位表示的是slave设备的7bit address
  • master控制sda、scl:第8位表示是读(1)还是写(0)操作,所以我们其实可以把7bit address和这1bit读写位结合起来当成一个byte。
  • master控制scl,slave控制sda:slave强制拉低sda来表示第9位为ack

这里写图片描述

分析好了这第一个byte的内容,就可以继续后面更复杂的了。这个时序一共进行了2个byte的写操作。 
- master控制sda、scl:start 
- master控制sda、scl:7位地址 
- master控制sda、scl:1位写 
- master控制scl,slave控制sda:slave ack 
- master控制sda、scl:1字节数据 
- master控制scl,slave控制sda:slave ack 
- master控制sda、scl:1字节数据 
- master控制scl,slave控制sda:slave ack 
- master控制sda、scl:stop 
这里写图片描述

再看个读操作的 
- master控制sda、scl:start 
- master控制sda、scl:7位地址 
- master控制sda、scl:1位读 
- master控制scl,slave控制sda:slave ack 
- master控制scl,slave控制sda:1字节数据 
- master控制sda、scl:master ack 
- master控制scl,slave控制sda:1字节数据 
- master控制sda、scl:master ack 
- master控制sda、scl:stop 
这里写图片描述

纯粹的读和纯粹的写我们都会了,下面就要读写混合了。最常见的场景就是通过I2C从设备那读取某个寄存器的值。 
- master控制sda、scl:start 
- master控制sda、scl:7位地址 
- master控制sda、scl:1位写 
- master控制scl,slave控制sda:slave ack 
- master控制sda、scl:1字节数据 
- master控制scl,slave控制sda:slave ack 
- master控制sda、scl:start 
- master控制sda、scl:7位地址 
- master控制sda、scl:1位读 
- master控制scl,slave控制sda:slave ack 
- master控制scl,slave控制sda:1字节数据 
- master控制sda、scl:master ack 
- master控制sda、scl:stop 
这里写图片描述

基本功能的I2C介绍就这些了,但是刚才说到I2C还有许多的可选功能,譬如clock stretching功能,这次就遇到一个bug和这个功能有关。

我们再来看看刚才看过的这个图,在第一个byte传输完之后的一段时间内,scl为低。为什么会出现这种情况那?其实不一定是在第一个字节之后,也可能是master要从slave那读取某个寄存器的值,第一个字节的slave address发过去了,然后第二个字节的寄存器地址又发过去了,后面就该slave来返回一个byte的数据了。但是可能这个数据并不是那么简单的得到的,slave可能会先进入中断,然后做一些计算才能得到要返回的值,而这个计算又比较耗时。那slave可以强制拉低scl来表示现在我在忙,要等我做完事情了才可以继续返回数据。假如slave有这种功能,而master又不支持,那就完蛋了,数据全乱了。幸好,我们的master是CPLD的,通过修改支持了这个功能,操作就正常了。 
这里写图片描述

SMBUS

SMBUS是一种基于I2C而扩展出来的协议。有一些更为复杂的操作,但是原理都还是基于I2C的。 
这里写图片描述

这里写图片描述

这里写图片描述

PMBUS

PMBUS是基于SMBUS,定义了很多和电源管理相关的命令。在物理传输上,和SMBUS是完全一致的。

SPI

SPI有四根线,一根时钟,一根收数据,一根发数据,一根片选。当有多个设备时,他就需要多根片选,所以相比I2C而言,布线更为复杂。 
这里写图片描述

SPI只规定了如何收发数据,但是数据的具体格式含义并没有定义。譬如在I2C中跟在7位地址后面的1位表示读写,所有设备都需要遵循。但是SPI不是这样,每个slave都有自己定义的数据格式,各不相同。我们先看看下面这个例子。master发送的第一个字节里01表示写,而05表示读。根据第一个字节的不同,slave会做出不一样的响应。 
这里写图片描述 
这里写图片描述 
而我还见过一种是slave规定,master发给slave的前两个字节代表寄存器的地址,但是0-15位的第15位不当地址来用,而当读写位来用,但是我找不到这个例子的时序图了。我举这个例子是想说明SPI传输数据必须要根据slave设备的timing来,不可想当然。

<think>好的,用户现在想了解I2C通讯协议的工作过程步骤。首先,我需要回顾之前提供的关于MPU6050的内容,特别是涉及到I2C的部分。之前提到MPU6050支持I2CSPI接口,其中I2C的标准模式是100kHz,快速模式是400kHz。用户之前的问题是关于MPU6050的参数特性,而现在转向了I2C协议的具体过程。 用户可能正在开发使用MPU6050的项目,需要实际通过I2C与传感器通信,所以需要详细步骤。他们可能已经看过数据手册,但需要更清晰的协议流程说明。另外,用户提供的引用材料中提到了I2C的基本原理、SMBusPMBus的区别,以及数据传输的步骤,比如起始条件、停止条件等。这些信息需要整合到回答中,但要注意引用标记。 接下来,我需要确保回答结构清晰,分步骤讲解I2C的工作过程,同时结合MPU6050的实际应用,比如如何初始化、读写寄存器等。可能需要举出代码示例,比如之前MPU6050的C语言初始化代码,但用户现在可能更关注协议本身,而不仅仅是代码。 还要注意用户的中文要求,以及正确使用LaTeX格式,比如行内公式用$...$,独立公式用$$...$$。例如,在讲解时钟频率时,可以提到I2C的速率如$100\ \text{kHz}$或$400\ \text{kHz}$。同时,用户要求生成相关问题,这些问题需要围绕I2C的应用、错误处理、与其他协议的区别等方面展开。 需要检查是否引用了用户提供的引用[1][2],比如在讲解起始停止条件时引用[2],在讨论协议特点时引用[1]。确保每个引用自然融入内容,并在段末标注[^1]或[^2]。此外,要确认之前的回答中是否有相关的引用编号,避免重复或冲突,比如之前的回答已经引用了[^1]、[^2]、[^3],所以新的引用应继续编号,但根据用户提供的引用,现在需要引用[^1][^2],可能需要调整以避免混淆。 最后,确保回答真实可靠,符合I2C标准协议,并结合MPU6050的实际案例,帮助用户将理论应用到实际项目中。例如,在读写步骤中,可以提到MPU6050的寄存器地址读写操作,如初始化配置寄存器的例子。同时,注意用户可能需要排除常见问题,比如ACK信号处理、时钟同步等,所以相关问题中可以包含这些方面。</think>### I2C通信协议的工作过程与步骤详解 I2C(Inter-Integrated Circuit)是一种**同步、半双工、主从式**的串行通信协议,仅需两条信号线(SDA、SCL)即可实现多设备通信。以下流程基于I2C Primer规范[^1],结合MPU6050等实际应用场景说明其工作过程: --- #### 一、硬件基础 - **信号线** - **SDA(Serial Data)**:双向数据线 - **SCL(Serial Clock)**:主设备控制的时钟线 - **设备角色** - **主设备(Master)**:发起通信并控制时钟(如MCU) - **从设备(Slave)**:响应主设备命令(如MPU6050,地址$0x68$或$0x69$) --- #### 二、通信核心步骤 1. **起始条件(Start Condition)** - **触发方式**:SCL为高电平时,SDA从高电平跳变到低电平 - **作用**:标志通信开始,主设备获取总线控制权[^2] - 示例:MPU6050初始化时,主控MCU发送起始信号 2. **地址帧传输(Slave Addressing)** - **格式**:7位从机地址(如MPU6050的$0x68$)+ 1位读写标志(0:写,1:读) - **数据帧结构**: $$ \text{地址字节} = (\text{7位地址} \ll 1) | \text{R/W位} $$ - **ACK响应**:从机在第9个时钟周期拉低SDA确认 3. **数据传输(Data Transfer)** - **写模式**:主设备发送控制命令或寄存器地址(如配置MPU6050的采样率寄存器`0x19`) - **读模式**:主设备接收从机数据(如读取MPU6050的加速度计原始值) - **单位数据帧**:每8位数据后跟随1位ACK/NACK 4. **停止条件(Stop Condition)** - **触发方式**:SCL为高电平时,SDA从低电平跳变到高电平 - **作用**:释放总线,结束本次通信[^2] --- #### 三、完整通信流程示例(以MPU6050读操作为例) 1. 主设备发送**起始条件** 2. 发送**从机地址 + 写标志**($0x68 \ll 1 | 0 = 0xD0$) 3. 发送**目标寄存器地址**(如加速度计数据寄存器`0x3B`) 4. 重新发送**起始条件**(重复起始条件,避免总线释放) 5. 发送**从机地址 + 读标志**($0x68 \ll 1 | 1 = 0xD1$) 6. 连续读取**6字节数据**(加速度计X/Y/Z轴高、低字节) 7. 主设备发送**NACK**终止读取,最后发送**停止条件** --- #### 四、关键时序特性(以标准模式为例) | 参数 | 值 | |---------------------|-------------------------| | 时钟频率 | $100\ \text{kHz}$ | | 起始条件保持时间 | $>4.0\ \mu\text{s}$ | | 数据建立时间 | $>250\ \text{ns}$ | | 停止条件释放时间 | $>4.7\ \mu\text{s}$ | --- #### 五、常见问题与解决方法 - **无ACK响应**:检查从机地址是否正确、电源连接或总线冲突 - **时钟同步**:多主设备场景需通过SCL线“线与”逻辑仲裁 - **信号干扰**:总线增加上拉电阻(典型值$4.7\ \text{k}\Omega$) --- #### 六、MPU6050的I2C应用代码片段(STM32 HAL库) ```c // 写入配置寄存器(示例:设置采样率) uint8_t regAddr = 0x19; // SMPRT_DIV寄存器 uint8_t data = 0x07; // 分频值7 → 125Hz采样率 HAL_I2C_Mem_Write(&hi2c1, 0xD0, regAddr, I2C_MEMADD_SIZE_8BIT, &data, 1, 100); // 读取加速度计数据 uint8_t buffer[6]; HAL_I2C_Mem_Read(&hi2c1, 0xD1, 0x3B, I2C_MEMADD_SIZE_8BIT, buffer, 6, 100); int16_t AX = (buffer[0] << 8) | buffer[1]; // X轴数据合成 ``` --- ### 相关问题 1. 如何通过I2C检测MPU6050的设备地址是否有效? 2. I2C通信中如何处理多个主设备的总线仲裁? 3. 为什么MPU6050的I2C总线需要上拉电阻?如何选择阻值? : I2C Primer协议规范与功能特性 [^2]: I2C起始/停止条件与数据传输时序要求
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值