keil调试程序的断点设置技巧及harddefault解决

这几天整同事留下来的项目的BOM,很简单的错误,弄的头大,看下文章分下神,值得尝试一下这个调试方法。

关于keil断点调试,断点窗口

程序运行过程中,有些数据被莫名修改了,在哪里修改的?又是怎么修改的?这个代码我只想知道是否运行过,或者运行了多少次,但是不想让程序停下来,或者仅打印调试信息,怎么办?当这个变量设置成某个数据后,我想让程序自动暂停下来进行分析,怎么办? 比如中断处理函数的调试,程序一旦停下了也就失去了所有中断的后续响应;比如两个设备通信,一方采用常规断点的方式调试,肯定会打断正常的通信过程,而这可不是我们想要的,我们只想知道在收到或发送数据后得到环境快照,而并不想让程序停下来。以上这些问题可以采用打印方式解决,但是打印调试也有很多弊端:

以串口为例:

1、你必须添加必要的打印和串口驱动代码,如果你使用 printf 函数,你还得重定向(如果对空间要求高的话,你得知道使用 printf 差不多要占用 1K 大小代码空间)。

2、如果打印效率比较低,常规波特率 9600 和 115200 打印一个字符串耗时可能比较久,那么对于中断频率较高的函数就可能就不适用了。如果你使用 printf 函数,你还得考虑函数是否可重入问题。

3、在代码中引入调试代码有风险,本来程序运行没有问题的,一旦引入调试代码之后可能就出现了问题,这种情况对于拥有丰富开发经验的人来说应该见怪不怪了。原因就在于打印输出时间太久,打乱了程序运行的节奏(而这也是我推荐使用 ITM 调试的一个原因,因为它的输出效率比串口要高得多),或者打印函数本身有问题,也会导致程序运行出现问题。

4、调试完毕之后,你必须把对应的调试代码删除(不管是删除代码还是使用宏,都要进行这一步),不然会影响运行效率。而人是健忘的(也不能说健忘,可能只是因为专注于 BUG 本身,容易忘记其它细枝末节,而解决 bug 之后的欣喜更可能忘记后续处理工作了)这个时候你可以尝试#warnning。但是这一步还是必不可少。而以上问题的解决方案就是 KEIL 的断点调试窗口!

打开断点调试窗口:

首先打开数据观察点的窗口:
,得先进入仿真 --> 快捷键是 Ctrl + B。
可以看到如下窗口:
在这里插入图片描述

当然你也可以watch 变量--> 右击 选set access breakpoint at....

常规用法

1、代码位置运行次数,可以直接设置断点或watch里的变量,这个设置成功的关键是要先把断点打在有效的位置上,就是可以循环的跑起来的位置上才可以再直接设置变量
有些时候我们想知道某些代码的运行次数,比如进入中断处理函数的次数,寻常的断点设置方式必然会让程序停止在中断程序中,但有些时候我们并不希望它停下来。这个时候,你只需要打开该窗口,找到已有的对应断点位置,双击之后就可以看到类似下面的窗口:
在这里插入图片描述

此时,你将 Count 的值设置的尽可能大一些,那么就可以让程序运行多次之后才停止。

比如我们设置 Count 的值为 100 次,那么必须在==该代码位置运行 100 次才会让程序暂停==。当你设置完后点击【Define】后,就会询问你是否需要重新定义,你选择“是”即可。
在这里插入图片描述
这样你的断点变成了这样:
在这里插入图片描述
后面的 count=100 表示剩余运行次数为 100,运行 100 次后将停止程序。前面的 00 代表断点号,E 代表这是一个执行断点,0x080016B0 代表代码地址,后面的是源码位置。

2、数据访问,也就是变量被调用时停止

有些时候我们需要知道一些变量会在哪里被访问,那么你可以设置该变量的访问条件。比如想知道 emOspery 变量会在哪里被读取?那么你只需设置如下:

在这里插入图片描述

定义之后就是这样:
在这里插入图片描述
因为 Count 值设置为 1,所以每一次读取 emOspery 的操作都将使程序停止。比如这段代码:还有后面的打印函数也使用 emOsprey 变量,所以也会导致程序运行停止。
在这里插入图片描述

2_1、数据访问,变量改变时停止,这个在有效断点设置后,可以将有效断点失效,这样就可以直接根据变量判断条件这样来实现调试。

而当你设置为写(Write)访问时,你会发现从复位程序开始运行后,程序会停止在某个地方,这是为什么?当你知道全局变量会在进入 main 函数之前被初始化时,你也就明白为什么了。

在这里我们选择使用 Objects 访问,即按整个变量对象进行访问,上面的 emOsprey 变量实际上是 uint16_t,所以 len 为 2,即字节大小。也就说,如果你设置为 Objects 访问,那么它会根据实际的情况设置访问范围。

为了更好的说明这一点,我构造一个结构体。
在这里插入图片描述
这个结构体大小可以看出是 6 个字节。
然后设置访问该结构体的条件:
在这里插入图片描述
如果我们按 Objects 访问的话,那么下面的每一条语句都会导致程序运行的停止。
在这里插入图片描述

这是因为这些数据都在 Osprey 结构体的范围内(从这里也可以了解到,只要在 len 的范围内的访问都会导致程序停止运行,所以你可以试试将 Size 设置得更大)。

而如果设置为 Byte 访问的话,那么就只有第一条语句才会导致程序停止运行:
在这里插入图片描述
实际上如果你希望只在某个结构体成员变量被访问时才停止,那么直接这么设置就可以:
在这里插入图片描述
你会发现设置是如此之简单。

实际上还有一种更为通用的访问方式,即按地址访问。
上面可以看出 ==Ospery.Ospery1 成员变量的地址为 0x2000 0016,***这样就可以知道变量的地址***==(由此我们知道也可以通过这个来看出一个结构体变量的地址是多少)。所以我们可以这样设置:
在这里插入图片描述
而代码位置的断点设置亦是如此。
断点太多,怎么知道程序因何停止?看你的命令窗口就知道了:
在这里插入图片描述

3、数据匹配,也变是变量加判断条件停止

有些时候,我们并不关注地址访问情况,而对变量的数据内容感兴趣。比如说想让变量 emOspery 等于 1 时停下来,怎么设置?

在这里插入图片描述

只要简单的设置 emOspery == 1 即可(注意必须设置访问条件,并且 Size 设置正确)。

事实上你也可以设置两个变量相等作为条件:

在这里插入图片描述

设置为不等也是可以的:

在这里插入图片描述
当然还有其它支持的运算就靠你们自己去发现了(可支持运算:&,&&,<,<=,>,>= ,==,!=)。

注意:以上内容可以组合使用,比如读、写条件,计数器计数等可以同时设置。满足条件时就会让程序运行停止。

4. 高级用法 ,在Command里面打印,printf

以上为比较常规的调试功能,这个技能的使用灵活性更大,而且对于解决疑难杂症更是不二之选。

首先设置一个你需要的断点:每次程序经过这个断点时都会打印,程序不会停止

在这里插入图片描述
打开断点窗口,并双击你之前设置的断点:

在这里插入图片描述
设置 Command 为【printf(“USRAT_Init()\n”)】(注意\n,否则可能不能输出,这个应该是 KEIL 的一个 bug)。最后【Define】:

在这里插入图片描述
清空你之前的命令(如果你不嫌乱的话,也可以不清空):

在这里插入图片描述

那么你的程序每次运行到这个代码位置都会在 Command 窗口输出一条信息:

当然也可以将前面3.数据匹配部分加进来进行打印,==也就是所谓的组合条件打印==

在这里插入图片描述

断点设置相关问题:根本的原因就是没有设置好一个可以循环执行的断点位置,其他都还好说。

2. 关于had default

1. M4核寄存器

R0~R12为通用目的寄存器,
R13为栈指针,物理上存在两个栈指针:主栈指针(MSP)为默认的栈指针,在复位后和处理器处于处理模式时,会被选择使用;另一个栈指针为进程栈指针(PSP),只能用于线程模式(有RTOS时)。
R14为链接寄存器(LR),用于函数或子程序调用时返回地址的保存。在函数或子程序结束时,程序控制可以通过将LR的数值加载程序计数器(PC)中返回调用程序处并继续执行,在异常处理期间,LR会自动更新为特殊的EXC_RETURN(异常返回)数值。
R15为程序计数器(PC)

2. 查找步骤?

进入异常前,程序会类似于中断保护,会将以上寄存器入栈,具体入MSP还是PSP取决于异常发生时使用的栈?进入异常后链接寄存器 LR 中存放异常返回值 EXC_RETURN, 如果其 bit 2=0 那么用的就是 Main Stack,如果 bit 2=1,那么用的就是 Process Stack。
#基本原理就是通过仿真 -> register 中 LR R14值来判断使用的是哪个栈,如r14为0xfffd,使用的就是PSP,再根据psp值在内存memory1窗口中找到相应栈地址,一般的压栈顺序为 R0-R3,R12, LR, PC,PSR ,所以LR为第6字节,PC为第7个字节 —> 所以只要定位于程序计数器pc值,就可以定位到程序出错的位置,在Disassembly反汇编窗口单击右键—>选择Show Didassembly at Address—>输入地址pc,keil即可自动对应.c文件中出错位置。
#另一种方法就是查看map文件,根据前面寄存器 register 中 PSP值,找工程map中附近值对应的任务名

在这里插入图片描述

  • 107
    点赞
  • 451
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值