SPI协议详解:从基础到STM32应用实践

发布时间:2026/9/12 20:17:15

SPI协议详解:从基础到STM32应用实践 1. SPI协议基础解析SPI(Serial Peripheral Interface)是一种同步串行通信协议由摩托罗拉在1980年代初期开发。作为嵌入式系统中最常用的通信接口之一它通过简单的四线制实现了全双工高速数据传输。典型的SPI系统包含一个主设备(Master)和一个或多个从设备(Slave)主设备通过控制时钟信号来同步数据传输。1.1 物理接口组成标准SPI接口由以下四条信号线构成SCLK(Serial Clock)主设备产生的时钟信号用于同步数据传输MOSI(Master Out Slave In)主设备输出从设备输入的数据线MISO(Master In Slave Out)从设备输出主设备输入的数据线SS(Slave Select)从设备选择信号(低电平有效)在实际应用中当系统只有一个从设备时SS线可以永久接地。但对于多从设备系统每个从设备需要独立的SS线。1.2 工作原理SPI的核心是主从设备间的移位寄存器交换。数据传输时主设备拉低目标从设备的SS线主设备产生时钟信号SCLK每个时钟周期主从设备同时通过MOSI和MISO线各发送1位数据数据通常以MSB(最高有效位)优先的方式传输传输完成后主设备拉高SS线这种机制使得SPI能够实现全双工通信主从设备可以同时收发数据。传输的数据长度没有限制常见的为8位或16位但也可以根据需求调整。2. SPI工作模式详解2.1 时钟极性与相位SPI定义了四种工作模式由时钟极性(CPOL)和时钟相位(CPHA)两个参数决定模式CPOLCPHA时钟空闲状态数据采样边沿000低电平上升沿101低电平下降沿210高电平下降沿311高电平上升沿注意不同厂商的SPI设备可能只支持特定模式使用时必须确保主从设备模式一致。2.2 多从机配置方案SPI支持三种多从机连接方式独立片选(Standard SPI)每个从设备有独立的SS线主设备通过拉低对应SS线选择通信的从设备优点简单直接各从设备互不影响缺点占用较多IO口资源菊花链(Daisy Chain)所有从设备共用一条SS线数据从主设备依次通过各从设备传回优点节省IO口缺点所有从设备必须支持菊花链模式扩展器方案使用解码器或移位寄存器扩展SS线通过发送地址码选择目标从设备平衡了IO口占用和系统复杂度3. SPI协议变体与扩展3.1 常见SPI变体Dual SPI将MOSI和MISO作为双向数据线使用每个时钟周期传输2位数据常用于Flash存储器读取Quad SPI新增SIO2和SIO3两条数据线每个时钟周期传输4位数据显著提高传输速率QPI/SQI全四线通信包括命令传输需要设备特殊配置提供最高性能3.2 高速SPI实现技术DDR SPI在时钟上升沿和下降沿都传输数据理论上使带宽翻倍eSPI(Enhanced SPI)Intel提出的增强型SPI工作电压降至1.8V支持1/2/4位宽模式最高时钟频率66MHz4. SPI应用实例与编程4.1 STM32 SPI配置示例以下是在STM32上配置SPI接口的典型步骤初始化GPIO// 配置SCK, MOSI, MISO为复用推挽输出 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_AF_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate GPIO_AF5_SPI1; HAL_GPIO_Init(GPIOA, GPIO_InitStruct);配置SPI参数hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_MASTER; hspi1.Init.Direction SPI_DIRECTION_2LINES; hspi1.Init.DataSize SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity SPI_POLARITY_LOW; hspi1.Init.CLKPhase SPI_PHASE_1EDGE; hspi1.Init.NSS SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_2; hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; hspi1.Init.TIMode SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial 10; if (HAL_SPI_Init(hspi1) ! HAL_OK) { Error_Handler(); }数据传输函数uint8_t txData[4] {0x01, 0x02, 0x03, 0x04}; uint8_t rxData[4] {0}; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // 拉低SS HAL_SPI_TransmitReceive(hspi1, txData, rxData, 4, 1000); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // 拉高SS4.2 SPI Flash读写操作以W25Q128 Flash芯片为例读取设备IDuint8_t cmd 0x9F; // 读ID命令 uint8_t id[3] {0}; HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, cmd, 1, HAL_MAX_DELAY); HAL_SPI_Receive(hspi1, id, 3, HAL_MAX_DELAY); HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);页编程(写入)void FLASH_PageProgram(uint32_t addr, uint8_t *data, uint16_t len) { uint8_t cmd[4] {0x02, (addr16)0xFF, (addr8)0xFF, addr0xFF}; FLASH_WriteEnable(); // 发送写使能命令 HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, cmd, 4, HAL_MAX_DELAY); HAL_SPI_Transmit(hspi1, data, len, HAL_MAX_DELAY); HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET); FLASH_WaitForWriteEnd(); // 等待写入完成 }5. SPI性能优化技巧5.1 DMA传输实现使用DMA可以显著提高SPI传输效率特别是在大数据量传输时初始化DMA__HAL_RCC_DMA2_CLK_ENABLE(); hdma_spi1_tx.Instance DMA2_Stream3; hdma_spi1_tx.Init.Channel DMA_CHANNEL_3; hdma_spi1_tx.Init.Direction DMA_MEMORY_TO_PERIPH; hdma_spi1_tx.Init.PeriphInc DMA_PINC_DISABLE; hdma_spi1_tx.Init.MemInc DMA_MINC_ENABLE; hdma_spi1_tx.Init.PeriphDataAlignment DMA_PDATAALIGN_BYTE; hdma_spi1_tx.Init.MemDataAlignment DMA_MDATAALIGN_BYTE; hdma_spi1_tx.Init.Mode DMA_NORMAL; hdma_spi1_tx.Init.Priority DMA_PRIORITY_HIGH; hdma_spi1_tx.Init.FIFOMode DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(hdma_spi1_tx) ! HAL_OK) { Error_Handler(); } __HAL_LINKDMA(hspi1, hdmatx, hdma_spi1_tx);DMA传输函数void SPI_Transmit_DMA(uint8_t *pData, uint16_t Size) { HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit_DMA(hspi1, pData, Size); while(HAL_SPI_GetState(hspi1) ! HAL_SPI_STATE_READY); HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET); }5.2 软件SPI实现当硬件SPI资源不足时可以使用GPIO模拟SPIvoid Soft_SPI_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; // 初始化SCK, MOSI, CS为输出 GPIO_InitStruct.Pin SOFT_SPI_SCK_PIN|SOFT_SPI_MOSI_PIN|SOFT_SPI_CS_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(SOFT_SPI_PORT, GPIO_InitStruct); // 初始化MISO为输入 GPIO_InitStruct.Pin SOFT_SPI_MISO_PIN; GPIO_InitStruct.Mode GPIO_MODE_INPUT; HAL_GPIO_Init(SOFT_SPI_PORT, GPIO_InitStruct); // 初始状态 HAL_GPIO_WritePin(SOFT_SPI_PORT, SOFT_SPI_SCK_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(SOFT_SPI_PORT, SOFT_SPI_CS_PIN, GPIO_PIN_SET); } uint8_t Soft_SPI_Transfer(uint8_t data) { uint8_t i, ret 0; HAL_GPIO_WritePin(SOFT_SPI_PORT, SOFT_SPI_CS_PIN, GPIO_PIN_RESET); for(i 0; i 8; i) { // 设置MOSI HAL_GPIO_WritePin(SOFT_SPI_PORT, SOFT_SPI_MOSI_PIN, (data 0x80) ? GPIO_PIN_SET : GPIO_PIN_RESET); data 1; // 上升沿 HAL_GPIO_WritePin(SOFT_SPI_PORT, SOFT_SPI_SCK_PIN, GPIO_PIN_SET); // 读取MISO ret 1; if(HAL_GPIO_ReadPin(SOFT_SPI_PORT, SOFT_SPI_MISO_PIN) GPIO_PIN_SET) ret | 0x01; // 下降沿 HAL_GPIO_WritePin(SOFT_SPI_PORT, SOFT_SPI_SCK_PIN, GPIO_PIN_RESET); } HAL_GPIO_WritePin(SOFT_SPI_PORT, SOFT_SPI_CS_PIN, GPIO_PIN_SET); return ret; }6. SPI调试与问题排查6.1 常见问题及解决方案无数据通信检查电源和接地连接确认SS信号是否正确控制验证时钟极性(CPOL)和相位(CPHA)设置检查SPI是否已正确初始化数据错误降低时钟频率测试检查PCB布线确保信号完整性确认数据传输的位序(MSB/LSB)检查从设备是否需要在命令间添加延迟DMA传输不完整确认DMA缓冲区是否在有效内存区域检查DMA中断是否被其他高优先级中断抢占验证DMA传输完成标志是否正确处理6.2 逻辑分析仪调试使用逻辑分析仪调试SPI的步骤连接探头到SCK、MOSI、MISO和SS线设置正确的采样率(至少4倍于SPI时钟频率)配置解码器为SPI协议设置正确的时钟极性和相位触发条件设置为SS线下降沿分析捕获的数据帧专业提示对于高速SPI(10MHz)建议使用差分探头减少噪声干扰并确保探头接地良好。7. SPI与其他串行协议对比7.1 SPI vs I2C特性SPII2C线路数量4线(3线变体)2线速度可达50MHz标准模式100kHz拓扑结构点对点/菊花链多主多从总线寻址方式硬件片选软件地址数据方向全双工半双工功耗较高较低复杂度简单较复杂(仲裁等)7.2 SPI vs UART特性SPIUART同步性同步异步时钟线需要不需要速度可达50MHz通常3Mbps数据格式原始数据帧结构(起始/停止位)错误检测无奇偶校验距离短距离(1m)可长距离(加驱动)在实际项目中这三种协议经常结合使用。例如主处理器通过UART与上位机通信通过I2C连接传感器通过SPI连接高速外设如Flash或显示屏。
延伸阅读

更多相关文章

2026/9/12 17:30:18

2026智能照明控制系统工厂选型榜:上海凡特领衔五大机构

2026年,智能照明控制系统早已不是楼宇自控里的“选修课”,而是成了空间体验与能耗管控的硬通货。扎心的现实是:80.3%的采购方曾被华而不实的方案坑过,要么协议不通配成了摆设,要么所谓智能只是多了个手机开关灯。正好&…

2026/9/12 16:56:39

Unity MapMagic 2:运行时程序化地形生成与开放世界构建指南

1. 项目概述:当开放世界需要“活”起来如果你正在或计划开发一个开放世界、生存建造、MMO或者任何需要一张巨大、动态且细节丰富地图的游戏,那么“运行时地形生成”这个需求,大概率已经让你头疼过不止一次。传统的美术手绘地形,在…

2026/9/11 21:58:02

树莓派UART串口通信详解与实战

1. 树莓派串口通信基础解析树莓派的串口通信功能是其与外部设备交互的重要方式之一。作为一名嵌入式开发者,我经常使用UART接口连接各种传感器、模块和其他微控制器。树莓派提供了两种UART硬件:PL011和mini UART,它们各有特点。PL011 UART是A…

2026/9/12 20:16:01

基于Django的智能控糖食物推荐系统设计与实现

1. 项目背景与核心价值糖尿病已经成为全球性的健康挑战,根据国际糖尿病联盟最新数据,我国糖尿病患者人数已突破1.4亿。在这样的背景下,控糖饮食管理成为刚需,但普通用户往往面临三大痛点:食物GI值难以获取、个性化推荐…

2026/9/12 20:16:01

Java构建物联网平台的优势与架构解析

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

2026/9/12 20:16:01

Unity 教程跟完后怎么练:一次只改一个可验收目标

摘要:跟完一个 Unity 案例后,想加背包、换操作、改关卡,却越改越乱?先选一个能看见结果的小改动,写清不改什么,再用正常情况、重复触发和原功能检查判断是否完成。本文给出目标筛选表与假想拾取练习&#x…

2026/9/12 20:16:01

国产AI短剧平台选型三原则:分镜可控、审核可配、分发同步

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

2026/9/12 20:16:01

Python开发十大常见错误与解决方案详解

1. Python十大常见错误及其解决方法概述作为一门简洁优雅的编程语言,Python凭借其易读性和丰富的生态系统吸引了大量开发者。但在实际开发中,无论是初学者还是资深工程师,都难免会遇到各种"坑"。这些错误轻则导致程序异常&#xff…

2026/9/12 20:11:01

MySQL-存储过程与函数

1.存储过程概述1.1理解含义:存储过程的英文是Stored Procedure.他的思想很简单,就是一组经过预先编译的SQL语句的封装.执行过程:存储过程预先存储在MySQL服务器上,需要执行的时候,客户端只需要向服务器端发出调用存储过程的命令,服务器端就可以把预先存储好的这一系列SQL语句全…

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码