电子说
搞软件开发,如果谁能拍胸脯说自己开发的代码不存在bug
,一定会被现实打脸的。系统复杂了,代码多了,一定会出问题。就算代码架构设计得多么先进,程序员编程水平多么高,团队协作多么紧密,代码审核多么严谨,运行出问题的几率一定存在,是不过是概率大小,出问题早晚,问题的严重与否而已。
既然代码会出问题,那肯定要解决,最有效的办法就是调试(Debug
)了。不管是嵌入式开发,还是应用开发,调试都是程序员必备技能,只不过嵌入式开发的调试又有所不同,除了需要OCD
、GDB
之类的调试软件之外,还需要J-Link
、ST-Link
等调试器,以及片上JTAG
模块的支持。
我在读大学的时候学的是51
单片机,当时也只有实验室有实验箱。所谓的调试基本就是根据运行现象去分析,比如某种亮灯状态表示某种情况,或者是串口打印信息,屏幕显示信息等,以此来Debug
。
后来跟课题组做项目,陆续用到AVR
、PIC
单片机,当时基本没有第三方的开发板,只能找官方资源,官方的下载器。官方的调试器极其昂贵,想调试的话也只能跟调试51一样,基本都能解决问题,就是要麻烦一点。
现在的ARM调试器都是白菜价,各个IDE
也都具备基本的调试功能,Debug
更方便了。Keil
下的调试比较直观,在工程选项里配置好调试参数后,点个按钮就进入调试模式,这里就不多介绍。今天来讲一下CubeIDE
下怎么去调试代码。
跟Keil
不同,基于Eclipse
的CubeIDE
下的工程默认有Debug
和Release
两个编译配置,如下图所示。可以在工程属性下设置不同的编译参数,分别作为调试和发行时使用,当然也可以根据需要增加新的编译配置。Keil
下也可以实现类似的功能,不过需要我们自己去配置,这个有很多文档可以参考。
保留不同编译配置的功能在写代码时非常有用,结合条件编译,可以提高调试效率,或者是适应不同的硬件平台,不需要再搞一个新的工程。例如在Debug
编译配置下,默认会定义一个DEBUG
的符号,在Release
编译配置下,则没有定义这个符号。见下图。
我们在编写代码的时候,就可以根据编译配置的不同,结合条件编译,选择编译不同的代码。例如,在正常工作的时候,某个传感器上电后需要经过10分钟才能正常工作,而在调试的时候,完全没必要去等这10分钟。我们可以用下面的伪代码实现这个功能。
#ifndef DEBUG
delay_second(10*60); //延时10分钟
#endif
使用Debug
编译选项编译完成后,会在工程目录->Debug
下生成elf
可执行文件,elf
文件包含调试信息,这是我们调试的必要文件。Eclipse
调试前需要配置调试参数,配置方式见下图。
需要进行调试的话,点击工具栏小虫子图标就进入调试模式。
在调试模式下可以设置断点,或单步运行,也可以查看寄存器的值,变量值等。另外CubeIDE
还提供了很多有用的功能,比如说可以调出“故障分析器”,代码出现异常时可以自动分析错误类型,不需要我们费力的去查看相关寄存器的值来确定错误类型;还可以显示反汇编后的汇编代码,与C代码同步显示。需要注意的是,调试模式下,编译代码应选择不优化,这样设置的断点才都会有效。
调试时所需要查看的信息都可以在下图的菜单里调出来。
进入调试模式后,就可以根据实际情况设置断点,查看寄存器或变量值,也可以根据需要单步运行。大家可以在实践中熟悉调试方法与技巧。
另外,在调试模式下,无论是打断点还是单步运行,都没有办法实时跟踪寄存器或变量值,看到的只是断点处的值,如果想看到实时变化的寄存器或变量值,甚至是某个函数被调用的次数,或者运行占用的CPU
时间等,可以通过ARM
提供的SWV(Serial Wire Viewer)
实时跟踪技术来实现,下次我们再来讲讲这个SWV
。
全部0条评论
快来发表一下你的评论吧 !