搞嵌入式的没有不跟SPI打交道的,但恰恰是这个看起来最简单的协议,坑了我很久。直线接线没问题、逻辑分析仪上波形也有,屏就是不亮;换一个传感器模块,读出来的数据全是0xFF;把某个外设往总线上多挂一路,原来的设备直接罢工。这些问题我当年一个个都踩过,回头排查才知道根子上全是SPI的细节理解不到位。
这篇文章我把自己用SPI这几年踩过的坑、总结出的规律梳理一遍。从四根线到底怎么分工,到CPOL/CPHA时序模式怎么看数据手册,再到硬件片选和软件片选怎么选、一根总线挂多个从机要注意什么、硬件SPI不够用时怎么用GPIO模拟,最后把SPI和IIC、UART放在一起做个选型对比。内容全是实战里磨出来的经验,适合正在用STM32、ESP32、Arduino做项目,或者在调SPI屏幕、Flash、SD卡、各种传感器的朋友。
1. 先搞清楚SPI在解决什么问题,再去背四根线的名字
很多人学SPI,上来就背SCLK、MOSI、MISO、CS,背完就懵。我建议反过来想:SPI是被什么需求逼出来的。
1.1 为什么需要一种新的串行协议
早年的板级通信,UART是主力,但UART有个先天性缺陷——异步通信,收发两边各用各的时钟。你要发数据,就得提前约定波特率,两边时钟稍微有点偏差,数据就错位了。而且UART只能点对点,一台主机想同时跟多个外设通信,得接多路串口,管脚根本不够用。
后来IIC出现了,用两根线挂一堆设备,省管脚,还有地址机制。但IIC速度上不去,标准模式100kbps,快速模式也就400kbps,到了1Mbps已经属于高速模式,对时序要求还特别苛刻。我当年试图用IIC去读一颗200万像素的摄像头寄存器,光初始化配置就得小一秒,根本没法用。
在这个背景下,SPI就是冲着两个核心诉求去的:一是快,二是简单粗暴。它把时钟线单独拉出来,主机产生时钟、从机跟着时钟走,没有波特率对齐的问题,也没有地址帧、应答位的开销。时钟能拉到多高,取决于PCB走线和从机能跑多快。几十MHz非常常见。这就是SPI至今在中低速板级通信里不可替代的根本原因。
1.2 四根线各管什么事
SPI是主从结构,一个主机可以挂多个从机,最少只需要四根线,但注意——这个"最少"是有条件的,你挂的从机越多,片选线就越多。
- SCLK:串行时钟,由主机产生,从机只能被动接收。时钟的频率就是数据传输速率的核心参数之一。
- MOSI:Master Out Slave In,主机输出、从机输入。主机要发给从机的数据,通过这根线一位一位传过去。
- MISO:Master In Slave Out,从机输出、主机输入。从机回给主机的数据走这根线。
- CS/SS:片选信号,通常是低电平有效。主机把某个从机的CS拉低,等于告诉它"我要跟你说话",其他CS保持高电平的从机就闭嘴,MISO输出呈高阻态。
这里有个新手最容易忽略的点:SPI是全双工。MOSI和MISO是两根独立的线,主机发数据的同时,从机也在往MISO上放数据。所以一次SPI传输,读和写是同时完成的。这个特性直接影响后面对代码和时序的理解——很多人不理解为什么SPI读Flash要先发一个空字节,其实那个空字节就是时钟的"载体",没有MOSI上的数据,SCLK也得继续跑,从机才能把数据推出来。
1.3 主从结构带来的一个隐含约束
因为是主机负责产生时钟,所以SPI总线上的所有活动,必须由主机主动发起。从机没有时钟,它永远不会主动说话。这个特点既是优点也是限制:优点是好控制,主机想什么时候通信就什么时候通信;限制是如果某个从机有紧急事件需要通知主机,它只能靠另外一根中断线拉个引脚,SPI协议本身没有"从机主动上报"的机制。设计系统架构时,这一点要先想清楚,别等到做项目了才发现某个传感器需要实时上报,结果SPI总线这边还在轮询。
2. 时序模式是SPI一半的坑:CPOL、CPHA与数据手册该怎么读
说实话,SPI通信里我见过最多的问题,不是接线接错,而是时序模式对不上。主机和从机一个按模式0工作,一个按模式2工作,波形看起来都有,数据就是乱码。这一章我把这块彻底讲透。
2.1 从波形图看懂CPOL和CPHA
SPI的时序模式由两个参数决定:CPOL(Clock Polarity,时钟极性)和CPHA(Clock Phase,时钟相位)。
CPOL决定的是SCLK的空闲电平——就是不传数据的时候,时钟线停在什么电平。CPOL=0,空闲低电平;CPOL=1,空闲高电平。
CPHA决定的是数据在哪个边沿被采样。CPHA=0,在第一个边沿采样;CPHA=1,在第二个边沿采样。这里"第一个边沿"和"第二个边沿"要结合CPOL来理解:如果CPOL=0,时钟空闲是低电平,那第一个有效边沿就是上升沿;如果CPOL=1,时钟空闲是高电平,第一个有效边沿反而是下降沿。
两个参数一组合,就是四种模式:
| 模式 | CPOL | CPHA | 空闲电平 | 第一个边沿 | 采样边沿 |
|---|---|---|---|---|---|
| Mode 0 | 0 | 0 | 低电平 | 上升沿 | 上升沿 |
| Mode 1 | 0 | 1 | 低电平 | 上升沿 | 下降沿 |
| Mode 2 | 1 | 0 | 高电平 | 下降沿 | 下降沿 |
| Mode 3 | 1 | 1 | 高电平 | 下降沿 | 上升沿 |
2.2 绝大多数设备用的都是Mode 0或Mode 3
实战里最常用的就是Mode 0(CPOL=0, CPHA=0),其次Mode 3(CPOL=1, CPHA=1)。为什么是这两个?因为SPI协议规范里对默认状态推荐的是极性和相位都为0或都为1,这两种模式足够覆盖绝大多数Flash芯片、SD卡、屏幕驱动、传感器模块。
Mode 1和Mode 2不是没有,但少见得多。所以如果你手里有一颗不认识的芯片,又没有数据手册,先试Mode 0,不行就试Mode 3,大概率能通。
2.3 数据手册里怎么定位时序模式
很多数据手册不会直接写"Mode 0"这几个字,需要你自己看图。这里我教一个很实用的方法:找到手册里的SPI时序图(SPI Timing Diagram),看三样东西。
第一,看SCLK空闲时是低还是高,就能确定CPOL。第二,看数据的稳定区出现在第一个边沿还是第二个边沿附近,如果数据在上升沿处稳定、下降沿处切换,说明是在上升沿采样,CPHA=0;反之则是CPHA=1。第三,很多手册还会给一张表格,里面有CPOL和CPHA或对应模式的说明,直接对照就行。
我见过最坑的一颗芯片是某国产陀螺仪,手册翻译得稀碎,时序图画成了Mode 1,结果实际是Mode 3,折腾了我半天。后来我学聪明了:直接用逻辑分析仪抓从机在已知频率下回的数据,换个模式试,哪种能解出正确ID就锁定哪种。
提示:买模块时优先选明确标注了SPI模式的成品模块,那种连时序模式都不标的模块,要么自己拿逻辑分析仪测,要么换一家买,别浪费项目时间。但如果必须用,可以按"先Mode 0后Mode 3、再Mode 2最后Mode 1"的顺序试,最快定位。
3. 片选决定成败:硬件NSS与GPIO软件片选怎么选
片选是SPI里最容易被低估的信号。很多人以为就是把CS拉低再拉高,结果遇到了各种莫名其妙的问界。
3.1 STM32硬件NSS的坑
STM32的SPI外设提供了硬件NSS功能:一种是NSS引脚由硬件自动控制,发送数据前自动拉低、发完后自动拉高;另一种是NSS输出模式,外设自己控制引脚状态。听起来很方便对吧?我当年也是这么想的,直到踩了坑。
坑在哪儿?硬件NSS的自动拉低/拉高时机,不是你想的那样干净利落。它在SPI传输完成但配置未清除时,可能会提前释放片选,导致从机认为本次传输结束,后面补的字节被当成新的一帧开头;而且它跟DMA、FIFO配合时行为更复杂。多层板子、高频时钟、长距离飞线,这些情况下硬件NSS很容易出诡异问题。
另外一个坑是引脚复用功能冲突。STM32的NSS脚经常和别的功能复用,你在CubeMX里开了硬件NSS,可能就把某个用得好好的GPIO或者别的外设引脚给顶掉了。
3.2 GPIO软件片选:简单、可控、推荐
我的建议是:除非有特殊需求,否则用普通GPIO做软件片选。逻辑上就是传输前把对应引脚拉低,传输完成后拉高。
// 软件片选控制示例(HAL库风格) #define CS_LOW() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET) #define CS_HIGH() HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET) // 读Flash ID uint8_t spi_read_flash_id(void) { uint8_t cmd = 0x9F; // JEDEC ID命令 uint8_t id = 0x00; CS_LOW(); HAL_SPI_TransmitReceive(&hspi1, &cmd, &id, 1, 100); CS_HIGH(); return id; }软件片选的好处有三个。第一,时机完全可控,你想在什么时候拉低、什么时候拉高,自己说了算,不会受外设状态机影响。第二,不占用专用NSS引脚,随便找个GPIO都能当片选,布局布线自由度大。第三,挂多个从机时,每个从机一个GPIO,逻辑一清二楚。
要注意的是,两个从机之间切换片选时,最好加一点间隔(比如几个微秒),不要一个CS刚拉高立刻拉低另一个。从机芯片内部需要时间完成当前帧的收尾,太快切换可能导致残留数据错位。我之前调一块屏幕和一颗Flash共用总线时,切换太快就会出现Flash偶尔读错地址的现象。
3.3 多从机场景的接线策略
一根SPI总线上挂多个从机,所有从机的SCLK、MOSI并在一起,MISO也并在一起,片选各自独立。这里有几个关键点必须注意。
MISO线是所有从机共用的,但同一时刻只能有一个从机在驱动这根线。所以从机在不被选中时,MISO必须呈高阻态,不能死顶着输出。绝大多数SPI从机芯片都是这么设计的,但个别廉价模块会在CS拉高后还拖个尾巴。遇到这种情况,要么在MISO上加个串联电阻缓冲,要么给每个从机MISO串一个小的三态缓冲器(比如74LVC1G125),成本不高但能保平安。
另外SCLK和MOSI在切换从机时,尽量保持在同一状态。很多从机是在CS下降沿才真正检测时钟边沿,如果CS拉低时SCLK刚好是一个毛刺,可能产生误触发。
4. 从CubeMX到逻辑分析仪:跑通一次真实SPI传输
这一章我带你把一次完整的SPI通信走通,从STM32CubeMX配置开始,到代码实现,再到用逻辑分析仪验证波形。这套流程我每次做新板子都会完整走一遍,能省掉后面80%的调试时间。
4.1 CubeMX里的关键配置项
打开CubeMX,选择一个SPI外设,你会看到一堆配置项。每项怎么填,对应什么底层逻辑,下面这个表格捋清楚了:
| 配置项 | 常见取值 | 说明 |
|---|---|---|
| Mode | Transmit Only / Full-Duplex等 | 根据外设需求选,读多写多选Full-Duplex |
| Prescaler | 4/8/16/32/64等 | 分频系数,决定实际SCLK频率 |
| Clock Polarity | Low / High | 对应CPOL,看从机手册 |
| Clock Phase | 1st Edge / 2nd Edge | 对应CPHA,看从机手册 |
| Data Size | 8 Bit为主 | 个别传感器用16位,必须匹配 |
| First Bit | MSB First为主 | 极少数从机要求LSB First |
| NSS | Software | 按上一章建议,优先软件片选 |
| CRC | Disable | 极少用,后文说明 |
Prescaler的计算逻辑很容易被忽略。STM32的SPI时钟源来自APB外设时钟,不同型号、不同总线配置,APB时钟不一样。如果你用的主频是170MHz,APB2外设时钟可能也是170MHz,Prescaler填8,SPI时钟就是170/8,约21MHz。有些屏幕模块最高只支持20MHz,你填个4倍分频就是42MHz,就会概率性花屏。所以务必先算清楚实际频率,再对一下从机的最高时钟限制。
4.2 基础收发代码框架
CubeMX生成初始化代码后,最常用的是HAL库的阻塞式收发接口:
// 写操作:发送buffer、不接收数据 HAL_StatusTypeDef status; status = HAL_SPI_Transmit(&hspi1, tx_buffer, len, timeout); // 读操作:先发命令/地址,再接收数据 HAL_StatusTypeDef status; status = HAL_SPI_Receive(&hspi1, rx_buffer, len, timeout);这个Receive接口内部其实也是全双工的,发送部分是空字节,不需要你手动处理。它的本质就是主机输出空数据产生时钟,从机在时钟驱动下把数据放到MISO上,主机把它采进来。
不过要注意,阻塞式收发在传输过程中会一直占用CPU,如果你的系统里还有其他实时任务(比如PID控制、WiFi协议栈),建议使用中断或DMA方式。中断方式用HAL_SPI_Transmit_IT,DMA方式用HAL_SPI_Transmit_DMA,本质逻辑一样,只是数据传输不占CPU。用DMA时记得开启SPI的DMA请求中断,否则你不知道什么时候传输完成。
4.3 逻辑分析仪验证波形
写代码从来不是终点,验证波形才是。我强烈建议每一个做嵌入式的人搞一个24MHz以上采样率的逻辑分析仪,二三十块钱已经够用,调试SPI的效率能翻倍。
接线很简单:把逻辑分析仪的CH0接SCLK、CH1接MOSI、CH2接MISO、CH3接CS,共地接好,然后用配套软件打开SPI协议解码器,设置CPOL和CPHA与你的配置一致,抓一次通信。
第一次抓波形,重点看三件事。第一,CS是不是在传输期间全程拉低,有没有中途抖动;第二,SCLK频率对不对,跟预想差多少;第三,MOSI上的数据和解码器解出来的数据,是否跟你的发送buffer一致。把这些确认好了,再去解码MISO上的回包,往往问题瞬间水落石出。
我遇到过最典型的一个问题:主板SPI走线太长,SCLK信号过冲,逻辑分析仪上显示频率正确,但屏就是偶尔白屏。后来在SCLK上串了一个33Ω电阻,问题直接消失,这就是信号完整性问题在SPI上的经典表现。高频走线时,串阻抑制振铃不是玄学,是必要的工程手段。
5. 一根总线上挂多个从机:屏幕与SD卡共享SPI的实战经验
ESP32、STM32这类主控的SPI外设数量是有限的,常常需要让一块屏幕和一张SD卡共用一根SPI总线。这个需求非常典型,但也非常容易出问题。
5.1 为什么两个器件能共享一根总线
本质原因就是前面讲的片选机制。SPI是主从之间点对点通信,但通过片选信号可以实现时分复用。同一时刻,只有一个从机的CS是低电平,其他从机的CS都是高电平,它们的MISO处于高阻态,不会影响主机的MISO采样。所以屏幕和SD卡共享SCLK、MOSI、MISO,各自用独立的CS脚,逻辑上完全可行。
我在做一个小型数据记录仪时,就是让ILI9341屏幕和MicroSD卡共用ESP32的VSPI总线。屏幕负责显示,SD卡负责存储。两个器件按时间片轮流占用总线,互不干扰,实测很稳。
5.2 共享总线时必须满足的三个条件
第一个条件:片选必须独立且软件可控。这个前面已经说过,硬件NSS在这种场景下基本没法用。第二个条件:两个从机的时序模式必须一致,或者至少都兼容同一个模式。屏幕和SD卡绝大多数都支持Mode 0或Mode 3,如果你选的屏幕只支持Mode 2,SD卡只支持Mode 0,那就要在两个器件切换时动态切换SPI的CPOL和CPHA,增加复杂度不说,还容易出错。第三个条件:MISO线必须在从机未选中时是高阻,否则两个从机同时驱动MISO,电平冲突直接烧引脚。
第三个条件不是所有模块都满足。我踩过一个坑:某TFT屏幕模块在CS拉高后,MISO依然被驱动为低电平,SD卡正常工作时,这根线被它拽住了,导致SD卡的数据读取随机失败。排查了很久才定位到,最后在屏的MISO上串了一个1kΩ电阻,问题解决。所以买模块前或者画板前,最好先看下模块原理图,确认MISO是否有三态控制。
5.3 共享总线时的速率与负载问题
屏幕和SD卡对时钟频率的要求通常不一样。屏幕为了刷新率高,能跑到20MHz甚至更高;SD卡就娇贵一些,虽然标称支持25MHz,但在飞线场景下跑到10MHz以上就容易出错。
我建议的做法是:把总线时钟设成两个器件都支持的较低值,然后优先保证SD卡的稳定性。屏幕刷新率不够,可以通过优化显示缓冲、只更新局部区域来弥补,而不是硬拉高SPI时钟。ESP32的SPI外设支持按每次传输设置不同的时钟频率,这个功能很实用——操作SD卡时用低速(比如10MHz),刷新屏幕时用高速(比如26MHz),两边需求都照顾到了。如果主控没有这种特性,简单粗暴地统一用较低频率反而是最稳的。
还有一个很多人不重视的问题——总线负载。SCLK和MOSI是共享的,走线分支多、器件引脚电容叠加,会让信号边沿变缓。SPI频率越高越明显。如果板子上挂了三个以上从机,SCLK上串个22-47Ω电阻做阻抗匹配非常重要,同时尽量让分支走线等长且短。
6. 硬件SPI不够用时的Plan B:IO口模拟三线SPI
不是所有场景都适合用硬件SPI。当你遇到资源不足、时序特殊、或者手头主控根本没有硬件SPI时,用GPIO模拟SPI是一个必须掌握的技能。
6.1 什么时候真的需要软件模拟
我知道很多人听到软件模拟SPI会觉得"低级",其实不是。真实场景里,软件模拟SPI反而是救命稻草。
一种典型场景是引脚不够。某些封装很小的MCU,比如TSSOP16、SOIC8里塞的芯片,硬件SPI模块虽然有,但引脚都在特定位置,跟你实际布局对不上。这时候用IO口模拟三线SPI,就能把SPI放在任意GPIO上,布线的自由度一下子大很多。另一种是外设过多:一颗STM32F103C8T6只有两个SPI,一块板子上挂了一颗屏幕、一块Flash、一个CAN控制器、一个编码器,硬件SPI完全不够分,剩下的设备就用软件模拟。还有一种特殊场景:某个从机的时序非常特殊,硬件SPI的模式、位宽、片选行为都满足不了它,只能靠GPIO一点一点抠时序。
6.2 模拟SPI的代码框架
软件模拟SPI的核心就是两个动作:拉高拉低SCLK模拟时钟,在合适的边沿往MOSI写数据或者从MISO读数据。以三线SPI(SCLK、MOSI、MISO)为例,一个简单的发送函数可以写成这样:
#define SCLK_HIGH() HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET) #define SCLK_LOW() HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_RESET) void spi_soft_write_byte(uint8_t data) { for (int i = 7; i >= 0; i--) { // MSB First if (data & (1 << i)) { MOSI_HIGH(); } else { MOSI_LOW(); } SCLK_HIGH(); // 上升沿,数据被采样 SCLK_LOW(); // 时钟恢复低电平 } }这是Mode 0(空闲低、上升沿采样)的写法。如果是Mode 3(空闲高、上升沿采样),初始化时要把SCLK拉到高电平,数据变换后在SCLK下降沿前保持稳定,然后下降沿让从机采样。
读操作跟写操作的差别在于:主机不需要关心MOSI上的数据,只需要在采样边沿把MISO的电平读进来。
uint8_t spi_soft_read_byte(void) { uint8_t data = 0; for (int i = 7; i >= 0; i--) { data <<= 1; SCLK_HIGH(); // 上升沿,从机把数据推到MISO data |= HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin); SCLK_LOW(); } return data; }6.3 软件模拟的时序与性能权衡
软件模拟的最大瓶颈是速度。一次简单的GPIO翻转加判断循环,在72MHz的STM32F103上大概要花几十纳秒,一个字节8个位,一帧可能还要加片选操作,算下来整体速率能跑到几MHz已经不错了。对SPI Flash的读操作这种纯数据搬运场景,软件模拟确实偏慢,但对传感器寄存器配置、LCD初始化这类低频操作,完全够用。
延时怎么加也有讲究。有些器件对SCLK的最小高低电平宽度有要求,比如手册写了最小SCK周期是200ns,那你翻转时钟后最好加一小段延迟(用for循环空转或者__NOP()),否则连续翻转太快,从机跟不上,表现为偶发数据错乱。加多长?按手册的时序参数来,留50%以上余量最稳妥。
软件模拟还有一个容易被忽视的细节:中断关闭。模拟SPI传输过程中,如果来了一个中断,GPIO电平状态在中断返回后可能跟期望的不一致,导致某一比特翻转丢失。所以在传输关键帧(比如Flash页写入)期间,临时关闭中断或临界区保护是很有必要的,否则偶尔的乱码会让你怀疑人生。
7. 别再用"快"来区分SPI和IIC:三组选型对比
每次一聊SPI,就有人拿IIC和UART一起来问。我总结了一套自己的对比框架,用物理层差异倒推应用场景,比单纯背"SPI快、IIC慢、UART简单"要靠谱得多。
7.1 物理层差异决定一切
UART是异步串行,收发双方各管各的时钟,所以必须约定波特率才能通信。它只需要TX和RX两根线,全双工,但没有时钟线,也就没有主从同步的概念,只能点对点。只要波特率一致、空闲电平都对,数据就能传,这是它协议最简单的一面。
IIC是同步串行,但它只有两根线——SCL时钟和SDA数据。数据线是双向的,半双工,同一时刻只能一个方向传输。它用地址机制解决多设备共享问题,每次传输主机发一个7位或10位地址选出从机,然后再传数据。少了片选线,代价就是传输效率低、时序要求严苛。
SPI是最"奢侈"的:时钟、发、收、片选四根线起步,全双工、速度快、协议开销几乎没有。但它的地址能力为零,多个从机完全靠片选线区分,从机数量越多,占用的GPIO越多。
7.2 什么时候用谁:一张表说清楚
| 对比维度 | SPI | IIC | UART |
|---|---|---|---|
| 线数 | 4根起步(SCLK/MOSI/MISO/CS) | 2根(SCL/SDA) | 2根(TX/RX) |
| 通信方式 | 同步+全双工 | 同步+半双工 | 异步+全双工 |
| 多从机能力 | 靠片选,从机多占管脚 | 靠地址,从机多不占管脚 | 点对点,不支持 |
| 速率 | 数十MHz级别 | 标准100k/400k,快速1M,高速3.4M | 取决于波特率,常用115200bps |
| 典型场景 | 屏幕、Flash、SD卡、ADC/DAC高速采样 | 传感器小数据量、RTC、EEPROM、温度计 | GPS模块、蓝牙模块、串口调试、工业设备 |
| 协议开销 | 几乎没有,裸数据 | 有地址帧、应答位,效率打折 | 有起始位、停止位、校验位 |
UART虽然慢,但在设备互联、长线传输、无线模块对接上仍然是最方便的,因为不需要共享时钟,双方各收各的,收发天然解耦。
7.3 数据手册上的"指纹"帮你快速判断
拿到一颗未知芯片,怎么快速判断它该用哪个协议?我以前的经验是看引脚数量和名字。
如果引脚里有SCL和SDA,那就是IIC;如果有SCLK/SCK加MOSI/MISO加CS,那就是SPI;如果只有RX和TX,那就是UART。这三组名字就是协议最清晰的指纹,几乎不会混淆。稍微特殊一点的是有些传感器同时支持IIC和SPI,通常通过某个引脚的电平或地址引脚选择模式,看手册里"It is possible to select I2C or SPI mode by..."这样的描述就能定位。
还有一个小提示:IIC的SCL和SDA外部必须接上拉电阻,SPI一般不需要(从机内部可能自带弱上拉或者直接推挽驱动),UART的TX/RX之间注意电平匹配、不要直接接RS232的电平。这几个细节在新手阶段最容易翻车,接口一接错,波形抓都抓不出来。
SPI这个协议,说实话,核心概念就那么几个:时钟、相位、片选、全双工。但每个细节展开都有实际工程的坑。最终我自己养成的习惯是:无论多简单的外设,上电后第一件事就是拿逻辑分析仪抓波形确认时序模式;无论多赶的项目,片选切换之间都留足余量;无论多贵的器件,都要核对一下最高SCLK限制。希望大家看完这篇文章,能在SPI这条路上少走一些我当年走过的弯路。