STM32 硬件 SPI 实战:全双工上 MHz,给 I2C 那些慢设备提速
硬件 I2C 能把一堆传感器安顿好但 I2C 满打满算 400k顶多应付温湿度、气压这种慢变量。等我要往 TFT 屏刷像素、从 SPI Flash 烧程序、读 IMU 的裸数据流400k 直接跪屏一闪一闪跟抽风似的。SPI 一上场就不一样全双工、推到十几 MHz、没有地址仲裁那套开销字节一个接一个往外蹦。这篇讲怎么把 SPI 用稳别让 CPOL/CPHA 和片选把你自己绕晕。协议人话版SPI 四根线SCK时钟、MOSI主发从收、MISO从发主收、CS/SS片选。时钟由主机产生数据在 SCK 边沿一位位移进移出。靠两根数据线所以它才能全双工发的同时就能收。和 I2C 最大区别SPI没有从机地址靠 CS 脚一个一个挑从机也不用上拉电阻推挽输出直接驱动速率上限高得多。代价是每多一个从机就多一根 CS 线线数蹭蹭涨。CPOL / CPHA 四种模式这是 SPI 最容易栽的地方。两个参数决定在时钟的哪个边沿采样数据CPOL空闲时 SCK 是高还是低。CPHA在第一个边沿还是第二个边沿采样。组合出 4 种模式Mode 0~3。从机 datasheet 写 Mode 0你就配 Mode 0差一个模式数据整字节错位。别凭感觉配先翻从机手册的 “SPI Mode” 那一行。CubeMX 怎么配SPI1 → Mode 选Full-Duplex Master全双工主机。参数Clock Polarity (CPOL)/Clock Phase (CPHA)对照从机手册填。Baud Rate PrescalerSPI 时钟 APB 时钟 / 分频。84MHz 的 APB2 上选/4就是 21MHz新手先/8或/16跑通。Data Size8 bits默认或 16 bits某些 DAC/ADC 用 16 位帧。First BitMSB First默认和绝大多数器件一致。NSS选Software软件片选。这样 CS 脚你自己用普通 GPIO 控制灵活度最高HAL 不会自动帮你拉 CS。引脚SCK/MOSI/MISO 自动分配CS 脚单独设一个 GPIO 输出如 PA4。代码全双工收发是核心SPI 是移位寄存器发一位的同时收一位。想读数据你就得发 dummy 把 SCK 跑起来从机才往 MISO 吐。#defineCS_PINGPIO_PIN_4#defineCS_PORTGPIOAstaticinlinevoidcs_low(void){HAL_GPIO_WritePin(CS_PORT,CS_PIN,GPIO_PIN_RESET);}staticinlinevoidcs_high(void){HAL_GPIO_WritePin(CS_PORT,CS_PIN,GPIO_PIN_SET);}// 读 W25Q 这类 SPI Flash发命令3字节地址再收数据voidspi_flash_read(uint32_taddr,uint8_t*out,uint32_tlen){uint8_tcmd[4]{0x03,(addr16)0xFF,(addr8)0xFF,addr0xFF};cs_low();HAL_SPI_Transmit(hspi1,cmd,4,100);// 发读命令地址HAL_SPI_Receive(hspi1,out,len,100);// 发 dummy 把时钟跑起来收数据cs_high();}注意上面分两步Transmit发命令Receive其实是在发 dummyHAL 内部填 0xFF产生 SCK 同时收 MISO。只想收也必须发东西否则从机没时钟、不吐数据——这是 SPI 新手最常懵的一点。单次收发最简单用TransmitReceiveuint8_ttx0xAA,rx0;HAL_SPI_TransmitReceive(hspi1,tx,rx,1,100);// 发的同时收 1 字节DMA 版刷屏、连续搬大块时省 CPUuint8_tframe[1024];cs_low();HAL_SPI_Transmit_DMA(hspi1,frame,1024);// 完成进 HAL_SPI_TxCpltCallback// 收也要 DMA 就再加一条 SPI1_RX 流全双工需 TX、RX 两个流都开多从机共享总线多个 SPI 从机可以共用 SCK/MOSI/MISO但每个从机一根独立 CS。谁要通信就拉谁的 CS 低谈完拉高。绝不能同时拉低两个 CS。// 三个从机各一根 CSCS1PA4, CS2PA5, CS3PA6voidtalk_to(uint8_tdev){cs_high_all();switch(dev){case1:HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);break;case2:HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);break;case3:HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET);break;}// ... 传数据 ...cs_high_all();}10 个真实翻车点1. CPOL/CPHA 模式对不上。★ 头号坑。从机 datasheet 写 Mode 0CPOL0, CPHA0你图省事默认配成 Mode 3数据整字节错位读回来全是乱码。拿到任何 SPI 器件第一步翻手册 SPI Mode 那行照着配。2. 软件片选忘了拉低。NSS 设成 Software 后HAL 的Transmit/Receive不会自动拉 CS。你没cs_low()就直接发从机压根没被选中总线静悄悄。每次传输前cs_low()、之后cs_high()当成仪式。3. 多从机 CS 没释放干净。上一个从机谈完忘了cs_high()下一个又cs_low()另一个结果两个 CS 同时低——两个从机一起往 MISO 驱动数据打架总线冲突。封装成拉高全部→只拉低目标的talk_to()最稳。4. 速率超规格。分频算的 21MHz但线长超过 10cm 或负载重SCK 振铃、建立保持时间不够偶发错字节。先降一档/8验证线短再往上提。5. 想只读却用 Transmit。SPI 收数据必须有 SCK而 SCK 只在发的时候跑。你只调HAL_SPI_Transmit想读从机没被时钟驱动啥也收不到。只读请用TransmitReceive或ReceiveHAL 会填 dummy 发时钟。6. 读 SPI Flash 没等 WIP 忙。Flash 写完/擦完内部要忙一阵状态寄存器 WIP 位为 1。你立刻读读到的可能是旧值或乱的。写/擦后先轮询Read Status Register等 WIP 清 0 再读。7. DMA 只开一个方向。SPI 全双工TX 和 RX 是两个独立 DMA 流。想全双工 DMA 必须 TX、RX 流都配只开 TX 收不到只开 RX 没时钟。单工场景纯发屏只开 TX 没问题。完成回调是HAL_SPI_TxCpltCallback/HAL_SPI_TxRxCpltCallback不是 UART 那套。8. 16 位帧高低字节错。有些 DAC/ADC 一帧 16 位。你Data Size配 16bit但发的数组是uint8_t[2]HAL 按 16 位搬会把两个字节当成一个数高低字节反掉。16 位帧必须用uint16_t数组。9. MSB/LSB first 不一致。默认 MSB First绝大多数器件也这么要。少数器件某些老 LCD 控制器要 LSB First你没改First Bit数据整串反的。翻手册确认。10. 半双工/三线器件错配成全双工。有些 SPI 器件是三线半双工MISO/MOSI 合一或双线/四线那是 QSPI另算。你按全双工配了四根线MISO 悬空读到的就是随机噪声。先数清楚器件到底是几根线。完整例程骨架intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_SPI1_Init();cs_high_all();uint8_tid[3];cs_low();uint8_tcmd0x9F;// Read JEDEC IDHAL_SPI_Transmit(hspi1,cmd,1,100);HAL_SPI_Receive(hspi1,id,3,100);cs_high();// id[0..2] 厂商/内存类型/容量while(1){/* ... 刷屏 / 读写 Flash ... */}}适合TFT 屏、SPI Flash/SD 卡、IMU 裸数据流、高速 ADC/DAC 这类要速率、要全双工、不在乎多几根线的大块数据传输。不适合板子上器件多又不想多占引脚的慢速控制面那种用 I2C 更省线。铁律三条CPOL/CPHA 严格照从机手册配、软件片选每次传输前后必须拉低拉高、只读操作也要发时钟用 Receive/TransmitReceive。把这三条焊死SPI 基本一次跑通。SPI 解决了快但它是点对点、靠 CS 挨个轮询的器件一多 CS 线爆炸而且没有应答机制、传错了你不知道。要一堆节点平等地挂在两条差分线上、自带仲裁和校验、错了能重发就得上 CAN。进阶玩法CAN 怎么在嘈杂的现场总线里稳住。

相关新闻

给样本,比讲规则管用:我花了 20 多天,把 Hermes Agent 训练成能独立交付的 Dify 开发助手

给样本,比讲规则管用:我花了 20 多天,把 Hermes Agent 训练成能独立交付的 Dify 开发助手

给样本,比讲规则管用:我花了 20 多天,把 Hermes Agent 训练成能独立交付的 Dify 开发助手作者前言:本文由我与 AI 协作完成,数据来源于 2026 年 7 月至 8 月的本地真实交付记录,可溯源、可验证。旨在分享 A…

2026/9/21 14:03:45 阅读更多 →
基于Nemotron-3与.NET构建私有化长上下文对话系统实战

基于Nemotron-3与.NET构建私有化长上下文对话系统实战

1. 项目缘起:从“一问一答”到“有记忆的对话” 最近在折腾一个智能客服的原型,发现了一个挺普遍的问题:用户问“我昨天咨询的那个订单怎么样了?”,系统要么一脸懵,要么就得让用户再报一遍订单号。这背后的…

2026/9/21 14:04:24 阅读更多 →
产业变局下的渠道革命:工业液压渠道服务商从信息不对称到技术赋能的蜕变

产业变局下的渠道革命:工业液压渠道服务商从信息不对称到技术赋能的蜕变

一、液压产业变革期,渠道服务商迎来价值重构全球液压市场规模2025年已达476.7亿美元,中国是全球最大液压生产国与消费国,2025年国内市场规模达1200亿元,同比增长12.5%,预计2030年将突破1850亿元。工程机械占45%以上市场…

2026/9/18 17:36:48 阅读更多 →

最新新闻

i9-12900KF与RTX 3070 Ti超频调校:从散热瓶颈到性能全面释放

i9-12900KF与RTX 3070 Ti超频调校:从散热瓶颈到性能全面释放

先交代一下背景。这套i9-12900KF加RTX 3070 Ti的主机是我去年下半年自己组装的,平时主要用来跑2K分辨率下的各种3A大作和日常剪辑渲染。刚装完那会儿,性能确实够用,但我总觉得不太对劲——具体说就是显卡负载一高,风扇声音开始撕心…

2026/9/21 14:06:18 阅读更多 →
Optimistic Rollup架构解析与开发实战指南

Optimistic Rollup架构解析与开发实战指南

1. 为什么我们需要理解Optimistic Rollup?区块链扩容问题就像早高峰的地铁1号线——所有人都挤在同一个狭小空间里,交易确认慢如蜗牛,手续费高得离谱。作为在以太坊生态摸爬滚打五年的老开发,我亲眼见证Layer2解决方案如何从理论构…

2026/9/21 14:06:18 阅读更多 →
ipmitool带内配置BMC管理IP:从原理到实战的完整指南

ipmitool带内配置BMC管理IP:从原理到实战的完整指南

前两天在机房给一台X86服务器做初始配置,系统装完了,网卡也通了,结果发现BMC管理口的IP还停留在出厂默认值。手边没有显示器,KVM切换器也被同事借走了,这时候最顺手的办法,就是通过操作系统内部用ipmitool做…

2026/9/21 14:06:18 阅读更多 →
Win11下华为手机无法识别?ew_usbccgpfilter.sys驱动修复指南

Win11下华为手机无法识别?ew_usbccgpfilter.sys驱动修复指南

每次新装Win11,或者某次系统更新完之后,华为手机插上电脑只剩“嘀嘀”两声,文件管理里死活不出现手机盘符,设备管理器里却躺着一个黄色感叹号的“USB Composite Device”——这个场景如果你熟,那大概率就是今天要聊的这…

2026/9/21 14:06:18 阅读更多 →
Ubuntu 20.04下AirPods配对与音频优化全指南

Ubuntu 20.04下AirPods配对与音频优化全指南

1. 为什么AirPods在Ubuntu 20.04上“像块砖”?——从协议栈底层看配对失败的真正原因你刚把AirPods从充电盒里拿出来,打开盖子,耳机指示灯亮起白色,手机秒连,但转头切到Ubuntu 20.04笔记本——蓝牙图标右下角那个小齿轮…

2026/9/21 14:06:18 阅读更多 →
SSM框架实现健身房数字化管理系统设计与优化

SSM框架实现健身房数字化管理系统设计与优化

1. 项目概述:当健身房遇上数字化管理去年帮本地一家中型健身房改造会员系统时,我深刻体会到传统纸质登记表的痛点——教练排课冲突、会员预约信息丢失、打卡记录混乱等问题频发。这个基于SSM框架的健身房管理系统,正是为了解决这些行业普遍存…

2026/9/21 14:05:17 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

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

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

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

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

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

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

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →