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/10/17 11:30:50 阅读更多 →
基于Nemotron-3与.NET构建私有化长上下文对话系统实战

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

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

2026/10/17 8:07:34 阅读更多 →
产业变局下的渠道革命:工业液压渠道服务商从信息不对称到技术赋能的蜕变

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

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

2026/10/16 14:09:45 阅读更多 →

最新新闻

ST-GCN骨骼动作识别实战:从环境配置到毕设级部署

ST-GCN骨骼动作识别实战:从环境配置到毕设级部署

简介:本资源是一套基于时空图卷积网络(ST-GCN)实现骨骼动作识别的完整毕业设计项目,面向计算机、人工智能及相关专业本科生,专为毕设开发、课程设计与深度学习实战训练打造。项目已通过导师审核并获98分高分评价&#…

2026/10/18 5:43:43 阅读更多 →
大数据场景下的数据清洗全攻略:从质量维度到管道实践

大数据场景下的数据清洗全攻略:从质量维度到管道实践

干数据这行的人,大概都有过这种经历:任务名写着“分析用户行为”,开工第一周却在清空表、补字段、调格式;跑完模型看指标,训练集漂亮得不行,一到验证集就崩盘,最后查来查去,问题出在…

2026/10/18 5:43:43 阅读更多 →
DSP28335上UCOSII移植与CANopen协议栈融合实践

DSP28335上UCOSII移植与CANopen协议栈融合实践

简介:面向数字信号处理器嵌入式开发者的实时操作系统与工业总线应用资料包,以TI TMS320F28335为平台,完整演示uC/OS-II移植流程以及基于CANOpen协议的Copley驱动器控制方法。压缩包共包含264个文件,整体约1.64MB,文件类…

2026/10/18 5:43:43 阅读更多 →
瞬变电磁测深原理与数据处理:从瞬态响应到视电阻率反演

瞬变电磁测深原理与数据处理:从瞬态响应到视电阻率反演

1. 从“看电阻率”到“看时间”:瞬变电磁法的底层逻辑做物探的人都知道,直流电法看的是稳定电流场,频率域电磁法看的是谐变场,而瞬变电磁测深(TEM)完全换了条思路——它不靠稳态,靠的是“断电后…

2026/10/18 5:43:43 阅读更多 →
Flutter for OpenHarmony实战:剧本杀记录页设计与踩坑记录

Flutter for OpenHarmony实战:剧本杀记录页设计与踩坑记录

做这个“Flutter for OpenHarmony 剧本杀组队App”的记录展示功能,前后磨了两个多星期,踩了不少OpenHarmony生态里特有的坑。这篇文章把游戏记录展示从数据模型、本地存储、列表UI到状态管理的实现过程完整梳理一遍,重点说清楚“为什么这么设…

2026/10/18 5:43:43 阅读更多 →
俳句翻译实战拆解:从17音、季语到切れ字的基本功

俳句翻译实战拆解:从17音、季语到切れ字的基本功

把一首十七个音节的日本俳句翻译成中文,好的译文不是让你读通,而是让你在句号之后多停一秒。我最近在整理一份署名译者的《芭蕉俳句》四首选原译稿,所谓原译,就是直接从芭蕉的日语原文译出,不经过英译本或者其他语种的…

2026/10/18 5:42:43 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/16 14:23:36 阅读更多 →