首页 > 资讯 > 科技 > 正文
2024-03-05 08:07

听说你会调试?

在当今的嵌入式系统开发领域,高效的调试工具对于工程师来说至关重要。 它们可以显着减少开发周期中的错误跟踪时间并加快产品上市时间。 作为业界领先的嵌入式开发工具之一,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窗口还可以设置变量被读或写后自动停止运行,这对代码调试很有帮助。 您可以定义一个函数,在窗口中输入该函数的名称,然后将一个数字传递给该函数。 在此窗口中您可以看到该函数的寄存器的首地址。 传完号码后可以看到号码的类型是Wh​​at。

点击该按钮,弹出界面如下:

让我们举一个例子来演示这个过程。 例如定义一个全局变量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仿真工具可以让你的技术更上一个台阶。

最后,如果您有电子设计或其他相关技术的原创文章,欢迎您提交给我们。 我们会选出最好的,发表文章后您将获得稿费奖励!

温馨提示: