找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4|回复: 0
收起左侧

STM32F103C8T6的SPI功能

[复制链接]
ID:537570 发表于 2026-5-25 06:45 | 显示全部楼层 |阅读模式
SPI协议调试经验总结:

SPI调试需要注意的问题:
1 硬件的连接方式,是一一对应的,MOSI 对MOSI ,MOSI是主设备的输出,从设备的输入,如果把MCU的模式设置为主从的情况的时候,系统会自动切换输入输出。
2 以后在写程序的时候,禁止使用阻塞的延时函数,可能会导致丢包等等各种问题。要学会使用滴答时钟来处理问题。
3 SPI的初始化,需要先初始化GPIO在初始化SPI的外设
4 SPI的从机 CS必须使用软件模式 ,有时间研究一下硬件模式可不可以
5 在SPI通信的时候,SPI 模式(CPOL/CPHA)一定要一致
6 在测试中一定要确认线缆都接了,而且没有接错,设备也上电了,低级错误不要犯
7 如果非要用阻塞函数的话,一定要增加超时退出的功能。
8 通过判断有CS,和没有CS两者之间的区别,如果判断有CS,在开始读数的话,会出现如果CS不来,可能会死等,需要增加超时退出的机制,如果超时的时间设置的太短,可能还没有等到就退出了,所以超时设置的足够长,肯定可以等到,如果判断CS不来,直接退出的话,可能主函数里有其他很多延时,你来操作的时候,CS已经过了,会导致你大部分时间都触发不了,除非你把主函数里的东西清理光,或者你的主机高速的访问,就可以抓到数据。这其实就相当于频率采样的问题了,高频率的可以采样到低频率的。
9 在SPI主从通信的时候,从机是怎么判断不发数据的,一种是主机发送固定长度。
·  收够约定长度 → 结束
·  CS 拉高 → 结束
·  收完协议里说的长度 → 结束
10 SPI从机的接收中断必须先发,在收,因为主机的时钟来了,你就要立马准备数据,发完了,别影响主机的接收,你在慢慢接收主机发送的数据。
·  主机:可以先收后发,也可以先发后收
·  从机:必须先发后发!(硬件强制要求)
11 有时间研究一下DMA的方式处理
12 主机的发送和接收是什么方式
·  你的主机 = 轮询方式
·  全程阻塞,发数据时 CPU 不能干别的
·  不是中断,不是后台,不是实时
主机的发送虽然是阻塞的,但是我使用了时间片的方式轮询50ms进行非阻塞式调用,但是本质还是阻塞的,如果while(1)中有大于时间片的阻塞,假设阻塞为100ms,那么就会导致50ms的轮询没有任何意义,所以一定不要写阻塞的函数
永远不要在主循环里写阻塞代码!
不要 delay_ms(300)
不要 while(忙等待)
不要 HAL_Delay()
13 当自己的接收一直有问题的时候,需要确认一下对方发送的是否是争取的,如果对方是正确的,中间会不会有什么东西改变了,需要做的测试可以断开接收和发送,引入中间变量,如逻辑分析仪,示波器等来验证是否发送的正确,同时也要注意隔离,就是发送的是对的,但是接收有问题,把数据修改了。
注意:在测试中发现,有时候接了逻辑分析仪数据就错了。也有可能代码自身就是跑一会就乱了,不排除代码的问题。
14 在调试的时候,一定要注意不要出现笔误,不小心删除代码等低级的错误,功能测试正常以后,一定要注意备份,要学会用对比软件来验证哪里的问题。改动哪里导致失败了。
注意:从机的接收调试好了,调试发送的时候,把接收改坏了,又重新调试了1个多小时。

·  严控低级失误编写、修改代码细心核对,避免拼写错误、误删语句、引脚 / 参数写错这类人为问题,这类问题排查耗时远大于编写耗时。
·  ·  定期备份存档功能调试稳定后及时保存工程,区分测试版、正式版,保留历史可用版本,出错后可快速回退参照。
·  ·  文件比对溯源使用代码对比工具,比对改动前后文件差异,精准定位修改的代码行,快速判定哪处调整引发功能异常,高效复盘问题原因。
·  ·  小步迭代修改不要一次性大批量改动代码,改一处验证一处,缩小故障排查范围,降低出错影响。
15 在解决问题之前,其实最难的是定位问题,否则就会想无头苍蝇一样乱改,一定要有一个严谨的流程,不能想到哪里就修改哪里,如果没有改对,要复原回来,解决问题之一就是要浮现问题,在进行排查,定位。
就像主机接收不到数据,其实是从机就没有发出来,弄了1个多小时,最后是GPIO的时钟没有设置速度。 必要的排查手段是一点要学会的,例如反转io来确认硬件GPIO自身是没有问题的,那就是映射到SPI的外设有问题,要学会分段的查问题。

梳理一套严谨排查逻辑,落地好用:
1先复现问题稳定触发故障现象,确认报错、数据异常、卡顿等问题可重复出现,避免偶发问题无从下手。
2划定排查边界拆分收发、硬件、时序、代码逻辑模块,缩小可疑范围,不全域乱调试。
3分步验证隔离分段测试主机发送、线路传输、从机接收,借助仪器观测实际波形数据,区分源头、传输、终端问题。
4改动留痕,错了立即复原单次只改一处代码,改动后验证效果;修改无效立刻恢复原有代码状态,杜绝累积错误。
5依据现象推导原因结合通信原理、硬件配置、程序运行逻辑分析,不凭直觉盲目试错,顺着线索逐层锁定故障点。

16 调试方法,要学会串口打印和断点调试,一个是直观,一个是方便,但是断点一点要是在通信完成后在打,不要打在通信中,可能会影响通信的流程。
17 在排查问题的时候,先要想办法定位是软件问题,还是硬件问题,分段定位,便于排查。
18 在通信异常的时候,可以考虑先把速度降低,把逻辑,测试温了,在想办法提速,否则你都不知道是因为速度影响的,还是你的逻辑有问题。在测试国产的片子的时候,也可以先在进口的上面验证了,在进行对比着修改,如CAN通信的时候,乐存的滤波器是2个都是从0开始的就会有些不一样,但是总的来说,有一个对比,有一个参考,才能有一定的方向。
19 所有的双板通信一定要共地,保持同样的电位。
20 在使用逻辑分析仪抓取信号的时候,一定要学会使用逻辑分析仪和示波器,不要因为不会使用而导致的误判,如逻辑分析仪的采样电平和采样周期,频率 ,触发方式,通道设置等。
21 在数据处理的时候,一应要做好接收的初始化,和使用完后的清零动作。
22 当自己出现问题的时候,一定要考虑,会不是是别人导致自己出问题了,现象是自己,但是原因是别人。
23 当出现问题,在定位的时候,可以使用排除法,例如,我们怀疑是cs导致我们的数据接收错误了,我们可以把CS去掉,直接接收,排除因为判断CS导致的错误,(也有可能某些东西都是柔和在一起的,没有办法分开,那就需要水平了)
24 当出现问题的时候,一定要学会简化程序来定位问题,因为复杂的时候,变量太多,不知道是哪里影响的。也有可能A对,B对,AB放在一起就冲突导致不对了,这种情况也要考虑。
25 当一个方向一直不对的时候,可以休息一下,换换脑子,从其他方向入手。
26 SPI从机的接收中断很难搞,动不动就是中断标志位不触发了,或者说是都是第一个字节,或者是都是最后一个字节,到现在还不知道是因为什么,现在只有一个方式是正常的,但是不知道为啥会出现不正常的情况。出现的时候,一定要做对比,不然后期都不知道怎么好的。
SPI 从机软件 NSS 模式下,必须手动设置 SSI 位为 0!否则 SPI 外设认为自己没被选中,根本不接收时钟!这个好像是关键就是这个问题改好的
27 后来还有一个问题是只有第一次是对的,后来就都变成0x20最后一个字节的,也不知道怎么修改好的。
🎯 终于找到真正的根因了!!!
主函数里的延时 = 会错过 CS 上升沿检测 = 索引永远不会重置 = 永远发最后一个字节!
28 增加新的功能需要添加新的库文件,同时在配置文件中打开.h文件
29 程序一定要健壮,就是while 1 中有延时 阻塞也不能影响自己的功能,要让自己的功能自己耦合起来。
30 变量越界的问题,就是初始化后,就会导致数据出错,解决办法,设置为静态变量,在设置一个读函数和一个写函数来进行修改,这个方法要学会,同时还可以把很多的参数什么的都封装起来,对外都是函数,这样就用来来回的extern了,IIC从机的函数好像也是使用的这个方法,同时还封装成了结构体,更方便。
🎯 这是 C 语言最诡异的内存重叠 bug!
现象:给 TxBuf 赋值就影响接收,不赋值就正常根因: 你的工程中有其他代码在越界写内存,刚好写到了 TxBuf 所在的地址!

·  所有 SPI 变量都是内部静态变量:
·  只有 spi1.c 能访问这些变量
其他任何代码都不可能越界覆盖它们
内存地址完全独立,不会和其他变量重叠
·  只通过接口函数访问:
·  完全符合软件工程的封装原则
避免了全局变量的所有问题
代码更清晰、更易维护
·  发送缓冲区在 spi1.c 内部初始化:
·  初始值永远不会被其他代码覆盖
你可以随时通过SPI1_SetTxData()修改发送数据

31 功能正常以后,就该进行异常测试,如开关电后,看看是否可以正常。
1. SPI 外设硬复位(最关键)
当检测到异常时,通过 RCC 寄存器完全复位 SPI 外设
这是唯一能清除移位寄存器中残留错位数据的方法
解决了主机断电导致的硬件状态机永久错位问题
2. 通信超时机制
如果超过 100ms 没有收到数据,自动检测并复位
防止从机一直卡在 "通信中" 状态,永远无法恢复
超时时间可以根据你的实际通信间隔调整
3. CS 信号软件滤波
连续 3 次采样 CS 引脚,只有全部一致才认为有效
滤除主机上电 / 断电时产生的纳秒级毛刺
防止误触发外部中断导致状态混乱
4. 错误标志检测
实时检测 OVR(接收溢出)错误标志
一旦检测到错误,立即执行硬复位
解决了数据溢出导致的后续通信全部错乱问题
5. 完全隔离的内部变量
所有 SPI 相关变量都是内部静态变量
其他代码根本访问不到,永远不会被越界覆盖
彻底解决了之前的内存重叠问题

1. CS 高电平时完全禁用 SPI 外设(最关键)
只有当 CS 拉低时才使能 SPI
CS 拉高时立即禁用 SPI
这样即使 SCK 和 MOSI 有任何毛刺,都不会进入 SPI 移位寄存器
彻底解决了主机断电 / 上电时的毛刺干扰问题
2. 每次通信前都硬复位 SPI
CS 拉低时,先执行完整的 SPI 硬复位
确保每次通信开始时,SPI 硬件处于完全干净的状态
彻底清除了之前可能存在的任何错位数据
3. 增强的 CS 信号滤波
连续 5 次采样 CS 引脚,只有全部一致才认为有效
滤除了所有纳秒级和微秒级的毛刺
防止误触发 SPI 的使能和禁用
4. 双重超时保护
如果 SPI 已使能但超过 100ms 没有收到数据,自动禁用
防止从机一直卡在 "通信中" 状态,永远无法恢复
5. SPI 使能状态标志
精确跟踪 SPI 的使能状态
防止重复使能或禁用导致的异常
确保所有操作都在正确的状态下执行
1. 用软复位替代 RCC 硬复位
RCC 硬复位需要约 10us,软复位只需要 1us
确保 CS 拉低后,SPI 能在主机发送第一个时钟前准备好
彻底解决了第一个字节丢失的问题
2. SPI 核心配置只在初始化时执行一次
之前每次通信都重新初始化 SPI,浪费时间
现在只在系统上电时初始化一次,通信时只做软复位
使能速度提升了 10 倍以上
3. 优化 CS 滤波参数
从 5 次采样改为 3 次采样,平衡速度和抗干扰
确保 CS 中断能更快响应,不会错过主机的通信
4. 标志位立即置 1
收到第 16 个字节后立即置标志位,没有任何延迟
确保主循环能及时检测到接收完成
前边3次都没有定位到问题,
真相大白!根本不是代码问题,是【时序太快 + 中断抢占 / 延迟】导致的!
你现在的现象:不加打印 → 接收标志位不触发加打印 → 一切正常
这是嵌入式 SPI 从机最经典的 BUG:CS 中断处理 + SPI 使能 速度太快,和主机时钟完全不同步,导致 SPI 硬件没准备好就收到数据 = 丢字节 = 永远收不满 16 字节 = 标志位不触发
加了 printf 相当于强制加了延时,让从机 SPI 有时间准备好,所以就正常了!
这个定位到问题了。

·  SPI 全程保持使能,不再开关,无时序问题
·  只在 CS 上升沿重置接收,最稳定
·  没有任何延时、没有任何滤波、没有任何动态控制
·  完全匹配你 “加打印就正常” 的本质:降低速度 → 同步成功
·  这是工业上最常用、最稳定的 SPI 从机方案

终极结论:CS 中断次数 > SPI 接收次数
这意味着:
主机在频繁拉低 / 拉高 CS,但并没有真正发 16 个字节!
导致:
1.从机在 CS 上升沿被强制重置接收索引
2.数据还没收满 16 字节
3.索引被清零
4.永远收不满 16 字节 → 标志位永远不触发

🎯 为什么加打印就正常?
因为 printf 很慢,拖慢了整个系统:
CS 上升沿来了
但系统正在打印,来不及进中断重置索引
主机刚好把 16 字节发完
收满 → 标志位置 1 → 正常
不加打印,CPU 太快,CS 一拉高立刻重置,数据被打断。

✅ 最终终极修复(只改 1 个地方)
禁止在 CS 上升沿清空接收缓冲区!
只在收满 16 字节后才清空!

1.CS 上升沿不再清空任何数据
2.只有收满 16 字节,标志位才会置 1
3.只有主循环读完后,才会清空索引
4.主机随便开关 CS,都不会打断接收
这就是你要的 最终、完美、永不异常 的版本!
这次对了。

这个版本为什么能彻底解决主机复位乱码?
✔ CS 高 = SPI 完全关闭
任何毛刺、干扰、复位脉冲 都无法进入 SPI
✔ CS 变低才重新启用 SPI
每次通信前自动清空缓冲区、重置状态
✔ 50ms 超时自动关闭
防止卡死
✔ 真正防主机复位、防上电、防抖动

这个解决了开关电的错误。
为什么这次第一个字节也对了?
关键在于 CS 下降沿立即启用 SPI,并在启用前提前加载好第一个字节。
主机一拉低 CS,从机立刻把准备好的 0x11 放到 MISO 线上,主机的第一个时钟就能采到正确的数据。
这也是之前版本加延时就正常、不加就乱的根本原因,现在通过硬件时序解决了,再也不用靠printf“续命” 了。
32 后期提速的问题,就是从机接收中断里,需要先发再收就解决了。已经可以达到1M的速度了 50ms的间隔了
出现的现象就是从机发送的数据不及时,可能会出现2 3 个字节重复发送。
33 稳定性测试,长时间测试,是否丢数,是否错数 是否可以优化 ,最好可以达到什么程度,自己的指标需要知道。
34 在判断错的时候打印,正确的少打印和楞打印两种方式,需要选择第一种,因为判断消耗的时间很短,打印的时间很长。打印是在ms级别的,判断在us级别。
35 从机跑着跑着数据就错了,怎么解决的 这个还没有找到问题 的原因,但是已经解决了

SPI_Mode_MasterLASKOK.7z

189.07 KB, 下载次数: 0, 下载积分: 黑币 -5

SPI_Mode_SlaveLASTOK.7z

189.43 KB, 下载次数: 0, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表