当前位置: 首页 > news >正文

Keil MDK 将不同文件中的特定数据链接到同一位置

最近在一个STM32的项目中,为了方便现场调试的抓取一些运行数据,就想在项目中增加类似于 linux 的串口终端,实现一些基本命令行的调试命令。本着开源优先的原则,一通搜索,最终选定了 xcmd 这个开源库。

XCMD 介绍 https://gitee.com/two_salted_eggs/xcmd.git

它有以下几个优点:

  • 移植十分简单
  • 资源占用很小
  • 支持历史记录
  • 支持命令自动补全
  • 支持注册快捷键
  • 支持 xcmd_cmd_register()/xcmd_key_register()方法注册命令或按键
  • 支持 XCMD_EXPORT_CMD()/XCMD_EXPORT_KEY()方法直接导出命令或按键,不需要额外运行注册函数

具体的移植过程看 readme.md 文件即可,参考 example 中的 demo, 不到 20分钟就能把例程在项目上跑起来了。
但是项目提供的 demo 没有启用 ENABLE_XCMD_EXPORT 选项,命令和按键是通过 xcmd_cmd_register()/xcmd_key_register() 在运行时注册。
如下图所示:
image

通过 xcmd_cmd_register()/xcmd_key_register() 注册命令和按键会有额外的RAM开销,如下图所示,每条命令也会有32bytes(32位的MCU)的链表项。
image

而通过 XCMD_EXPORT_CMD()/XCMD_EXPORT_KEY() 导出,则可以将命令和按键以常量表的方式放到 FLASH 中。
image

下面修改例程 “example\stm32\MDK\stm32f4xx” 以说明在 keil mdk 中,启用 ENABLE_XCMD_EXPORT 选项的步骤

  1. 首先打开工程文件 “Project/test.uvprojx”,编译项目,确保能正确编译完成。
    然后将 “Output” 目录下的文件 “test.sct” 复制一份到 “Project” 目录。
    打开工程配置页面(Options for Target),切换到 Linker 页面,去掉 “Use Memory Layout from Taget Dialog” 的选中状态,同时通过 ScatterFile 栏的 “...” 选择刚才复制到 “Project” 目录的 “test.sct” 文件。
    如下图所示:
    image

  2. 点击上图中的 “Edit...” 打开 “test.sct” 文件。如下,在 “ER_IROM1” 域添加下面 11~16 行的内容:
    下面添加的部分,链接器会按照字典顺序排序。这是在keil MDK中能使用 XCMD_EXPORT_CMD()/XCMD_EXPORT_KEY() 的关键点。

点击查看代码
1.     ; ************************************************************* 
2.     ; *** Scatter-Loading Description File generated by uVision *** 
3.     ; ************************************************************* 5.     LR_IROM1 0x08000000 0x00200000 { ; load region size_region 
6.       ER_IROM1 0x08000000 0x00200000 { ; load address = execution address 
7.           *.o (RESET, +First) 
8.           *(InRoot$$Sections) 
9.           .ANY (+RO) 
10.           .ANY (+XO) 
11.           *(a1_xcmd_cmd_list_start) 
12.           *(a2_xcmd_cmd_list) 
13.           *(a3_xcmd_cmd_list_end) 
14.           *(b1_xcmd_key_list_start) 
15.           *(b2_xcmd_key_list) 
16.           *(b3_xcmd_key_list_end) 
17.         } 
18.         RW_IRAM1 0x20000000 0x00030000 { ; RW data 
19.         .ANY (+RW +ZI) 
20.       } 
21.     }

  1. 打开 “inc\xcmd.h”, 将下面的代码:
点击查看代码
#define XCMD_EXPORT_CMD(_name, _func, _help)  XCMD_USED const xcmd_t XCMD_SECTION("_xcmd_cmd_list") \ xcmd_cmd_##_name={\ .name=#_name, \ .func=_func, \ .help=_help\ }; 
#define XCMD_EXPORT_KEY(_key, _func, _help)   XCMD_USED const xcmd_key_t XCMD_SECTION("_xcmd_key_list") \ xcmd_key_##_key={\ .key=_key, \ .func=_func, \ .help=_help\ }; 

改为下面所示内容:

点击查看代码
#if defined(__CC_ARM) || defined(__CLANG_ARM)
#define XCMD_EXPORT_CMD(_name, _func, _help)        XCMD_USED const xcmd_t XCMD_SECTION("a2_xcmd_cmd_list") \xcmd_cmd_##_name={\.name=#_name, \.func=_func, \.help=_help\};
#define XCMD_EXPORT_KEY(_key, _func, _help)         XCMD_USED const xcmd_key_t XCMD_SECTION("b2_xcmd_key_list") \xcmd_key_##_key={\.key=_key, \.func=_func, \.help=_help\};
#else
#define XCMD_EXPORT_CMD(_name, _func, _help)        XCMD_USED const xcmd_t XCMD_SECTION("_xcmd_cmd_list") \xcmd_cmd_##_name={\.name=#_name, \.func=_func, \.help=_help\};
#define XCMD_EXPORT_KEY(_key, _func, _help)         XCMD_USED const xcmd_key_t XCMD_SECTION("_xcmd_key_list") \xcmd_key_##_key={\.key=_key, \.func=_func, \.help=_help\};														
#endif	//#if defined(__CC_ARM) || defined(__CLANG_ARM)

  1. 打开 “src\xcmd_default_cmds.c”, 将下面的代码:
点击查看代码
XCMD_EXPORT_CMD(help, cmd_help, "show this list") 
XCMD_EXPORT_CMD(clear, cmd_clear, "clear screen") 
XCMD_EXPORT_CMD(keys, cmd_keys, "show keys") 
XCMD_EXPORT_CMD(logo, cmd_logo, "show logo")

改为下面的内容:

点击查看代码
#if defined(ENABLE_XCMD_EXPORT) && (defined(__CC_ARM) || defined(__CLANG_ARM)) XCMD_USED const xcmd_t XCMD_SECTION("a1_xcmd_cmd_list_start") _xcmd_cmd_list_start = {"help", cmd_help, "show this list"}; XCMD_USED const xcmd_t XCMD_SECTION("a3_xcmd_cmd_list_end") _xcmd_cmd_list_end = {NULL, NULL, NULL}; 
#else XCMD_EXPORT_CMD(help, cmd_help, "show this list") 
#endif XCMD_EXPORT_CMD(clear, cmd_clear, "clear screen") 
XCMD_EXPORT_CMD(keys, cmd_keys, "show keys") 
XCMD_EXPORT_CMD(logo, cmd_logo, "show logo") 

  1. 打开 “src\xcmd_default_cmds.c”, 将下面的代码:
点击查看代码
XCMD_EXPORT_KEY(KEY_CTR_H, xcmd_del_char, "backspace") 
XCMD_EXPORT_KEY(KEY_BACKSPACE, xcmd_del_char, "delete") 

改为下面的内容:

点击查看代码
#if defined(ENABLE_XCMD_EXPORT) && (defined(__CC_ARM) || defined(__CLANG_ARM)) XCMD_USED const xcmd_key_t XCMD_SECTION("b1_xcmd_key_list_start") _xcmd_key_list_start = {KEY_CTR_H, xcmd_del_char, "backspace"}; XCMD_USED const xcmd_key_t XCMD_SECTION("b3_xcmd_key_list_end") _xcmd_key_list_end = {NULL, NULL, NULL}; 
#else XCMD_EXPORT_KEY(KEY_CTR_H, xcmd_del_char, "backspace") 
#endif XCMD_EXPORT_KEY(KEY_BACKSPACE, xcmd_del_char, "delete") 

修改后的代码可以参考我 fork 的副本

https://gitee.com/sqqdfny/xcmd/tree/dev-sqqdfny

http://www.hskmm.com/?act=detail&tid=30323

相关文章:

  • 1013日总结
  • 数据流图
  • 2025公众号排版效率榜:5款AI工具实测对比,从排版到分发一站搞定
  • OpenLayers地图交互 -- 章节十六:双击缩放交互详解 - 教程
  • CF1935E Distance Learning Courses in MAC
  • 联考の记录
  • 06-mysql备份实战 #
  • 静态内部类
  • 05_mysql备份方案
  • 实验1_CPP
  • 数组
  • CF2153 Codeforces Round 1057 (Div. 2) 游记
  • 从《花果山》到《悬鉴》:一首诗的蜕变与AI元人文理论的建构历程
  • java循环
  • 10.13做题笔记
  • java语法(switch)
  • 详细介绍:微服务与面向服务编程(SOA)入门指南:从架构演进到 Spring Cloud 实践(初学者友好版)
  • python中修改局部json的思路
  • LSNet
  • Webpack 构建速度优化
  • [模拟赛] 过关(pass)
  • 2025.10.13
  • 第十三节:基于 Redis+MQ+DB实现高并发秒杀下的扣减
  • c++初体验
  • 元宇宙的搜索引擎:如何在虚拟世界中查找信息 - 详解
  • 四则运算错题本和错题重做的建立
  • 行列式的性质
  • 04_SQL语句一
  • 死锁的原因、表现以排查
  • 详细介绍:【C++】二叉搜索树