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、数据访问,也就是变量被调用时停止,前提是这个变量得能跑起来,这点很重要,有些只能在明显的while(1)里设置,其他地方设置就会报错,其次变量的设置是可以不用打断点的

在这里插入图片描述

有些时候我们需要知道一些变量会在哪里被访问,那么你可以设置该变量的访问条件。比如想知道 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 设置正确)。

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

在这里插入图片描述

设置为不等也是可以的:

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

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值