Keil调试技巧
一、调试前的准备
使用ST-Link将PC和单片机连接
以STM32入门教程中的“读写内部FLASH”实验为例,使用Keil打开该工程
按照下图所示的步骤进行操作,如果使用ST-Link仿真器,则在第三步选择ST-Link Debugger
按照下图所示的步骤进行操作,输出选项卡需要勾选调试信息
按照下图所示的步骤进行操作,代码生成的优化选项中,优化等级需要选为0,否则Keil在编译程序的过程中可能会过度优化,导致编译得到的二进制机器码和C语言代码不是等价的,在调试过程中会引起代码执行顺序错乱
完成以上步骤后,编译程序,然后将其下载到单片机中
二、Keil调试界面
1、调试界面的进入
完成上一节的操作后,点击下图所示的Debug图标,即可进入Keil调试界面
2、调试界面介绍
(1)Register栏显示的是单片机核心寄存器的状态。
(2)Disassembly栏显示的是所编译程序对应的汇编代码。
(3)Command是命令行窗口,部分特殊操作需要通过命令行实现。
(4)右下角窗口用于显示变量及内存的存储值,有多个选项卡供切换。
三、程序执行控制
1、程序执行控制键
(1)Reset:控制单片机回到上电复位的状态,并在Reser_Handler处停止运行。
(2)Run:控制单片机从当前停止点对应的C代码开始运行程序,直到触发停止运行的条件,或手动停止运行。
(3)Stop:控制单片机停止运行程序,代码浏览页面会跳转到停止点。
(4)Step:控制单片机从当前停止点对应的C代码开始运行程序,并停止在下一条C代码,也即只运行一条C代码,如果遇到函数调用,会转入函数中,停在函数开头。
(5)Step Over:控制单片机从当前停止点对应的C代码开始运行程序,并停止在下一条C代码,也即只运行一条C代码,如果遇到函数调用,会一步跳过,不会转入函数(即使在执行函数的时候触发了断点)。
(6)Step Out:控制单片机从当前停止点对应的C代码开始运行程序,直到从当前运行的函数中转出,或触发停止运行的条件,单片机停止运行程序。
(7)Run to cursor line:控制单片机从当前停止点对应的C代码开始运行程序,直到运行到蓝色光标所指的C代码,或触发停止运行的条件,单片机停止运行程序。
①黄色光标所指的C代码,是单片机当前运行的C代码。
②蓝色光标所指的C代码,是调试员在代码浏览界面选中的C代码。
(8)Show Next Statement:将代码浏览界面切换至当前单片机停止处的C代码,也即黄色光标所指的C代码(只能在内核停止时使用)。
2、程序断点
(1)在代码浏览区的左侧有一些灰色的区域,鼠标左键点击,即可在区域对应的代码打上断点,当单片机运行到这些代码的时候,会触发停止运行的条件。
(2)如果需要取消断点,鼠标左键点击它对应的红色圆圈,即可取消断点。
(3)按下CTRL+B,可查看当前在窗口中设置的所有断点。
①点击对应的断点,代码浏览界面会切换至所点击断点对应的代码处。
②Count选项可配置次数,当单片机运行断点代码的次数达到Count指定次数后,才会触发停止条件,这在调试带循环结构的代码块时比较实用。
3、访问断点
(1)访问断点,它是针对变量而言的,如果一个变量被设置了访问断点,那么当程序对该变量进行访问时,会触发停止条件。
(2)设置全局变量/静态变量访问断点的步骤:
①在变量查看窗口中右键选中需要设置断点的变量,选择“Set Access Breakpoint at ‘<变量名>’”。
②在弹出的断点配置窗口中,表达式已经自动生成,如果希望在写访问时触发停止条件则勾选“Write”,如果希望在读访问时触发停止条件则勾选“Read”(选项可以是多选的),然后点击“Define”即可。
(3)设置局部变量访问断点的步骤:
①运行程序,使其停止在局部变量所在函数的入口。
②在命令行窗口输入“&<局部变量名>”,获取局部变量的地址。(有时候编译器会将局部变量优化,导致&的操作数无效,也即不存在这个局部变量,为了避免这种情况发生,在定义局部变量时可以使用volatile关键字,强制编译器为其分配内存地址)
③在弹出的断点配置窗口中,表达式输入“<变量地址>”,如果希望在写访问时触发停止条件则勾选“Write”,如果希望在读访问时触发停止条件则勾选“Read”(选项可以是多选的),然后点击“Define”即可。
④函数返回后,(非静态)局部变量会被销毁,对应内存空间释放,相应地,访问断点也要删除(至少要禁用)。
4、条件断点
(1)条件断点,它也是针对变量而言的,如果一个变量被设置了条件断点,那么当这个变量等于某个值时,会触发停止条件。
(2)设置全局变量/静态变量条件断点的步骤:
①在变量查看窗口中右键选中需要设置断点的变量,选择“Set Access Breakpoint at ‘<变量名>’”。
②在弹出的断点配置窗口中,表达式已经自动生成,在表达式后面加上“== <停止值>”,然后勾选“Write”,点击“Define”即可,这样,当变量被写成停止值时,内核就会停止运行。
(3)设置局部变量条件断点的步骤:
①运行程序,使其停止在局部变量所在函数的入口。
②在命令行窗口输入“&<局部变量名>”,获取局部变量的地址。(有时候编译器会将局部变量优化,导致&的操作数无效,也即不存在这个局部变量,为了避免这种情况发生,在定义局部变量时可以使用volatile关键字,强制编译器为其分配内存地址)
③在弹出的断点配置窗口中,表达式输入“*(<局部变量类型> *)<变量地址> == <停止值>”(相当于对局部变量地址解引用,访问局部变量),然后勾选“Write”,点击“Define”即可,这样,当变量被写成停止值时,内核就会停止运行。
④函数返回后,(非静态)局部变量会被销毁,对应内存空间释放,相应地,条件断点也要删除(至少要禁用)。
四、变量和内存的查看
1、局部变量的查看
(1)变量和内存的查看窗口中,Call Stack + Locals选项卡可以查看整个程序的调用栈,可以查看对应函数中的局部变量,如果局部变量是结构体变量,还能展开查看各个成员的值。
(2)双击局部变量(或局部结构体变量成员)的值,可以对其进行修改,按下回车后,修改将同步至单片机。
2、全局变量的查看
(1)右键选择想要查看的全局变量,可以将其添加进对应的窗口中(如果窗口不存在则会自动新建),如果全局变量是结构体变量,还能展开查看各个成员的值。
(2)双击全局变量(或全局结构体变量成员)的值,可以对其进行修改,按下回车后,修改将同步至单片机。
3、内存的查看
变量和内存的查看窗口中,Memory选项卡可以查看某一块内存的具体情况,在输入栏输入想要查看内存的起始地址,然后按下回车即可
五、逻辑分析仪
1、硬件配置
(1)使用Keil的逻辑分析仪功能,需要仿真调试器支持TDO/SWO引脚接口,部分仿真器可能只有基础的调试引脚,并不具备完整的20Pin。
(2)对于STM32F10xxx来说,其TDO/SWO引脚的引脚号为PB3,其它型号的芯片具体可参考数据手册。
2、Debug配置
本节使用J-Link连接单片机与PC,需要在Keil中按照下图所示进行配置
3、Debug的逻辑分析仪
(1)点击Debug图标,进入Keil调试界面,然后点击逻辑分析仪图标“Logic Analyzer”,即可打开逻辑分析仪。
(2)逻辑分析仪只可观测全局变量和静态变量,在代码浏览界面中右键选择想要查看的变量,可以将其添加进逻辑分析仪窗口中。
(3)点击“Setup..”,可以设置示波器的最大值、最小值。
