STM32双机SPI通信实战:从CubeMX配置到HAL库代码调通

发布时间:2026/9/8 22:33:32

STM32双机SPI通信实战:从CubeMX配置到HAL库代码调通
简介面向STM32初学者的两块板间SPI通信例程详尽注解主从模式配置、时钟极性/相位选择、SPIx_CR1/CR2/SR/DR等寄存器设置与收发流程并集成液晶显示功能适合需要快速上手多板通信或SPI外设交互的开发者。资源共60个文件以C源码、H头文件、UVproj工程文件为核心另含hex、map、axf等编译固件与列表文件以及txt说明、htm文档等辅助材料整包仅450KB结构紧凑便于直接打开工程对照学习。目前已有3073人学习下载。通过例程可完整掌握SPI从初始化、发送接收、状态查询到错误处理的实战路径液晶显示部分展示SPI接口驱动屏幕的典型用法代码注释覆盖每一步操作背后的硬件机制有助于理解寄存器位含义、时钟分频及主从握手逻辑对后续扩展多从机通信或高速传输也有参考价值。 最近刚把两块STM32F103C8T6小板子用SPI连起来做了个双机通信折腾了大概一个下午中间踩了好几个坑。网上关于SPI的教程不少但大多数都是“单片机外挂一颗Flash/传感器”这种单主多从的玩法真正讲清楚“两块STM32板子互相通信、主从角色怎么定、代码怎么写、波形怎么查”的反而少见。这篇就按我实际调通的路径把从零到一的过程完整记录下来包括CubeMX配置、HAL库代码、排查技巧新手照着做就能跑起来。1. 两块板子直接连先搞清主从角色和接线SPI是个同步全双工总线靠一根SCK时钟线同步数据在MOSI和MISO两根线上双向流动。双机通信的“正确打开方式”不是像串口那样RX接TX交叉而是同名引脚直接相连主机的MOSI接从机的MOSI主机的MISO接从机的MISOSCK接SCK片选NSS接NSS。刚接触的时候我第一反应是“这不就短路了吗”后来想明白就通了——MOSI是“Master Out Slave In”主机输出、从机输入这根线上同一时刻只有一个设备在驱动它不会短路。1.1 为什么选SPI而不是IIC或串口双机短距通信可选方案无非就是UART、IIC、SPI三种。我这次选SPI核心原因是想传一批结构体数据对速度和时序有要求而且两块板子之间距离只有十几厘米SPI的高速优势能完全发挥出来。三者区别简单说UART最简单点对点只要两根线但速度上限一般而且双方得约定好波特率没有时钟线就意味着一端晶振偏一点就可能乱码IIC只有两根线支持多设备挂总线但通信有ACK机制、有地址帧协议开销大速度一般到400kHz就差不多了每次传输前还要发起START、发地址对“一次传几十个字节”的场景来说效率偏低SPI至少四根线SCK/MOSI/MISO/NSS配置灵活、速度能跑到几十MHz全双工同时收发协议层很薄收发的可靠性基本靠硬件时钟保证。对比项 通信线数 速度 协议复杂度 适合场景 UART TX/RX 2根 通常≤1.5Mbps 低 简单命令、日志、长距离 IIC SCL/SDA 2根 通常≤400kHz 中 多设备、低速率传感采集 SPI SCK/MOSI/MISO/NSS 4根 最高几十MHz 低 高速数据传输、双机全双工如果你的需求就是“两块板子互相丢几个字节状态”用串口就行省事。但如果像我一样要传数组、结构体甚至后续想上DMASPI是更合适的底座。1.2 主从机的引脚分配与杜邦线接线我用的是最常见的STM32F103C8T6“蓝板”SPI1引脚默认挂在PA5/PA6/PA7/PA4上。硬件连线如下主机(SPI1 Master) 从机(SPI1 Slave) PA5 — SCK ———————— PA5 PA6 — MISO ———————— PA6 PA7 — MOSI ———————— PA7 PA4 — NSS ———————— PA4 GND —————————————— GND注意MOSI和MISO线序不要接反。主机发数据走MOSI从机从同一根MOSI上收到从机回复走MISO主机从MISO上读。如果你拿串口的“交叉”思维来插SPI那就全乱了示波器上看起来SCK有波形、MOSI也有波形但从机就是收不到主机也读不到从机回的数据。另外一个必须强调的点GND一定要共地。SPI靠电平高低判断数据两边参考地不一致电平判断就没法保证轻则数据偶发错误重则完全通信失败。我试过用USB分别给两块板供电然后不共地结果数据全乱接上GND就正常了。2. CubeMX里把参数一次配对配置环境我用的是STM32CubeMX HAL库固件包选F1系列就行。之所以推荐CubeMX而不是纯标准库手写寄存器是因为SPI的GPIO复用、AFIO映射、时钟使能这些杂事CubeMX能一次给你配好不容易漏尤其适合新手少走弯路。2.1 主机端SPI1配置与分频计算打开CubeMX后先把两块板子的RCC都设为Crystal/Ceramic ResonatorSYS里Debug设为Serial Wire避免把SWD调试口给占了。然后主机端把SPI1设置为Full-Duplex Master参数按下面这样填Parameter 设置值 Mode Full-Duplex Master Data Size 8 Bits Prescaler 64 Clock Polarity (CPOL) Low Clock Phase (CPHA) 1 Edge NSS Hardware NSS Output Baud Rate 1.125 MBits/sPrescaler的选择不是随便拍的。F103的SPI1挂在APB2总线上时钟是72MHzSPI实际波特率 72MHz / Prescaler。分频器可选2/4/8/16/32/64/128/256。我最后选了64分频算出波特率 72MHz / 64 1.125Mbps。这个速度用杜邦线短距离通信相当稳既不会像最高18Mbps那样容易被线间串扰搞崩也不会像几百kHz那样慢得让人着急。实际用下来这个距离下1Mbps是很好的起点。如果后面你发现通信稳定想提速度可以逐步把分频降到32、16每次降完都跑一遍压力测试。如果用的是10cm以上的杜邦线超过4Mbps之后偶发误码率会明显上升。2.2 从机端配置与NSS引脚特殊处理从机端SPI1设置为Full-Duplex Slave其余参数和主机完全一致。CPOL和CPHA必须跟主机一模一样否则数据采样时刻对不上现象就是主机发过去了、从机收到的数据是错位的。CubeMX里从机一般会自动把NSS设为Hardware NSS Input这个不用改。这里有个新手特别容易踩的坑CubeMX的GPIO标签页里从机的NSS引脚可能会被标成GPIO_Output或GPIO_Input如果你在SPI配置界面没有正确选择硬件NSS模式的话。一旦NSS没被SPI外设接管从机永远不会进入选中状态SPI从机模块始终不工作主机那边MISO就永远读不到任何有效数据。再说下硬件NSS和软件NSS的区别。硬件NSS下主机开始传输时SPI外设会自动把NSS引脚拉低让从机知道自己被选中从机检测到NSS变低就知道这个通信周期是属于自己的。软件NSS则是用普通GPIO手动控制片选信号好处是引脚随意选、片选时机完全由代码控制坏处是时序要自己保证。双机通信我的建议是除非你对时序控制有十足把握否则乖乖用硬件NSS省心太多。3. 打通一发一收的核心代码3.1 主机发送与从机接收的同步策略先说最简单的单向通信主机发一串数据给从机从机收到后通过串口打印出来。主机端代码uint8_t tx_buf[5] {0xA5, 0x01, 0x02, 0x03, 0x5A}; while (1) { HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); HAL_SPI_Transmit(hspi1, tx_buf, 5, 1000); HAL_Delay(500); }这里HAL_SPI_Transmit最后一个参数1000是超时时间单位毫秒。如果1000ms内没传完函数返回HAL_TIMEOUT。正常情况下几毫秒就传完了。从机端要提前进入接收等待状态uint8_t rx_buf[5] {0}; while (1) { HAL_SPI_Receive(hspi1, rx_buf, 5, 1000); printf(RX: %02X %02X %02X %02X %02X\r\n, rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3], rx_buf[4]); }这里有个必须理解的关键点SPI从机没有自己的时钟完全是跟着主机的SCK被动走。从机必须先跑进HAL_SPI_Receive里“等着”主机再发起传输数据才能正好对上。如果你让主机先发数据、从机过200ms后才去接收那这5个字节早就没了——SPI不像串口有FIFO和起始位检测它不会帮你暂存错过的数据。所以“从机先等、主机再发”是SPI双机通信的基本纪律。实在想反过来主机等从机准备好就得靠握手信号比如从机准备好后拉高一个GPIO主机检测到这个GPIO再开始发送。3.2 双向通信改用一问一答模式实际项目里只单向传数据太局限了更多时候是“主机给从机发个命令从机返回一个状态或一组数据”。这时候用HAL_SPI_TransmitReceive一次完成一发一收// 主机端 uint8_t tx_cmd 0x01; // 查询命令 uint8_t rx_data[4] {0}; while (1) { HAL_SPI_TransmitReceive(hspi1, tx_cmd, rx_data, 4, 1000); printf(CMD: %02X, RESP: %02X %02X %02X %02X\r\n, tx_cmd, rx_data[0], rx_data[1], rx_data[2], rx_data[3]); HAL_Delay(500); }// 从机端 uint8_t rx_cmd 0; uint8_t tx_resp[4] {0xAA, 0xBB, 0xCC, 0xDD}; while (1) { HAL_SPI_TransmitReceive(hspi1, rx_cmd, tx_resp, 4, 1000); if (rx_cmd 0x01) { // 注意数据要在下一次传输前更新好 tx_resp[0] Read_Sensor_Value(); tx_resp[1] status_reg; } }这里新手最容易搞混的是从机的发送缓冲。HAL_SPI_TransmitReceive要求你在调用前就把要回的数据放进tx_resp然后从机会在主机SCK的节拍下把数据从MISO送出去。也就是说从机的“回复内容”其实是在本次传输过程中发送的你没法做到“收到命令之后再立刻准备回答一个此前完全未知的数据”并且还在同一帧里发出去——除非你约定好这次回复的是“上次查询的结果”或者直接延长SCK帧让从机处理完命令后主机再发起第二次传输。实际工程里我惯用的办法是主机先发一个命令帧从机收到后处理然后主机再发一个“读取帧”从机把处理结果回给主机。两个SPI周期一问一答逻辑非常清晰。3.3 帧格式设计建议SPI协议本身没有起始位、停止位和地址只要主机连续拉低NSS字节就会一个接一个流过去。一旦主机和从机对字节的计数不一致比如上电时序导致从机多等了一个字节那后面所有数据都会错位而且这种错位不会自动恢复。解决办法是加“帧同步头”。我这边的简单做法是固定以0xA5开头后面跟2字节长度、N字节数据、1字节校验。从机每次收到数据后先找0xA5找不到就丢弃一个字节继续找直到重新对齐。帧格式: [0xA5] [len_hi] [len_lo] [data0] [data1] ... [checksum]校验可以先用简单的累加和把前面所有字节加起来取低8位。等数据量大了再换CRC。别嫌这一步多余双机联调的时候帧头同步能帮你省下大量“为什么数据偶尔全对、偶尔错位”的排查时间。4. 波形不对别慌这些坑我踩过两块板子都下好程序之后我第一版代码调了小半小时才通。中间遇到的现象很有代表性整理成表大家对照着定位就行。4.1 现象对照表MISO没数据、数据错位、偶发乱码现象 可能原因 排查顺序 主机MISO读到0x00或0xFF 从机没初始化/从机NSS没选中 量从机SCK是否有波形 从机MISO配成了输入 查从机GPIO复用是否正确 硬件NSS没接或没配置对 查NSS电平传输期间应为低 数据错位一个bit或半字节 CPOL/CPHA两边不一致 逻辑分析仪抓波形对比采样点 数据帧格式MSB/LSB不一致 确认两边都设MSB First 通信偶发乱码 速率太高/杜邦线太长/没共地 降分频、缩短线距、接GND 从机收不到任何数据 主机NSS没被外设接管 查CubeMX NSS模式是否Hardware如果你手头没有逻辑分析仪最廉价的排查方式是拿从机的NSS引脚和SCK引脚先用示波器看波形。NSS在通信期间应该是低电平SCK上应该有连续脉冲。如果NSS没拉低问题基本出在片选控制上。4.2 用逻辑分析仪快速定位CPOL/CPHA不匹配我第一次遇到数据错位时代码翻来覆去看都没发现问题最后上逻辑分析仪抓波形一眼就看明白了。你不需要买多贵的几十块钱的8通道逻辑分析仪就够用。抓SPI波形主要看三点空闲时SCK是高还是低对应CPOL数据在SCK第一个边沿还是第二个边沿稳定对应CPHA数据位是先出高位还是先出低位。方便记忆的对应关系是CPOL0表示空闲低电平CPOL1表示空闲高电平CPHA0表示第一个边沿采样CPHA1表示第二个边沿采样。比如示波器上看到SCK空闲为低第一个上升沿时MOSI数据线已经稳定、随后才开始变化那对应的就是CPOL0、CPHA0也就是CubeMX里CPHA选1st Edge、HAL宏里SPI_MODE0。反过来如果看到数据在下降沿附近变化、上升沿才稳定那就是CPHA1。两边不一致时把参数改成一致就行代码不用动。4.3 线材、速率和共地的可靠性经验最后总结几条实打实的可靠性经验都是我实际踩过的杜邦线尽量短10厘米以内最好。超过15厘米速率上2Mbps就容易偶发错误尤其是在电机、继电器这类干扰源旁边。通信速率别盲目追高。1Mbps对双机短距通信来说体验和18Mbps几乎没有差别但可靠性完全不在一个量级。两块板子的地线一定要先接。用同一个电源供电最省事分开供电时一定补一根GND线。从机的回复数据要在主机启动传输之前准备好否则你发出去的就是上一次的旧数据。调试时可以配合ST-Link的在线调试主机端单步执行HAL_SPI_Transmit从机端断点打在接收完成之后两边数据对不对一目了然。我目前调通的这套例程已经扩展到了SPIDMA模式把传输负荷从CPU上卸掉了不少——主循环在做别的事数据靠DMA在后台搬运接收完成再挂中断通知CPU去处理。再往后如果要做多从机就在NSS线上做文章每块从机挂一根片选线主机选中谁就和谁通信。其实SPI的底层逻辑一旦通了往上叠加这些花活就是水到渠成的事关键是先把基础的一发一收、一问一答跑稳。本文还有配套的精品资源点击获取

相关新闻

西门子S7-1500 PLC报价差异3倍的真相:配置陷阱与成本维度拆解

西门子S7-1500 PLC报价差异3倍的真相:配置陷阱与成本维度拆解

2026/9/8 22:33:32

1. 为什么西门子PLC报价能差出3倍?这不是坑,是“配置陷阱”在说话 你手头刚收到三份西门子PLC的报价单:一份8万,一份15万,还有一份22万——型号都写着S7-1500,CPU型号也标得一模一样,都是6ES751…

res-downloader 免费跨平台资源下载:三分钟从零抓取到第一个视频

res-downloader 免费跨平台资源下载:三分钟从零抓取到第一个视频

2026/9/8 22:33:32

res-downloader 免费跨平台资源下载:三分钟从零抓取到第一个视频 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader …

Webpack Loader 实战剖析:基于 examples/loader 示例掌握自定义 Loader、内联请求与 css-loader 规则配置

Webpack Loader 实战剖析:基于 examples/loader 示例掌握自定义 Loader、内联请求与 css-loader 规则配置

2026/9/8 22:33:32

Webpack Loader 实战剖析:基于 examples/loader 示例掌握自定义 Loader、内联请求与 css-loader 规则配置 【免费下载链接】webpack A bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading part…

get-shit-done 模型解析单一事实源改造:Model Catalog 模块如何终结 resolve-model 的 SDK/CLI 模型漂移(3229)

get-shit-done 模型解析单一事实源改造:Model Catalog 模块如何终结 resolve-model 的 SDK/CLI 模型漂移(3229)

2026/9/8 23:23:34

get-shit-done 模型解析单一事实源改造:Model Catalog 模块如何终结 resolve-model 的 SDK/CLI 模型漂移(#3229) 【免费下载链接】get-shit-done A light-weight and powerful meta-prompting, context engineering and spec-driven developm…

FastAPI 高级指南:在 OpenAPI 中声明附加响应(Additional Responses)的完整实战解析

FastAPI 高级指南:在 OpenAPI 中声明附加响应(Additional Responses)的完整实战解析

2026/9/8 23:23:34

FastAPI 高级指南:在 OpenAPI 中声明附加响应(Additional Responses)的完整实战解析 【免费下载链接】fastapi FastAPI framework, high performance, easy to learn, fast to code, ready for production 项目地址: https://gitcode.com/G…

MCP工具UI方案:直接返回HTML还是采用A2UI结构化描述协议?

MCP工具UI方案:直接返回HTML还是采用A2UI结构化描述协议?

2026/9/8 23:23:34

上个月我接了一个 MCP 工具&#xff0c;想着“这回用 AI 自动生成表单&#xff0c;总算能省掉自己写 UI 的功夫了”。结果工具返回了一段完整的 HTML&#xff0c;从<!doctype html>到</html>一应俱全。我把它贴到浏览器里&#xff0c;渲染效果确实漂亮&#xff1b;…

10 分钟调出复古半色调点阵:three.js DotScreenPass 实战指南

10 分钟调出复古半色调点阵:three.js DotScreenPass 实战指南

2026/9/8 23:23:34

10 分钟调出复古半色调点阵&#xff1a;three.js DotScreenPass 实战指南 【免费下载链接】three.js JavaScript 3D Library. 项目地址: https://gitcode.com/GitHub_Trending/th/three.js three.js 的 DotScreenPass 是一个半色调后处理通道&#xff1a;场景渲染完成后…

COMSOL锂电池热管理仿真:从单体建模到冷却方案对比

COMSOL锂电池热管理仿真:从单体建模到冷却方案对比

2026/9/8 23:23:34

做电池热管理仿真的人应该都有过这种经历&#xff1a;领导或者甲方拿到一张温度云图&#xff0c;第一句话往往是“这个最红的地方多少度&#xff1f;会不会炸&#xff1f;”&#xff0c;再补一句“换成水冷能不能压到45度以下&#xff1f;”。如果你只会拉着模型瞎调参数&#…

基于YOLOv8与ONNX的直肠息肉检测系统:从训练到GUI部署全解析

基于YOLOv8与ONNX的直肠息肉检测系统:从训练到GUI部署全解析

2026/9/8 23:13:34

简介&#xff1a;面向医学影像与目标检测开发者的直肠息肉检测系统完整实现&#xff0c;基于YOLOv8与PyQt5搭建&#xff0c;提供Python源码、ONNX推理模型和可视化GUI界面&#xff0c;适合希望快速掌握检测模型落地流程的初中级学习者。压缩包共32个文件&#xff0c;约10.38MB&…

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

2026/9/7 20:21:46

本文首发于“生态学者”&#xff01;从“湿地面积”到“土壤碳密度”&#xff1a;为什么需要重新认识潮汐湿地蓝碳变化&#xff1f;潮汐湿地位于陆地与海洋的交汇地带&#xff0c;包括红树林、盐沼和潮滩&#xff0c;是全球重要的蓝碳生态系统。其土壤能够长期储存大量有机碳&a…

adb抓包

adb抓包

2026/9/8 4:55:53

前言 本文介绍如何通过 tcpdump 在 Android 手机上抓取网络数据包&#xff0c;并在电脑端使用 Wireshark 进行分析。适用于需要排查 App 网络请求、分析接口调用或调试网络问题的开发与测试场景。1. 手机要有 root 权限2. 下载 tcpdump3. adb push C:\Users\zhangkuixun\Downlo…

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

2026/9/8 22:37:26

大模型推理镜像极简瘦身&#xff1a;从 25GB 巨无霸到 3GB 精简镜像实战 在云原生基础设施中&#xff0c;容器镜像体积直接决定了服务的部署速度与弹性扩容敏捷度。对于传统的 Go / Java 微服务&#xff0c;镜像体积通常被严格控制在 50MB 到 200MB 以内&#xff0c;拉取镜像只…

芯片良率波动可视化:动画拆解工艺因果,重建客户信任

芯片良率波动可视化:动画拆解工艺因果,重建客户信任

2026/9/8 0:02:30

芯片这个行业有个不太被人摆到台面上、但几乎每天都在发生的场景&#xff1a;客户拿着一条良率曲线截图问你&#xff0c;这批货的良率怎么掉了三个点&#xff0c;是不是工艺出问题了&#xff0c;产生的不良会不会流到他们产线上去。你解释了半天&#xff0c;客户似懂非懂&#…

PyTorch DataLoader参数冲突:sampler与shuffle互斥的根源与正确写法

PyTorch DataLoader参数冲突:sampler与shuffle互斥的根源与正确写法

2026/9/8 0:02:30

ValueError: sampler option is mutually exclusive with shuffle&#xff0c;这个报错我在 PyTorch 的 DataLoader 上至少见过几十次了&#xff0c;而且很有意思的是&#xff0c;它经常不是新手专属——很多写了好几年模型的老手&#xff0c;在从单机改成自定义采样器&#xf…

中国车企再破谣言,GAC吉利零跑获欧盟安全五星

中国车企再破谣言,GAC吉利零跑获欧盟安全五星

2026/9/8 0:02:30

有人可能在网上开着皮卡拍视频&#xff0c;声称中国电动车不仅性能不如美国大排量车型&#xff0c;安全性也堪忧。然而事实恰恰相反&#xff0c;GAC、吉利和零跑最新推出的电动车型在极为严苛的欧盟新车安全评鉴&#xff08;Euro NCAP&#xff09;测试中全部斩获满分。就在特斯…

远程协作的工作台整理

远程协作的工作台整理

2026/9/8 4:23:39

远程协作的工作台整理远程协作的核心不是再加一个工具&#xff0c;而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置&#xff1b;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/8 3:19:39

持续集成 流水线自动化与 声明式交付 实践&#xff1a;原型怎样变成可用功能分类&#xff1a;[AI/大模型]细分主题&#xff1a;AI 增强型 CI/CD 流水线自动化与 GitOps 实践&#xff1a;Agent 工作流、工具调用与任务拆解&#xff1a;从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/8 4:00:23

容器编排 生产环境运维与排障实战&#xff1a;复盘记录怎样真正派上用场分类&#xff1a;[工程技术]细分主题&#xff1a;Kubernetes 生产环境运维与排障实战&#xff1a;可复制的项目复盘模板与决策记录大部分团队的事故复盘报告&#xff0c;最后都变成了躺在 Confluence 或钉…