Keil5调试分为在线调试和离线模拟两种调试方式:在线调试允许开发者在硬件设备上实时运行程序,并同步监控程序的执行情况;离线模拟就是在没有实际硬件设备的情况下,通过软件来模拟目标硬件的运行环境,让程序在这个虚拟的环境中运行,从而实现对程序的调试 。
一、在线调试
在线调试是利用设备内置的单片机内核调试模块,通过JTAG或SWD接口与调试器通信。当程序执行到断点时,调试器暂停运行,允许用户查看寄存器状态、变量值等,恢复后继续执行。
常用的调试器有ST-LINK、J-LINK、U-LINK,这些调试器都是硬件设备,主要用于在嵌入式开发中对微控制器(如STM32、ARM Cortex系列等)进行程序下载、调试和性能分析。
这些调试设备与单片机的连接方式主要通过JTAG或SWD调试接口来实现。调试器通过USB连接电脑,另一端通过排线(如20pin或10pin接口)连接开发板的调试接口,J-LINK需要在电脑上安装SEGGER驱动,ST-LINK需要安装ST官方驱动。
JTAG 接口使用 4 条线:TCK(测试时钟)、TMS(测试模式选择)、TDI(测试数据输入)和 TDO(测试数据输出),通过这些信号线,调试器可以与目标板上的芯片进行通信,实现对芯片内部寄存器、内存等资源的访问和控制 。
SWD 接口只需要 2 条线:SWCLK(串行时钟)和 SWDIO(串行数据输入 / 输出) ,在保证通信功能的前提下,减少了硬件连接的复杂度,提高了通信效率 。当程序在目标板上运行时,调试器可以向目标板发送各种调试命令,如单步执行、设置断点、读取和修改寄存器值等 ,目标板上的调试代理会接收这些命令,并根据命令对程序的执行进行相应的控制,然后将程序的执行状态和相关信息返回给调试器,开发者就可以在 Keil5 的调试界面中查看这些信息,从而分析程序的运行情况,找出潜在的问题。
要进行在线调试,必备的硬件设备就是调试器,常见的调试器有 ST – Link、J – Link 和 ULink 等 。ST – Link 是意法半导体(STMicroelectronics)推出的一款专门用于调试 STM32 系列微控制器的调试器,它价格相对较低,使用也较为广泛 ,很多 STM32 开发板都会自带 ST – Link 调试器,方便开发者进行调试 。
J – Link 是 SEGGER 公司开发的一款调试器,它支持多种芯片架构,具有高速、稳定的特点 ,在一些对调试性能要求较高的项目中经常被使用 。ULink 则是 Keil 公司自家推出的调试器,与 Keil5 开发环境的兼容性非常好 。
以 ST – Link 为例,连接方法如下:
- 使用一根 Micro – USB 线将 ST – Link 的 USB 接口连接到电脑的 USB 接口上 ,为 ST – Link 供电并实现与电脑的通信 ;
- 将 ST – Link 的 SWD 接口与目标板上的 SWD 接口对应连接 ,SWD 接口一般有 4 个引脚,分别是 VCC(电源)、GND(地)、SWCLK(串行时钟)和 SWDIO(串行数据输入 / 输出) ,将 ST – Link 上的这 4 个引脚与目标板上对应的引脚一一连接 ,注意连接时要确保引脚对应正确,避免接反导致硬件损坏 ;
- 连接完成后,给目标板通电,此时 ST – Link 的指示灯应该会亮起,表示连接正常 。
在 Keil5 中进行在线调试时,需按以下步骤配置调试参数:
在 Options for Target → Debug 选项卡中,选择实际使用的调试器(如 J-Link、ST-Link 或 DAP-Link),如下图:

其它参数保持默认即可。
2、关闭编译器优化
在 C/C++ 选项卡中,将优化等级设为 Level 0 (-O0),避免断点因优化失效。
二、离线模拟
离线模拟就是在没有实际硬件设备的情况下,通过软件来模拟目标硬件的运行环境,让程序在虚拟的环境中运行,从而实现对程序的调试 。
在 Keil5 中进行离线模拟调试(软件仿真)时,需按以下步骤配置调试参数:
1、选择仿真模式
在工程选项中(Options for Target → Debug选项卡),将调试器类型设置为 Use Simulator。如下图:

在 “Dialog DLL” 和 “Parameter” 输入框中,需要根据所使用的芯片型号设置相应的参数 ,这些参数一般由Keil5自动填入。
2、关闭编译器优化
在 C/C++ 选项卡中,将优化等级设为 Level 0 (-O0),避免断点因优化失效。
三、调试方法
假设对下述代码进行调试:
#include<reg52.h>
sbit led1 = P1^0;
void delay_ms(unsigned int ms) {
unsigned int i, j;
for(i=0; i<ms; i++)
for(j=0; j<1; j++);
}
void main()
{
while(1) {
led1=0;
delay_ms(1);
led1=1;
delay_ms(1);
}
}
步骤1:设置断点
断点是设置在代码行的一个标记,可以在任意代码行设置断点。当程序执行到标有断点的代码行时,程序会暂停执行,开发者可以通过查看内存、变量、调用堆栈等信息来定位和修复错误。
- 在代码编辑窗口,将光标定位到要设置断点的代码行上,如下图所示:

- 展开“Debug”菜单,选择“Insert/Remove Breakpoint”命令,或者用鼠标双击语句左侧的灰色区域设置断点,如下图所示:

断点所在的行会显示一个红色圆圈,表示该行代码设置了一个断点。开发者可以在不同的行设置多个断点,当程序执行到断定时会暂停执行,开发者可以查看到当前单片机各寄存器的状态和值、变量的值、内容区域的数据读写情况等。
步骤2:执行调式
断点设置完成后,执行程序进行调试。
- 执行程序:展开“Debug”菜单,选择“Start/Stop Debug Session”命令,或按下Ctrl+F5键,或单击工具条上的启动调试图标,都可以启动程序的仿真调试。启动调试后的界面如下图所示:
寄存器窗口:查看单片机各寄存器的状态和值。
汇编指令窗口:查看C源代码对应的汇编指令及其内存地址。
代码窗口:查看C源代码文件内容,黄色箭头指示当前执行位置,蓝色箭头(蓝色三角形)表示当前光标所在的行或当前选中的代码行。
观察窗口:用于实时监控变量值的变化。
- Watch窗口:Keil5提供了Watch1和Watch2两个独立观察窗口,展开“View”菜单,选择“Watch Windows”命令,出现下拉菜单,在下拉菜单中选择“Watch1”或“Watch2”,Keil会将“Watch1”或“Watch2”添加到观察窗口,下图添加了“Watch1”或“Watch2”到观察窗口:

上图Watch1窗口可以实时监控单片机I/O口P1寄存器的值和程序变量LED1的值。
在Watch窗口添加观察变量的方法位:
方式1:双击观察窗口的<Enter expression>区域直接输入变量名(寄存器名称、程序变量名称);
方式2:右键点击代码中的变量→选择Add ‘变量名’ to Watch;
- Call Stack+Locals窗口:主要用于分析函数调用关系和局部变量状态,具体观察内容如下:
- 自动列出当前执行函数内的所有局部变量及其实时值;
- 显示当前函数及其调用链,底部为最早调用的函数(如main()),顶部为当前调用的函数。

- 内存窗口:Keil5提供了Memory X四个独立的内存观察窗口,展开“View”菜单,选择“Memory Windows”命令,出现下拉菜单,在下拉菜单中选择“Memory X”将“Memory X”添加到观察窗口,下图添加了“Memory 1”到观察窗口:

内存窗口可以查看不同存储区域的数据,在Address输入域输入存储区的起始地址。
⑤ 查看单片机I/O口:51单片机一般有4组8位I/O口,分别对应单片机的P0~P3 寄存器,P1~P4 寄存器是8位寄存器。在程序调试过程中,可以实时查看P0~P3 寄存器的状态和值,观察程序对P0~P3 寄存器的影响。展开“peripherals”菜单,选择“I/O-Ports”菜单项,再弹出的子菜单中选择“Port X(0~3)”项。

Keil弹出P1口状态对话框,如下图所示。
从图中可以看到,当前P1口0~7位逻辑状态都为1,继续执行程序,再次查看P1口状态。

P1口第0位的逻辑状态已经发生了变化,其逻辑状态为0。
步骤3:单步执行
单步执行是每次仅执行一行代码,并在执行后暂停程序,开发者可观察当前寄存器、变量值、内存状态等中间结果。用于排查程序存在的问题或验证程序执行结果。
单步执行前,将光标定位到代码编辑窗口,然后按下F10键或选择“Debug”菜单下的“Step Over”命令,都可以让Keil5执行当前断点所在行代码,并将黄色箭头指向要执行的下一行代码,如下图所示:

在单步执行过程中,若当前执行的语句是函数调用,该如何操作?
在这种情况下,有两种方式:一种方式是跳过函数,不进入函数内部;一种方式是进入函数内部,逐行执行函数内部代码。
第一种方式:按下F10键或选择“Debug”菜单下的“Step Over”命令,Keil5将执行函数,但不进入函数内部;
第二种方式:按下F11键或选择“Debug”菜单下的“Step”命令,Keil5将进入函数内部,开发者可逐行执行函数内部代码,也可以按下Ctrl+F11键或者选择“Debug”菜单下的“Step Out”命令跳出函数。
在单步执行过程中,若希望程序直接执行到某行代码,可以将光标定位到某行代码,然后按下Ctrl+F10键或选择“Debug”菜单下的“Run to Cursor Line”命令。Keil5将程序直接执行到该行代码。
四、常见调试问题及解决办法
1、无法下载程序
在实际开发中,无法下载程序是一个较为常见的问题。导致这个问题的原因有很多,需要逐一排查。
硬件连接问题:确保调试器(如 ST – Link、J – Link 等)与目标板之间的连接正常,查看数据线是否插好,是否有松动、损坏的迹象 。如使用 ST – Link 调试 STM32 开发板时,如果 SWD 接口的数据线接触不良,就可能导致下载失败 。可以尝试重新插拔数据线,或者更换一根数据线,看是否能解决问题 。同时,也要检查目标板的电源是否正常供应,电源指示灯是否亮起 。如果电源不稳定或者没有供电,目标板无法正常工作,自然也无法下载程序 。
驱动程序问题:如果驱动程序未安装或者安装不正确,电脑将无法识别调试器,从而导致下载失败 。以 ST – Link 为例,可以通过设备管理器来查看 ST – Link 设备是否正常识别 。如果在设备管理器中找不到 ST – Link 设备,或者设备前面有黄色感叹号等异常标志,说明驱动程序存在问题 。此时,需要到 ST 官网下载最新的 ST – Link 驱动程序,然后卸载原来的驱动,重新安装新的驱动 。安装完成后,再次查看设备管理器,确保 ST – Link 设备正常识别 。
下载设置错误:在 Keil5 中,下载设置也可能导致无法下载程序 。点击 “Project” 菜单下的 “Options for Target ‘Target 1’”,在弹出的窗口中,切换到 “Debug” 标签页,确保选择了正确的调试器 。比如,如果使用的是 ST – Link 调试器,就应该选择 “ST – Link Debugger” 。然后点击 “Settings” 按钮,在 “Debug” 选项卡中,检查 “Port” 是否选择了正确的接口(如 SWD 或 JTAG) ,并且时钟频率等参数设置是否正确 。在 “Utilities” 标签页中,确保选择了正确的下载算法,不同的芯片型号需要对应的下载算法 。如果下载算法选择错误,也会导致下载失败 。例如,对于 STM32F407 芯片,就需要选择对应的 STM32F407 的 Flash 下载算法 。
2、断点无效
在调试过程中,有时会遇到断点无效的情况,程序不会在断点处停止,这给调试工作带来了很大的不便,需要逐一排查。
编译优化问题:编译优化可能会导致断点无效 。当编译时设置的优化等级过高,编译器可能会对代码进行优化,改变代码的执行顺序或删除一些不必要的代码,从而使断点的位置发生变化或者断点被忽略 。在 Keil5 中,点击 “Project” 菜单下的 “Options for Target ‘Target 1’”,在弹出的窗口中,切换到 “C/C++” 标签页,将 “Optimization” 选项设置为 “Default (-O1)” 或更低的优化等级 ,然后重新编译程序,再进行调试,看断点是否有效 。
代码位置问题:断点设置的位置也可能影响其有效性 。如果断点设置在一些不会被执行的代码行上,比如在条件判断语句中,条件永远为假的分支代码上,那么断点自然不会生效 。另外,在一些内联函数、宏定义展开的代码中设置断点,也可能会出现无效的情况 。需要检查断点设置的位置是否合理,确保断点设置在会被执行的代码行上 。例如,在下面的代码中:
int main(void)
{
int a = 5;
if (a < 3)
{
// 这里设置断点无效,因为条件为假,这部分代码不会执行
a = 10;
}
while (1)
{
// 循环体
}
}
调试器设置问题:调试器的设置也可能导致断点无效 。在 Keil5 的 “Debug” 标签页中,检查调试器的相关设置是否正确 。比如,确保 “Use” 选项选择了正确的调试器,并且 “Run to main ()” 等选项设置符合需求 。另外,一些调试器可能需要特定的配置才能支持断点功能 ,需要查阅调试器的文档,进行相应的设置 。例如,对于某些 J – Link 调试器,可能需要在其设置中启用断点支持功能 。