stm32调试问题

本文总结了STM32开发过程中的多个常见问题及其解决方法,包括printf函数使用、串口发送函数死锁、BOOT0配置问题、程序偶尔死机、下载程序需手动复位等问题,以及I2C、NVIC_Init等高级功能的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好多问题是自己或者别人遇到的,我只做了一个整理,绝对得收藏。

1、printf()函数

printf()函数可以直接向窗口格式化输出,给我们调试程序带来很大的方便,然而在Keil MDK环境下直接使用printf()函数就会陷入软件中断,导致死循环的产生;

 

2、串口发送函数卡在了这里 

卡在了下面的那个while()处,一直调试也没有结果。由于程序内部加入了独立看门狗,使得芯片一直复位。很长时间未找到原因。

后经过分析代码,发现原来此串口的初始化函数没有运行,而后直接调用了这句话,导致形成死循环。解决方法很简单,在初始化函数部分加入此串口的初始化代码,程序得以正常运行。

3、BOOT0

现象:采用JLINK下载程序后,断电让其上电重新启动,发现有时可以正常运行,有时候无法正常运行,大约每两、三次就有一次无法正常上电启动。通过JLINK调试程序,每次均正常运行。太诡异了!

发现问题后开始定位原因。首先考虑是BOOT启动出问题了,stm32f4启动方式分三种:User FLash、SystemFlash和EmbeddedSRAM,通过BOOT0和BOOT1管脚配置。程序正常运行时从User FLash启动,如果BOOT0和BOOT1配置不正确,会导致无法正常运行;而通过JLINK调试程序,程序直接下载到SRAM中运行,不存在此问题。于是,通过万用表测BOOT0和BOOT1管脚电平,都是低电平,没问题!于是,基本排除此原因了。

其次,考虑电源供电不稳定问题。通过万用表测量各个模块电压,发现电压均正常值。那也有可能是系统上电时刻,由于负载变化,导致电压跳变,之后电压又稳定了,所以测量不出来。通过示波器捕捉电压变化,未发现明显的异常跳变。通过万用表测电流为88mA,并不大。初步认为不是电源供电问题导致。

然后,考虑是否是由于复位信号不稳定的原因。板子采用了外置复位芯片,上电后会产生复位信号,此提供给处理器、蓝牙等模块。由于JLINK调试时会自动产生一个复位信号,让系统恢复默认状态,然后程序开始运行,因此调试下程序应该都能正常启动。但是如果程序断电后上电启动,如果复位信号过短或者不稳定,有可能导致无法正常启动了。完美的解释!哈哈,那一瞬间仿佛找到问题所在了。程序无法正常启动时,RESET信号手动接地(给一个低电平脉冲),处理器都开始工作了!这进一步验证了我的推断。于是锁定是复位信号不稳定导致的,开始折腾复位信号,通过示波器观察、隔离复位信号、加滤波电容、换复位芯片等方法进行定位。最后发现复位信号感觉也没有什么问题,真是怪了!纠结~~~~

后来有人建议是不是晶振不稳定。但是,晶振不稳定,调试程序时也应该出现同样现象啊,道理上解释不通啊。无解啊~~~

我们几人仔细琢磨了板子的原理图和实验现象后,他突然问你的BOOT0怎么没有接电阻到公共地啊?我说接了吧,之前还用万用表量过电平,是低电平。他说不对啊,就是没接地啊。我才猛地想起来,板子是另外一个同事焊的,交到我手里时说板子已经仔细检查过了,没问题。当时,由于项目紧张,就没有再仔细核实。我再仔细一看,确实没接地,也就是悬空状态!而之前测电压是低电平,有可能是由于下拉电阻的作用。崩溃了!这么粗心,居然没有自己检查。赶紧焊电阻接地,重新上电,发现正常了。测试了三四十次,都是正常的。看来这次真正找到原因了,就是由于BOOT0悬空而导致的。BOOT0悬空时,其状态是不确定的,会导致程序无法从UserFlash中正常启动,就可能出现时好时不好的现象了!哎,原来是这样。终于长嘘了一口气。

问题终于解决了,但是还是有一点无法理解:既然是BOOT0悬空引起的,但是为什么将处理器的RESET信号手动接地(给一个低电平脉冲),处理器又正常运行了?难道是因为再次复位上电重启时,恰好BOOT0又被识别为低电平?RESET信号影响了BOOT0的状态?看来还需要进一步做实验,才能解答此疑惑。
4、莫名其妙死机

问题描述:ZET6跑了ucosII系统,在运行过程中有时会出现死机的情况,经过硬件调试发现,是进入延时的时候导致的这个问题,延时函数是没有问题的,而且这个问题是偶尔出现
问题排查
死机之后指针指向了硬件错误中断,初步猜测是因为栈溢出,因为跑了系统,并且函数的嵌套层数比较多,导致栈内存不够,进入了硬件错误中断
解决方法
将函数分离出来,减少函数嵌套,因为每一个函数都会分配单独的内存空间,所以多层的函数嵌套就会有多个函数空间,解决办法就是减少函数嵌套,这样当一个函数执行完弹栈之后,它的内存空间就会被释放。
其他资料
使用keil编译程序的时候,会显示程序对内存的占用情况,其含义如下 
Code为程序代码部分
RO-data 表示 程序定义的常量 const temp;
RW-data 表示 已初始化的全局变量
ZI-data 表示 未初始化的全局变量
Total RO Size (Code + RO Data)
Total RW Size (RW Data + ZI Data)
Total ROM Size (Code + RO Data + RW Data)
初始化时RW-data从flash拷贝到RAM
可以修改程序定义的堆栈大小 
猜想因为申请了很多零时变量,可能需要调整Stack_Size
在STM32F10x.s文件中
修改Stack_Size EQU 0x00000200
成Stack_Size EQU 0x00000400
5、关于下载程序后,需要按复位按钮才能正常运行程序的问题。

问题描述: 下载程序后,一开始用SWD自动复位启动程序没有发现问题,后来调试完毕拔掉SWD接线后,重新开机代码不能运行,只有手动将单片机RESET(复位)接地后才能正常运行。

问题预测: 遇到问题后,一开始没有相关经验, 在网上找了很多资料,一方面是说在串口下载的时候,勾选了“编程到FLASH”一项,以至于在从内部存储器启动的时候无法运行;另一方面是说在FRAM没有进行初始化,需要进行一定的延时等等。但尝试后依旧无效,并且没有找到根源。

问题解决 
   此问题出现过两次,通过与正常程序的对比,发现第一次是将延时函数的初始化放到了时钟配置初始化函数的前面,导致延时函数无效,在初次运行程序时就会卡在第一个延时的地方。第二次是MP3模块上电初始化需要一定的延时,而单片机未等到模块初始化就跑完了代码,导致程序卡在MP3部分或根本忽略掉MP3模块。

小结 
根据网上的经验和个人经验,首先排除硬件如虚焊、晶振不起振等原因,在软件方面出现这种问题的原因可能有以下几种: 
①若是用串口下载,注意下载代码的存储区是否与BOOT配置不对应;若是SWD或JLINK下载,注意下载器的RESET是否一直处于有效状态。 
②确定时钟配置是否正确,且在其他功能函数之前,注意配置顺序,比如中断配置、延时函数、外设配置等。 
③检查外设模块,是否需要待其进行硬件本身初始化,如射频模块、音频播放、液晶屏、外设RAM等。 
4看看Rerst and Run 是否勾选。
6、使用strcat连接字符串出现乱码

问题描述: 使用strcat连接两个字符串后并通过串口打印出来,结果出现连接不完整或重复等现象。

问题预测: 初步估计是函数使用不当,因为该函数只能连接两个字符串。

问题解决: 修改字符串长度(数组长度)后,问题解决。

小结: 
很多乱码问题都是由内存分配不当引起的,内存不足或发生重叠即可能发生数据乱码现象,所以在对内存进行操作的时候要重点考虑内存分配问题。 
同时注意C语言的字符串实际上都是字符型的数组形式,只是以不同的方式来操作。

7、I2C

调试STM32的硬件I2C已经有很长一段时间了,几乎搜遍了所有资料,对于其到底能不能正常工作,今天做一个彻底的研究。

下面是我在测试中得到的几个结论:

1、硬件I2C的CLK在50kHz及以下的情况下工作,不会出现任何情况下的卡住。(本人测试时间为20h)

2、硬件I2C的CLK在常用的100kHz和400KHz下工作,99%的概率下会在1小时之内卡住,甚至只有几十秒。

3、硬件I2C的CLK在任何频率下工作,在读取或者发送数据时,都绝对不允许其它中断事件打断它的工作,否则一定会卡住,只是时间问题。

综上,硬件I2C的稳定工作情况是:工作在50kHz及以下,并且保证无其它任何中断打断它的工作。这样只适用于某些对速率要求不高的场所,比如EEPROM的读取等,而对于高速器件例如某些型号的AD芯片,就不能用了。

如果你一定需要高速率(400KHz),那么推荐大家使用STM32的替代方案GD32(兆易创新),它与STM32完全兼容但是解决了STM32的硬件I2C bug,经过本人实际测试,在400KHz的情况下工作,48小时无任何错误发生。但是仍需注意的是不能有外部中断打断I2C的工作。

对于ST公司推荐的将I2C工作在DMA和最高优先级的中断,我只能说大家可以根据自己的情况使用,因为如果你使用了ucos ii或者其它实时操作系统,那么这种设置最高优先级的方式是绝对不推荐的。如果你是裸机程序,并且任务数量不多,可以考虑这种DMA+中断的方式,否则一定会出现问题,只是测试时间长短问题。

最后需要说明的是:

(1)以上只是考虑了最纯粹的硬件I2C代码,对于某些使用了软件弥补的方法,例如在经常卡住的部分设置超时退出,不在本文的讨论范围内,因为这样已经破坏了正常的I2C协议。

(2)由于使用STM32的较高境界是使用中断调度任务而不是死等循环,而硬件I2C对于中断打断十分忌讳,所以随着你的编程和对操作系统理解水平的提高,你会越来越感觉STM32硬件I2C是个坑。

所以,STM32的硬件I2C确实是个坑,可以正常工作的环境要求十分苛刻,所以本人现在已转而使用GD32芯片。

8、NVIC_Init问题

问题描述:最近使用在STM32上使用ucosii的运行多任务时候遇到一个奇怪问题,我用到了4个串口,随着程序增大,出现了上电后不运行的情况,我用一个LED闪烁指示运行,使用STLINK进行debug没有问题,但重新上电运行就不行,硬件复位了也不行,排除了硬件问题、指针跑飞、任务堆栈溢出、卡死在某死循环 等可能性后,怀疑是哪句初始化问题,就屏蔽了所有初始化语句(LED的IO口配置除外),最后定位在一个串口的NVIC初始化语句上。

通过上网搜索“STM32不运行 NVIC_Init ”,看到有位朋友在论坛发帖求助,情况和我类似,最后他自己解决了,就是要清一下中断,然后我也在初始化中添加了清串口接收中断,果然就可以了。我记得在谁家的例程里我也看到过这样的操作,初始化里清一下串口接收中断,可能是芯片是一个bug。从道理上来说这个问题说不通,遇到这种情况的人也许不多,如果有遇到了类似情况的看到这个希望能有所启发。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值