Keil MDK高级调试——Event Recorder

前言

如今,灵活且易于使用的中间件组件在现代微控制器应用中至关重要。 这些软件组件通常是应用程序程序员的“黑匣子”。 即使提供了全面的文档和源代码,对潜在问题的分析也具有挑战性。MDK调试器提供了Component Viewer和Event Recorder,它们显示软件组件的执行状态和事件信息,从而帮助您了解和分析内部操作。 所需的基础结构已在MDK中间件和Keil RTX5中实现。 但是,可以将这些视图轻松添加到其他软件组件或用户应用程序。

什么是Event Recorder?

就是通过在代码中调用Event API来记录软件运行的一些标志信息,然后通过MDK相关的调试窗口以图形化的形式显示出来。

说明:MDK调试器提供了Component Viewer和Event Recorder,它们显示软件组件的执行状态和事件信息,从而帮助您了解和分析内部操作。 所需的基础结构已在MDK中间件和Keil RTX5中实现。 但是,可以将这些视图轻松添加到其他软件组件或用户应用程序。

Component Viewer and Event Recorder views defined in SCVD format

Event Recorder与传统的串口printf调试区别及优势

1. prinf调试信息只能以字符串的形式显示,Event Recorder提供信息的分类可以在特定的窗口中以图形化的形式显示

2. 传统串口printf调试需要占用芯片的外设资源(一个串口)且由于串口速度限制。而Event Recorder是直接获取的芯片内存的数据速度与CPU主频一样。

3. 传统串口printf调试对于中断应用的调试会受限制,由于需要调用printf函数期间会占用不少CPU时间。而Event Recorder是直接获取内存的数据,速度快。

4. Event Recorder不需要占用芯片的外设资源

Event Recorder有什么作用?

1. 获取软件组件或者用户代码中的运行情况并通过MDK的Event Recorder和Component Viewer窗口清晰明了的显示

2. 支持Keil RTX操作系统调试以及MDK自带的中间件(文件系统、USB组件、网络组件、图形界面等)的调试。可以清楚的记录中间件以及RTX的执行情况

3.支持用户自定义即可以将用户自己写的代码也添加到Event Recorder窗口中并显示。具体请参考arm官方的帮助文档。

怎么使用Event Recorder?

准备工作

1. 硬件调试器:ULink、Jlink、ST-Link、CMSIS-DAP等只要是MDK支持的调试器就行

2. 如果MDK的RTE中没有找到Comiler组件。就需要在Keil官网下载下载Compiler组件,。https://www.keil.com/dd2/pack/

开始使用

1. 新建工程... 此处省略。如果不懂的如何创建工程的,请自行百度

2. 配置工程

1. 打开RTE(Manage Run-Time Environment窗口),在Compiler组件下勾选Event Recorder

2. 将Compiler组件下的I/O组件下中的STDOUT并将其修改为EVR。这一步是为了将printf函数重定向到Event Recorder上

3. 添加Event Recorder代码

在需要使用Event Recorder的代码处,调用Event Recorder API函数。同时如果需要进行printf输出的地方直接使用printf函数即可。

注:需要添加EventRecorder.h头文件。

具体的Event Recorder API函数,请参考帮助文档。在MDK的安装目录下,如:

4. 配置调试器

点击Options for Target图标 >> Debug >> Trace。主要设置Core Clock为具体的芯片内核时钟频率,然后勾选Trace Enable

5. 编译并开始调试工程

点击调试按钮,点击View - Analysis Windows - Event Recorder

备注说明:

关于MDK组件调试中Event id中的component number的取值及对应的组件事件。请参考MDK组件的头文件。如:FileSystem中的Debug头文件:

相应的测试代码工程:

链接:https://pan.baidu.com/s/11Wvv1xpwkYoK2dyHLj9KNw 
提取码:jack 
 

Keil MDK中使用树可以通过定义树节点结构体和使用指针来实现。下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义树节点结构体 typedef struct node { int data; struct node *left; struct node *right; } TreeNode; // 创建节点 TreeNode* create_node(int data) { TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); node->data = data; node->left = NULL; node->right = NULL; return node; } // 插入节点 TreeNode* insert_node(TreeNode* root, int data) { if (root == NULL) { return create_node(data); } if (data < root->data) { root->left = insert_node(root->left, data); } else { root->right = insert_node(root->right, data); } return root; } // 计算树的深度 int tree_depth(TreeNode* root) { if (root == NULL) { return 0; } int left_depth = tree_depth(root->left); int right_depth = tree_depth(root->right); return (left_depth > right_depth ? left_depth : right_depth) + 1; } int main() { // 创建根节点 TreeNode* root = create_node(5); // 插入节点 root = insert_node(root, 3); root = insert_node(root, 7); root = insert_node(root, 1); root = insert_node(root, 4); root = insert_node(root, 6); root = insert_node(root, 8); // 计算树的深度并输出 int depth = tree_depth(root); printf("Tree Depth: %d\n", depth); return 0; } ``` 在这个示例代码中,我们首先定义了一个树节点结构体,包含了节点数据和左右子节点指针。然后我们定义了创建节点和插入节点的函数,使用递归的方式实现。最后我们定义了计算树深度的函数,并在main函数中使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值