news 2026/9/16 7:10:11

一文读懂 SPI 总线:时序原理、电气特性与驱动开发全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一文读懂 SPI 总线:时序原理、电气特性与驱动开发全解析

文章摘要

SPI(Serial Peripheral Interface)是嵌入式开发中最常用的高速通信总线之一,也是大厂面试的高频考点。本文从通信时序、电气特性、驱动开发三个层面,系统梳理 SPI 的核心原理与工程实践,涵盖 CPOL/CPHA 四种模式、边发边收机制、MISO 三态问题、信号完整性设计,以及硬件/软件 SPI 的驱动实现与参数配置等关键内容,帮助你在面试与日常开发中真正做到"知其然,更知其所以然"。

文章目录

  • 文章摘要
  • 本栏系列文章
  • 其他专栏精品文章
  • 前言
  • 一、SPI 基础概念与时序
    • 1.1 SPI 是什么
    • 1.2 边发边收
    • 1.3 SPI 时序:CPOL 与 CPHA
    • 1.4 边沿读取与 M/LSB
    • 1.5 建立时间与保持时间
  • 二、电气属性与硬件设计
    • 2.1 电气模型
    • 2.2 拓扑结构
    • 2.3 硬件设计核心注意事项
      • (1)走线长度(最重要)
      • (2)信号完整性(Signal Integrity)
      • (3)CS(片选)设计
      • (4)MISO 三态问题(非常关键)
      • (5)上拉
      • (6)地线问题
      • (7)电平匹配(非常重要)
  • 三、驱动开发与调试
    • 3.1 硬件 SPI 与软件 SPI
    • 3.2 硬件 SPI 初始化
    • 3.3 软件 SPI 初始化
    • 3.4 附:MCU 外设 API 设计思路
  • 总结

本栏系列文章

学透CANFD看这个就行(四): 错误帧、位填充、采样点与通信负荷

其他专栏精品文章

CSDN高赞项目:工程训练竞赛之垃圾分类垃圾桶

前言

SPI 和 IIC 几乎是一定会被问到的两门总线协议,而 SPI 又因为"模式多、速率高、坑更多",考察的深度往往比 IIC 更上一层。

SPI 看起来"只是四根线",但真正能讲清楚的人并不多:

  • 你知道 CPOL 和 CPHA 到底分别决定什么吗?四种模式能否张口就画出来?
  • 为什么读数据时也要发一个"空字节"?
  • 多从机共线时 MISO 为什么要三态?信号反射了怎么处理?

这篇文章结合我自己的工程经验,把 SPI 的知识体系完整梳理出来,重点覆盖面试中容易被追问的几个方向:

  • 时序层面:CPOL/CPHA 四种模式、边发边收、M/LSB、建立/保持时间;
  • 电气层面:推挽驱动、走线长度、信号完整性、MISO 三态、电平匹配;
  • 驱动层面:硬件 SPI 与软件 SPI 的初始化、参数结构体配置、API 设计思路。

无论你是正在备战嵌入式面试的求职者,还是希望系统巩固 SPI 基础的同学,相信这篇文章都能帮你建立起完整的知识框架。


一、SPI 基础概念与时序

1.1 SPI 是什么

SPI(Serial Peripheral Interface)是 MCU 和外设之间的一种同步串行通信方式。它的核心逻辑是:

主机发时钟,从机跟着时钟一位一位收发数据。

与 IIC 不同的是,SPI 通信不是靠"地址"找设备,而是靠 CS 片选线找设备

SPI 由四根信号线组成:

信号线含义方向
SCLK时钟线主机输出
MOSI主机发送、从机接收主 → 从
MISO从机发送、主机接收从 → 主
CS片选线主机输出

1.2 边发边收

SPI 的一个显著特点是边发边收:哪怕你只是想读数据,通常也要发送一个空字节(比如0xFF0x00),用来产生时钟

在驱动库封装时,可以把CS 操作单独封装,尽量不与字节交换耦合,这样在多从机场景下复用性更好。

例如,MCU 要给外设发送0x9F,一次完整的通信流程是:

CS 拉低 -> MOSI 发送 0x9F -> SCLK 输出 8 个时钟 -> MISO 返回 1 个字节 -> CS 拉高

1.3 SPI 时序:CPOL 与 CPHA

SPI 的时序本质只控制两件事:
-时钟空闲时是高还是低(CPOL)
-在第几个边沿采样数据(CPHA)

其中:
-CPOL(Clock Polarity,时钟极性)决定"时钟初始状态";
-CPHA(Clock Phase,时钟相位)决定"在上升沿还是下降沿读数据"。

主机同样也是在边沿进行数据发送的。
每个时钟都有两个边沿(上升沿、下降沿),SPI 时钟只能在边沿读数据。当 CPOL = 0 时,第一个边沿为上升沿。

CPOL 取值

CPOL时钟空闲状态
0空闲时 SCLK = 0(低电平)
1空闲时 SCLK = 1(高电平)

CPHA 取值

CPHA数据采样时刻
0第一个边沿采样
1第二个边沿采样

由 CPOL 与 CPHA 组合出四种工作模式

模式CPOLCPHA时钟空闲电平采样边沿数据变化边沿
Mode 000上升沿(第 1 边沿)下降沿
Mode 101下降沿(第 2 边沿)上升沿
Mode 210下降沿(第 1 边沿)上升沿
Mode 311上升沿(第 2 边沿)下降沿

记忆口诀:CPOL 看空闲电平,CPHA 看采样在第几个边沿。Mode 0(CPOL=0, CPHA=0)最常用,也是相对最稳定的一种配置。

1.4 边沿读取与 M/LSB

SPI 不是一次把整个字节发出去,而是按 bit 发送与读取。SPI 更像一个"移位寄存器接口",按照 CLK 进行移入移出数据,因此提供 M/LSB 配置。
-MSB(Most Significant Bit first):高位在前;
-LSB(Least Significant Bit first):低位在前。

通常使用MSB 模式,且需要注意:
- 如果是主从 MCU 通信,M/LSB 必须设置一致;
- 如果从机是传感器,数据手册会标注它属于 M/LSB 哪一种。

对比 I2C:I2C 协议本身就规定 MSB 模式(没有 M/LSB 配置选项),而 SPI 提供可配置选项。

关于采样边沿的深入理解
CPHA 决定在第几个边沿进行采样,这个"采样"不仅代表主机对从机数据的采样,也包含从机对主机数据的采样。因此在另一个边沿开始时,主机与从机将对 MISO 与 MOSI 进行数据更新;理想情况下,MOSI 与 MISO 的数据会从"准备数据的边沿"一直维持到"下一个准备数据的边沿"。

1.5 建立时间与保持时间

  • 建立时间(Setup Time):采样之前,数据必须提前稳定的最短时间。在 SPI 里的意义是——上升沿之前的一段时间,MOSI 必须已经稳定
  • 保持时间(Hold Time):采样之后,数据还必须继续保持稳定的最短时间。即采样之后的一小段时间内,数据必须保持不变。

SPI 数据正确的本质:发送端在一个边沿改变数据,使数据在另一个边沿采样时满足 setup/hold 时间,从而保证采样点处的数据是稳定的逻辑电平。


二、电气属性与硬件设计

2.1 电气模型

SPI 的本质是推挽高速数字信号 + 同步时钟总线,即 MOSI / SCLK 是推挽驱动(区别于 IIC 的开漏 + 上拉)。
由于是推挽驱动,SPI 可以跑得很快:

速率说明
几 MHz ~ 20 MHz常规场景
50 MHz较高速度
100+ MHz短线等严格条件下可达

但因为 SPI 是单端对地信号,抗干扰能力一般。

2.2 拓扑结构

除主从机一对一外,SPI 常见的拓扑是总线(CLK、MOSI、MISO)被多从机共享,CS 用于独立控制各个从机
例如出现 8 路一样的 ADC 时,如果采样率允许,可以使用软件 SPI,甚至可以共用 MOSI、CLK、CS,然后各个设备回传的 ADC 数据分别走各自的 MISO

关键点:如果存在多个从机共用 MISO 的情况,MISO 必须处于三态(高阻)

2.3 硬件设计核心注意事项

(1)走线长度(最重要)

速率走线要求
低速(<1 MHz)可以几十 cm,板上随便走
中速(5~20 MHz)走线尽量短、不要绕远、避免跨分割地
高速(>50 MHz)控制阻抗、走线等长(可选)、加地参考层

(2)信号完整性(Signal Integrity)

边沿太快会出现信号反射,导致波形振铃、过冲、下冲。解决方法:

  • 串联电阻MCU ---[22Ω~47Ω]--- SPI 线,降低上升沿速度、抑制反射;
  • 缩短走线:SPI 的第一优化永远是"缩短距离";
  • 增加地平面:SPI 参考地必须完整,GND plane 必须连续,避免跨分割。

(3)CS(片选)设计

  • CS 必须使用独立 GPIO
  • CS 拉低后必须稳定一段时间,不能乱跳。

(4)MISO 三态问题(非常关键)

多从机状态下,只有一个从机能驱动 MISO,其他从机都必须是高阻态

(5)上拉

  • MOSI / SCLK不需要上拉(推挽驱动);
  • CS需要上拉(防止上电误触发)。

(6)地线问题

SPI 是高速单端信号,必须保证:

  • MCU 和从机 GND共地
  • 地线低阻抗;
  • 不要"长回流路径"。

(7)电平匹配(非常重要)

MCU 通常是 3.3V,而从机可能是 1.8V 或 5V,需要:

  • 使用电平转换芯片;
  • 或确认 IO 是tolerant IO(容忍电平)

三、驱动开发与调试

3.1 硬件 SPI 与软件 SPI

SPI 驱动也可以划分成两类:

  1. 硬件 SPI:借助 MCU 片上的 SPI 外设实现;
  2. 软件 SPI:通过控制 GPIO 实现。

无论硬件 SPI 还是软件 SPI,驱动部分核心都可划分成:初始化部分、写字节、读字节

3.2 硬件 SPI 初始化

基本流程为:

  1. 使能 SPI,初始化 GPIO,打开 AF 时钟,打开 SPI 时钟;
  2. 处理重映射相关 GPIO(封装时考虑用弱函数处理这部分);
  3. 复位 SPI,初始化 SPI 参数,使能 SPI。

芯片固件中的 SPI 初始化一般基于**「结构体 + 初始化函数」**,通常需要配置以下参数:

① 传输模式:用于 MCU 进一步裁剪 SPI 通信模式,常见模式如下:

模式说明
全双工同时收发(最常用)
全双工只接收仍需初始化 MOSI,只是硬件上不再发出数据
半双工双向只接收 / 只发送数据线只有一根 SDI 或 SDO,需将 MOSI/MISO 中一个引脚配置为数据线,另一个引脚释放(设为 GPIO 或悬空),具体取决于芯片手册

② 主从模式:确认通信为主机还是从机。

③ 帧宽度:确定一帧的宽度,通常设置为 8bit;对于某些大数据量场景(如读取外置 Flash),可配置为 16bit。

④ 时钟极性与时钟相位(CPOL/CPHA):确定空闲时时钟线的电平,并决定在第几个边沿采样。

⑤ 时钟分频系数:与 IIC 直接配置速率不同,SPI 通过时钟分频来确定 clk 频率,且分频系数最小为 2(因为数据传输时其他状态机需要时间吞吐数据)。

⑥ 片选类型:通常有软件片选与硬件片选。作为主机收发时通常使用软件片选,作为从机接收时使用硬件片选

⑦ M/LSB:决定字节发送时 bit 序号,一般用 MSB,且主从机需要一致。

3.3 软件 SPI 初始化

软件 SPI 的初始化更简洁,只需初始化对应的 GPIO:

  • CS、MOSI、SCK:初始化成推挽输出,其中 CS 需要先输出为高
  • MISO:配置为浮空输入

3.4 附:MCU 外设 API 设计思路

MCU 外设的 API 设计基本只看 2 个维度:

  1. 配置复杂度(参数多不多);
  2. 是否"运行态状态机"

基于这两个维度,常见外设的 API 风格推荐如下:

外设类型推荐 API 风格原因
GPIO函数式配置极少
UART函数 / 结构体混合中等复杂
SPI结构体参数组合多
I2C函数式状态机驱动
ADC结构体多通道 + 采样配置复杂
DAC函数式配置简单
TIMER结构体模式复杂(PWM / 输入捕获)
DMA结构体描述符复杂
CAN结构体报文 + 过滤器复杂
USB高度结构体协议栈复杂
WDT函数式极简单
EXTI函数式配置少

总结

本文从三个维度系统地梳理了 SPI 总线:

  1. 通信时序:理解 SPI「主机发时钟、CS 选设备、边发边收」的核心逻辑,掌握 CPOL/CPHA 四种工作模式、M/LSB 配置,以及建立时间与保持时间对采样稳定性的影响;
  2. 电气特性:SPI 是推挽高速单端信号,重点关注走线长度、信号完整性、MISO 三态、CS 上拉、共地与电平匹配等硬件设计要点;
  3. 驱动开发:掌握硬件 SPI 的初始化流程与参数结构体配置(传输模式、帧宽度、分频系数、片选类型等)、软件 SPI 的 GPIO 初始化,以及外设 API 设计的一般思路。

掌握以上内容,基本可以应对绝大多数 SPI 相关的开发与调试场景,也能在面试中从容应对各种追问。希望本文对你有帮助,欢迎交流讨论!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 7:09:56

DPR、压缩与格式:解决移动端图片模糊的三大核心

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/16 7:09:24

K8s Pod 资源 Request 与 Limit 设置的最佳实践与踩坑

K8s Pod 资源 Request 与 Limit 设置的最佳实践与踩坑在全面拥抱容器化与 Kubernetes 云原生的微服务体系中&#xff0c;每一个 Deployment YAML 文件里都包含着一组看似极其平淡的字段——resources.requests 与 resources.limits。 许多研发人员在配置这组参数时&#xff0c;…

作者头像 李华
网站建设 2026/9/16 7:08:28

Java本地AI推理:Jlama与LangChain4j构建离线RAG问答系统

咱做Java的&#xff0c;很长一段时间里&#xff0c;聊到AI基本都是"调接口"——把文本往云上的大模型API一丢&#xff0c;等着流式结果回来。这套玩法没错&#xff0c;但一旦业务要求"数据不出内网""零网络依赖""离线也能干活"&#x…

作者头像 李华
网站建设 2026/9/16 7:07:40

JAVA 跨域设置

java 跨域请求设置 import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;Configuration public class Confi…

作者头像 李华
网站建设 2026/9/16 7:06:07

Python列表操作全解析:从基础到高阶实战

1. Python列表操作完全指南&#xff1a;从基础到高阶实战在Python编程中&#xff0c;列表(list)是最常用且功能强大的数据结构之一。无论是数据处理、算法实现还是日常脚本编写&#xff0c;熟练掌握列表操作都是每个Python开发者的必备技能。这份指南将系统性地介绍列表的各类操…

作者头像 李华
网站建设 2026/9/16 7:06:06

MS-DACAN跨工况轴承故障诊断:多尺度与类条件对齐的迁移学习方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华