在当今的嵌入式系统开发领域,高效的调试工具对于工程师来说至关重要。 它们可以显着减少开发周期中的错误跟踪时间并加快产品上市时间。 作为业界领先的嵌入式开发工具之一,MDK内置的调试功能深受开发者的好评。 这些功能不仅提供对代码执行的深入洞察,还允许开发人员在实时环境中监视和修改系统行为。
通过本文,我们将探讨MDK的调试功能如何成为嵌入式开发者的得力助手,如何帮助我们构建更加稳定、高效的嵌入式应用。
1.MDK模拟调试配置
在MDK模拟之前,我们需要配置其环境。
Load at是启动调试时是否加载应用程序。 如果去掉该选项,程序将不会自动下载到单片机并直接调试。 如果勾选该选项,则每次进入调试前都会下载应用程序,然后再进入调试。
运行到main()可以使程序执行到main()函数。 进入调试模式后,程序自动运行到main函数。
如果ST-link未插好或者设备异常,会提示No ST-link。
2、各调试按钮的功能
接下来我们编译代码。 单击此按钮就像放大镜一样,开始模拟(此按钮也可以退出模拟)。
进入模拟后的界面如下图。
界面左侧显示寄存器地址和程序运行时间。 上半部分是汇编语言窗口,需要一定的汇编知识才能理解。 界面的左下角是命令窗口。 该窗口会显示一些打印信息,您还可以在此窗口中输入一些命令。 右下角的窗口是内存中函数和变量的地址信息。
左上角有一排关于调试的小按钮:
它们的功能从左到右分别是:复位、全速运行、停止、进入函数、执行该函数、跳出函数、执行到光标处、显示下一个要运行的代码
这里我以流水灯为例,详细讲解一下各个按钮的使用方法。 使用的微控制器模型是最小的系统板。 连接ST-link并上电,接线图如下:
意法半导体
时钟信号
时钟信号
SWDIO
SWDIO
接地
接地
3.3V
3V3
最小系统板上有一个小型内置灯。 该 LED 灯连接到 PC13 引脚。
首先,我们需要为小灯编写一个初始化程序。 这里不需要封装,直接写在main.c中即可。
#define LED_CLK() __HAL_RCC_GPIOC_CLK_ENABLE()
#define LED_GPIO GPIOC
#define LED_PIN GPIO_PIN_13
void led_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
LED_CLK();
gpio_initstruct.Pin = LED_PIN;
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_initstruct.Pull = GPIO_PULLUP;
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED_GPIO, &gpio_initstruct);
}
主要功能代码如下:
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
led_init();
while(1)
{
HAL_GPIO_WritePin(LED_GPIO,LED_PIN,GPIO_PIN_SET);
delay_ms(500);
HAL_GPIO_WritePin(LED_GPIO,LED_PIN,GPIO_PIN_RESET);
delay_ms(500);
}
}
点击放大镜进入仿真界面,然后点击左上角的开始按钮(或者使用快捷键F5)开始执行代码。
您可以看到最小系统板上的小 PC13 指示灯不断闪烁。 这时我们在第19行打断点,点击全速运行按钮:
可以看到当前程序运行到第19行,然后暂停。 最小系统板上的小 PC13 指示灯将保持亮起。
(需要注意的是,当调试在中断点停止时,内核会停止,但外设会继续运行)
然后我们在第21行打断点,然后点击全速运行按钮。
你会发现代码执行到了第21行就停止了。此时,最小系统板上的PC13小灯就会熄灭。
我们点击右上角的重置按钮,然后选择(); 行代码,单击“执行到光标”按钮(或快捷键 Ctrl+F10)以执行该行代码。
(需要注意的是,必须退出调试模式,重新进入调试模式,否则代码会一直死循环执行,导致代码无法执行到你要执行的行)
此时,我们点击进入功能按钮(或快捷键F11)即可进入LED初始化功能。
我们可以看到当前程序执行到了LED初始化函数中。 此时点击“执行此功能按钮”(或快捷键F10),如下图。
点击上面的按钮,程序就会执行一行代码。 而且,如果当前行是一个函数,则不会进入该函数的内部代码,直接执行函数代码,进入下一行。
如果不想查看()函数中的代码,可以单击“跳出函数按钮”(或快捷键Ctrl+F11)。 点击该按钮可以直接跳出当前代码程序,准备执行下一行。
(如果跳出函数,则默认执行当前程序代码,然后跳转到下一行)
3.检查程序段/函数的执行时间
在代码中,我们经常使用延迟函数。 那么,我们如何判断延迟函数是否真的延迟了我们设定的时间(比如500ms)呢?
我们可以通过代码调试功能来判断延迟时间的准确性。
首先打开魔棒,打开Debug中的选项。
再次单击“Trace”选项卡以查找时钟频率。
默认时钟频率为8MHz,这里我们将其更改为72MHz。
我们选择第20行,然后使用“执行到光标按钮”(快捷键是Ctrl+F10)运行到第20行。如下:
左下角的Sec表示程序运行了多长时间,单位为秒(s)。 我们使用“执行此函数”(快捷键为F10)来执行延时函数,看看延时函数是否准确。 结果如下:
用这个结果减去初始时间,我们可以看到延迟约为0.5s,即500ms。 可以认为延时函数的时间是非常准确的。
4.工具栏常用窗口按钮介绍
调试按钮左侧有一排窗口按钮,用于打开各种调试窗口(也可以通过菜单栏上的View打开)。
Watch窗口还可以设置变量被读或写后自动停止运行,这对代码调试很有帮助。 您可以定义一个函数,在窗口中输入该函数的名称,然后将一个数字传递给该函数。 在此窗口中您可以看到该函数的寄存器的首地址。 传完号码后可以看到号码的类型是What。
点击该按钮,弹出界面如下:
让我们举一个例子来演示这个过程。 例如定义一个全局变量int temp; 在程序中并在 while 循环中执行 temp++。 右键单击 temp 并选择将“temp”添加到...以添加到 Wacth 1。
在左下角的Watch 1窗口中,可以看到temp的首地址和定义类型。 如下所示:
这里我们使用“执行此功能按钮”(快捷键是F10)。 如果我们执行一次程序,就会发现temp的值发生了变化,temp++被执行了一次。 如下所示:
Wacth 窗口的功能远不止这些。 Wacth窗口还可以设置变量在被读或写后自动停止运行。 这个功能在调试有大量行的项目时非常有用,因为在很多场景下,一个变量可能会在几十个或几百个地方被修改。 如果没有这个函数,将很难检查变量是否被修改。
那么这个功能要如何设置呢?
首先,右键单击“temp”,会出现一个列表,单击“设置为“temp””。 如下所示:
此时会弹出一个窗口,您可以在其中设置函数在读取或写入时是否自动停止运行。 设置好后点击即可。
Wacth窗口对于调试我们的代码还是很有用的,大家都可以掌握。
同样,我们举一个例子。
首先我们在程序中定义一个类型为temp[10]的值,然后对数组{1,2,3,4,15}的前五个数字进行赋值,其他元素默认值为0。循环中我们执行 temp[0]++ 并仅增加第一个元素。
编译一下,打开模拟工具,然后打开窗口,在窗口中输入temp,这样我们就可以看到temp数组在内存中的地址和值了。 前面我们给数组赋值了{1,2,3,4,15},在窗口中可以看到temp数组以十六进制表示为“01 02 03 04 0F”。 如下所示:
(注意M3/M4/M7内核是-模式,内存值必须反向读取)
该窗口可以帮助我们快速查看内存中变量的地址和值,方便我们调试程序。
5. 总结
总的来说,如果想要更好地了解单片机,MDK仿真工具是必不可少的。 MDK仿真工具不仅功能强大,而且操作简单。 对于新手来说也非常友好。 最重要的是它可以帮助我们更好的理解和调试程序代码。 学习使用MDK仿真工具可以让你的技术更上一个台阶。
最后,如果您有电子设计或其他相关技术的原创文章,欢迎您提交给我们。 我们会选出最好的,发表文章后您将获得稿费奖励!
温馨提示: