一、SPI协议

1.1 SPI简介

  • SPI 是一种通用数据总线,有 4 根通信线 SCK(Serial Clock)、MOSI(主机输出,从机输入)、MISO(主机输入,从机输出)、SS(从机选择,专门用来指定从机的通信线)
  • 同步,全双工,支持总线挂载多设备(一主多从,不支持多主多从
  • SPI 无应答机制设计
  • SCK 提供时钟信号,数据位的输出输入都限在 SCK 的上升沿或下降沿进行的,此时数据位的收发时刻就可以明确确定。

1.2 SPI与I2C比较

1. 物理连接
SPI:通常需要 4 条线,分别是时钟线(SCK)、主机输出从机输入线(MOSI)、主机输入从机输出线(MISO)以及片选线(CS,每个从机至少需要一根独立的 CS 线,或者通过译码器控制)。SPI 通过 CS 线单独选择特定的从机进行通信。
I2C:仅需两条线,即数据线(SDA)和时钟线(SCL)。所有设备都连接到这两条总线上,通过地址来识别不同的从机。
2. 通信速度
SPI:通信速度相对较快,最高可达几十 Mbps。因为 SPI 是全双工通信,主机和从机可以同时发送和接收数据,且时钟频率由主机控制,可设置较高频率。
I2C:通信速度相对较慢,标准模式下为 100kHz,快速模式为 400kHz,高速模式为 3.4MHz。I2C 是半双工通信,同一时刻 SDA 线只能进行单向数据传输。
3. 寻址方式
SPI:没有专门的寻址字节,通过片选线(CS)来选择从机。主机通过使能特定从机的 CS 线来确定与之通信的从机。
I2C:主机在发送数据前,先发送一个地址字节,包含 7 位或 10 位的从机地址以及 1 位读写位,总线上所有从机通过比对地址来确定是否响应主机。
4. 总线仲裁
SPI:不需要总线仲裁,因为主机通过 CS 线独立控制每个从机,不会出现多个从机同时竞争总线的情况。
I2C:支持总线仲裁。当多个主机同时尝试控制总线时,I2C 通过 “线与” 逻辑(开漏输出结构)来仲裁,具有更高优先级的主机获得总线控制权,避免数据冲突。
5. 应用场景
SPI:适用于高速数据传输的场景,如与 Flash 存储器、ADC、DAC 等外设通信。由于其全双工和高速特性,能快速地读写大量数据。
I2C:常用于连接低速外设,如传感器(温度传感器、加速度计等)、EEPROM 等。I2C 的优点在于使用的引脚少,布线简单,且支持多主机和多从机通信,适用于设备数量较多且通信速率要求不高的系统。

1.3 硬件电路

  • 所有 SPI 设备的 SCK、MOSI、MISO 分别连在一起
  • 主机另外引出多条 SS 控制线,分别接到各从机的 SS 引脚,主机的 SS 线都是输出,从机的 SS 线都是输入,SS 线低电平有效,从而进行通信。
  • 输出引脚 P 配置为推挽输出(在 SS 为低电平时,MISO 才允许变为推挽输出),输入引脚 P 配置为浮空或上拉输入
  • SPI典型的应用电路
    在这里插入图片描述

1.4 移位示意图

在这里插入图片描述

  • 波特率发生器:它产生的时钟驱动主机的移位寄存器进行移位
  • 发生器的上升沿,所有移位寄存器向左移动一位,移出去的位放在引脚上,发生器的下降沿把引脚上的位,采样输入到移位寄存器最低位。

1.5 SPI的时序基本单元

交换一个字节(模式 1)
时钟极性 CPOL=0:空闲状态时,SCK 为低电平
时钟相位 CPHA=1:SCK 第一个边沿移出数据,第二个边沿移入数据
起始条件:SS 从高电平切换到低电平
终止条件:SS 从低电平切换到高电平
在这里插入图片描述
模式1示意图
在这里插入图片描述

模式0示意图
在这里插入图片描述
模式0和模式1区别:模式0把数据变化的时机给提前了

二、W25Q64(非易失存储器)

2.1 W25Q64简介

  • 是一种低成本,小型化,使用简单的非易失性存储器,常用于数据存储,字库存储,固件存储等场景。
  • 存储介质:Nor Flash(闪存)
  • 时钟频率:80MHz / 160MHz / 320MHz
  • 24位地址,最大能分配2²⁴字节,最大寻址能达到16Mb

2.2 硬件电路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3W25Q64框图

在这里插入图片描述

2.4 Flash 操作注意事项

1.写入操作时:

  • 必须先进行写使能
  • 每个数据只能由 1 改写 0,不能由 0 改写为 1
  • 写入数据前必须先擦除,擦除后,所有的数据位变为 1(0xFF)
  • 擦除必须按最小擦除单元进行
  • 连续写入多字节时,最多写入一页的数据,超过页尾位置数据,会回到首页覆盖写入
  • 写入操作结束后,芯片进入忙状态,不响应新的读写操作

2.读取操作时:

  • 直接调用读取时序,无需使能,无需额外操作,没有页的限制
  • 读取操作结束后不会进入忙状态,但不能在忙状态时读取

2.5 SPI时序(以W25Q64的时序为例)

在SPI中,通常采用的是指令码+读写数据的模型。具体不同的指令码需要阅读从机的相关手册

模式0:发送指令,向ss指定的设备,发送指令(0x06)写使能在这里插入图片描述
指定地址写:向 SS 指定的设备,发送写指令(0x02),随后在指定地址(address [23:0])下,写入指定数据
在这里插入图片描述

在 0x123456 地址下写入0x55 数据

三、SPI硬件外设

3.1 SPI外设简介

  • STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担
  • 可配置8位/16位数据帧、高位先行/低位先行
  • 时钟频率:fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)
  • 支持多主机模型、主或从操作
  • 可精简为半双工/单工通信
  • 支持DMA
  • 兼容I2S协议

STM32F103C8T6 硬件SPI资源:SPI1、SPI2

3.2 SPI框图

在这里插入图片描述

1. 核心信号与外部接口

  • MOSI:主机输出、从机输入数据线(Master Output Slave Input)。
  • MISO:主机输入、从机输出数据线(Master Input Slave Output)。
  • SCK:时钟信号(Serial Clock),由主机生成,同步数据传输。
  • NSS:从机选择信号(Slave Select),低电平选中对应从机(也可软件模拟片选)(一般用在多主多从模式,了解即可)

2. 内部功能模块

  • 波特率发生器:根据SPI_CR1寄存器的BR[2:0]位配置,生成SCK时钟频率(由APB总线时钟分频得到)。
  • 主控制电路:协调SPI整体工作模式,包括通过SPI_CR1配置主从模式(MSTR)时钟极性(CPOL)时钟相位(CPHA)、**数据位顺序(LSB FIRST)**等核心参数。
  • 移位寄存器:SPI的“数据中转站”——发送时,数据从发送缓冲区加载到移位寄存器,再逐位通过MOSI移出;接收时,MISO输入的位逐位移入寄存器,满后送入接收缓冲区,供CPU读取。
  • 通信电路:处理SPI的时序逻辑、同步机制,配合状态寄存器(SPI_SR)反馈通信状态(如TXE发送缓冲区空、RXNE接收缓冲区非空、OVR溢出等)。
  • 寄存器组
    • SPI_CR1/SPI_CR2:控制寄存器,配置SPI工作模式、速率、中断等。
    • SPI_SR:状态寄存器,实时反馈SPI的工作状态(如忙闲、收发完成标志)。

3. 数据流向逻辑

  • 发送:CPU将数据写入“发送缓冲区”→ 数据加载到“移位寄存器”→ 由SCK同步,逐位从MOSI发送到从机。
  • 接收:从机通过MISO发送的位,由SCK同步逐位移入“移位寄存器”→ 数据满后,转入“接收缓冲区”→ CPU从接收缓冲区读取数据。

3.3 SPI基本结构

在这里插入图片描述

  • 初始化SPI步骤
    1. 使能 SPI 及对应 GPIO 时钟
  • 开启 SPI 外设时钟(如RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE))
  • 开启对应 GPIO 端口时钟(如 SPI1 通常使用 PA5/6/7 引脚)
    2. 配置 SPI 引脚模式
  • 将 SCK、MOSI 引脚配置为复用推挽输出
  • 将 MISO 引脚配置为浮空输入或上拉输入
  • 例:GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;(复用推挽)
    3. 初始化 SPI 参数
  • 配置 SPI 工作模式(主模式SPI_Mode_Master或从模式SPI_Mode_Slave)
  • 设置数据帧格式(8 位 / 16 位,如SPI_DataSize_8b)
  • 配置时钟极性(CPOL)和相位(CPHA)
  • 设置数据传输顺序(MSB 先行或 LSB 先行)
  • 配置分频系数确定 SPI 时钟频率(如SPI_BaudRatePrescaler_2)
    4. 使能 SPI 外设
  • 通过SPI_Cmd(SPI1, ENABLE)开启 SPI 功能
    5. (可选)配置中断或 DMA
  • 若使用中断:SPI_ITConfig()配置相关中断
  • 若使用 DMA:SPI_DMACmd()使能 DMA 请求

3.4 SPI连续传输

1. 主模式全双工连续传输

在这里插入图片描述

主模式全双工连续传输比较复杂,如果对时间没有严格要求一般使用非连续传输。

2. 非连续传输

在这里插入图片描述

非连续传输函数步骤

  1. 等待发送缓冲区为空检查 SPI 状态寄存器的 TXE 位(发送缓冲区空标志),等待其置 1,确保可以写入新数据:
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
  2. 写入数据到发送缓冲区将待发送的数据写入 SPI 数据寄存器(DR),触发发送过程:
    SPI_I2S_SendData(SPI1, data);
  3. 等待发送完成(可选)若需要确保当前数据完全发送完毕再进行后续操作,可等待 BSY 位(忙标志)清零:
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET);
  4. 非连续发送间隔处理在两次发送之间根据需求添加延迟或其他操作(体现 “非连续” 特性),例如:
    delay_ms(10); // 自定义延时函数,根据实际时序要求调整

3.5 软件/硬件波形对比

在这里插入图片描述

  • 时序一致性:硬件波形(上方)的时钟、数据等信号在时序上更具规律性,脉冲间隔等更均匀;软件波形(下方)可能因软件执行的延时、中断等因素,时序一致性稍差。
  • 稳定性:硬件波形的信号电平、脉冲形状等更稳定,受外界干扰或系统负载影响小;软件波形可能存在更多因软件层面调度等产生的不稳定波动。
  • 精准度:硬件基于专用的硬件电路生成波形,在时钟频率、脉冲宽度等参数的精准度上更高;软件模拟波形受软件执行速度、系统时钟等限制,精准度相对略低。

有关【STM32】SPI通信 就到这,希望对你有所帮助,感谢观看!

码文不易,留个赞再走吧~

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐