本篇将介绍MDK下99%用户都不知道的万能printf方法。
一、说在前面的话
你听说过J-Link的RTT么?官方的宣传是这样的:
简单来说,只要拥有了J-Link,你就可以享受以下的便利:
无需占用USART或者USB转串口工具,将printf重定位到一个由J-LINK提供的虚拟串口上;
支持任何J-LINK声称支持的芯片
高速通信,不影响芯片的实时响应
它的缺点也是明显的:
你必须拥有一个J-Link,如果你使用的是 CMSIS-DAP或者ST-Link之类的第三方调试工具,就无法享受这一福利;
你必须在工程中手动插入一段代码
曾几何时,J-Link的这一福利让多少非J-Link用户羡慕嫉妒恨,看看手中的ST-Link、ULINKpro和各类廉价的CMSIS-DAP板载调试器——“隔壁邻居的小孩都馋哭了”
如果我告诉你,其实MDK中内置了一种非常简单廉价的方式,可以让你实现类似的功能,并具有以下特点:
支持所有的调试仿真器,哪怕自己手搓的CMSIS-DAP都行
MDK原生功能,连CMSIS-Pack都不用安装
点几下鼠标就可以通过RTE完成部署
除了简单的初始化函数外,无需手动插入代码
可以将你的printf输出直接打印在MDK的Debug (printf) View窗口中
你是否心动了呢?
二、部署从未如此简单
2.1RTE配置
依次通过菜单 Project->Manage->Run-Time Environment 打开RTE配置窗口:
找到并展开Compiler选项卡,勾选Event Recorder,并确保Variant下拉列表选中的是默认的DAP。
展开Compiler下的I/O,勾选STDOUT,并在Variant下拉列表中选择 EVR——这里EVR是Event Recorder的缩写。单击确定后,我们会在工程管理器中看到以下的内容:
至此,所需的工具都已经成功地加入到工程中了。
虽然这里EventRecorderConf.h是一个可以编辑的状态,但实践中,我们基本不用去碰他——使用默认配置即可。
2.2服务初始化
在包含main()函数的C代码文件中,按照如下的格式添加对头文件的包含:
#include#if defined(RTE_Compiler_EventRecorder) # include #endif
在main()函数中添加对EventRecorder服务的初始化:
void main(void) { ... #if defined(RTE_Compiler_EventRecorder) && defined(RTE_Compiler_IO_STDOUT_EVR) EventRecorderInitialize(0, 1); #endif ... }
如果你从未使用过EventRecorder也不必惊慌,这段代码的主要作用是为printf专门开启一个数据通道。
理论上,到这里,我们就已经完成了部署,可以在进入调试模式后,通过MDK的Debug (printf) View窗口来观察printf的输出结果了。比如,我们在main()函数中打印一个 "hello world ":
#include#include #if defined(RTE_Compiler_EventRecorder) # include #endif void main(void) { ... #if defined(RTE_Compiler_EventRecorder) && defined(RTE_Compiler_IO_STDOUT_EVR) EventRecorderInitialize(0, 1); #endif ... printf("Hello World "); ... }
编译,一切顺利的话,进入调试模式后通过菜单View->Serial Windows->Debug (printf) View打开窗口:
运行后,可以在Debug (printf) View窗口中看到如下的结果:
三、常见问题
如果你的工程中从未提供过对 ".bss.noinit"数据段的处理,那么很可能会发现通过上述方法实现的printf输出似乎不是很稳定——时有时无——处于一种薛定谔的状态。
这是由于EventRecorder有一段数据放置在了 “.bss.noinit” section中——以求芯片复位后不会破坏其中原有的内容。
如果你的工程没有专门针对 “.bss.noinit” 的处理,那么就会在进入调试模式后,从Command窗口中看到类似如下的信息:
即:
Warning: Event Recorder not located in uninitialized memory!
如果遇到这种情况应该怎么办呢?
打开工程配置窗口“Options for Target”,切换到“Linker”选项卡:
首先,一定要确保你勾选了图中的“Use Memory Layout from Target Dialog”选项。在这一前提下,再次取消对它的勾选:
我们会看到,MDK基于当前的Memory Layout,为我们在Out目录下生成了一个与工程同名的链接脚本(比如图中的工程名叫example,因此生成的链接脚本为example.sct)。
单击Edit按钮,可以看到脚本的内容:
先别着急半路开香槟——该文件是系统自动生成的,如果我们不移动它的位置,那么只要哪次手抖勾选了“Use Memory Layout from Target Dialog”,它的内容就会立即被覆盖掉——意味着我们在后续步骤中所做的修改就会付诸东流。
为了避免该问题,应该将它从Object目录中移动到工程目录下。具体步骤为:右键单击脚本文件名:
选择“Open Container Folder”来打开文件所在目录:
找到Scatter Script脚本文件后,将其拷贝到上一级目录下(也就是工程目录):
重新打开工程配置窗口:
确保我们“没有”选中“Use Memory Layout from Target Dialog”选项,并在Scatter File文本框中直接填写我们刚刚拷贝出来的脚本文件名(由于我们直接放在工程目录下,因此这里直接用相对路径"./example.scat"或者"example.scat"就行)。单击OK保存配置。
打开example.sct,在RW_IRAM1后面追加如下的代码:
ZI_RAM_UNINIT +0 UNINIT { .ANY (.bss.noinit) }
效果大约类似这样:
保存后重新编译,再次进入 Debug 模式,问题就应该解决了。
这里步骤的核心思想是在scatter script内紧接着为RW和ZI的execution region为.bss.noinit提供一个属性为UNINIT的专属execution region。
在领会精神的情况下,如果你的工程原本就使用了scatter script也可以如法炮制。俗话说解铃还须系铃人,如果你还是不知道怎么处理,那么就去找 你工程中scatter script的作者吧。
值得强调的是:如果你的MDK版本太老,为了确保最佳的用户体验,还是推荐尽快升级吧。您可以在关注【裸机思维】公众号后发送关键字【MDK】来获取其最新的网盘链接。
四、说在后面的话
总的来说,MDK通过EventRecorder为我们提供了一个通用便捷的方式来重定向printf——无论你使用什么调试仿真器,甚至是FVP,都可以享受来自“MDK”的阳光普照。
对很多有分发自己工程作为模板的小伙伴来说,使用该方法后将不再限制用户必须使用J-Link之类的工具,而是可以放开手脚,获得了“开袋即食”的调试体验。
最后强调一下哦,EventRecorder只在调试阶段有意义,如果我们需要在产品的正常工作模式下使用printf,还是老老实实把Compiler->IO->STDOUT配置为User:
实现stdout_putchar()函数——用它来发送字符到具体的外设吧,比如:
int stdout_putchar(int ch) { if (' ' == ch) { int temp = ' '; while(Driver_USART0.Send(&temp, 1) != ARM_DRIVER_OK); } if (Driver_USART0.Send(&ch, 1) == ARM_DRIVER_OK) { return ch; } return -1; }
-
usb
+关注
关注
60文章
8075浏览量
270178 -
串口
+关注
关注
14文章
1581浏览量
78469 -
MDK
+关注
关注
4文章
210浏览量
32463 -
J-Link
+关注
关注
0文章
88浏览量
22542 -
Printf
+关注
关注
0文章
84浏览量
14051
原文标题:MDK下99%用户都不知道的万能printf方法
文章出处:【微信号:Ithingedu,微信公众号:安芯教育科技】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
要学习protel了,不知道该学习是99还是***,更不知道在哪里找
电子万能试验机与液压万能试验机的区别
MDK下99%用户都不知道的万能printf方法
不知道电动车电池的型号怎么办?
万能遥控器设置方法_万能遥控器代码

关于人工智能的日常应用很多人都不知道
怎样调整地磅万能遥控器的四角误差
万能遥控器的设置和使用方法

射频干簧继电器的产品特性、优势及解决的痛点
长期以来,干簧继电器以其在切换和传输射频信号以及快速数字脉冲方面的出色性能而备受认可。然而,由于干簧管的引线通常由镍铁合金制成,这种材料的磁导率(µ)相对较高,因此人们普遍认为干簧继电器难以实现高达20GHz的射频信号切换与传输。如今,斯丹麦德电子成功突破了这一技术瓶颈。射频干簧继电器特性和优势产品特性高频应用限制:突破传统材料的限制,实现高达20GHz的高

TurMass™ 传输技术:赋能输变电物联网监测的核心引擎
随着新型电力系统建设持续推进,TurMass™ 技术凭借穿透性强、抗干扰优、安全性高等特点,已在变电站设备监测、山区线路防护、输电线路远程巡检等多个场景形成成熟的应用方案。其"精准感知、可靠传输、智能管控"的技术特性,正成为推动电网设备数字化改造的关键通信基座,为构建本质安全的智能输变电体系提供了可复制的技术路径。

ElfBoard技术实战|ELF 2开发板本地部署DeepSeek大模型的完整指南
ELF 2开发板本地部署DeepSeek大模型的完整指南

【H桥电机驱动电路原理】-学习笔记
工作原理电路分析这是一个由晶体管构成的H桥电机驱动电路,以下是对其各部分的介绍:核心器件晶体管:电路中使用了PNP型的SS8550(Q5、Q6)和NPN型的SS8050(Q9、Q10、Q13、Q14)。通过不同晶体管的导通与截止组合,实现电机两端电压极性的切换,进而控制电机正反转。比如,当Q5和Q10导通,Q6和Q9截止时,电流从MotorL+流入电机,从M

ATA-2041高压放大器在CFRP板分层缺陷的空耦超声原位测量中的应用
前言空气耦合超声波技术,作为一种高效且无损的检测方法,近年来在工业领域受到了广泛关注。其独特之处在于利用空气作为耦合介质,无需与被测物体直接接触,即可实现高精度的检测与成像。它能够检测在用CFRP板中的缺陷确保其应用安全,但传统的空气耦合超声方法通常依赖于线性缺陷指数在表征小尺寸缺陷方面无效。此外扫描步长完全限制了它们的成像空间分辨率,导致成像空间分辨率与检

TwinCAT3 EtherCAT抓包 | 技术集结
在使用TwinCAT测试EtherCATEOE功能时,我们会发现正常是无法使用Wireshark去进行网络抓包抓取EtherCAT报文的,今天这篇文章就带大家来上手EtherCAT抓包方式。准备环境硬件环境:EtherKit开发板网线一根Type-CUSB线一根软件环境TwinCAT3RT-ThreadstudiowiresharkEtherCATEOE工程

EtherCAT科普系列(8):EtherCAT技术在机器视觉领域的应用
机器视觉是基于软件与硬件的组合,通过光学装置和非接触式的传感器自动地接受一个真实物体的图像,并利用软件算法处理图像以获得所需信息或用于控制机器人运动的装置。机器视觉可以赋予机器人及自动化设备获取外界信息并认知处理的能力。机器视觉系统内包含光学成像系统,可以作为自动化设备的视觉器官实现信息的输入,并借助视觉控制器代替人脑实现信息的处理与输出。从而实现赋予自动化

新品 | 26+6TOPS强悍算力!飞凌嵌入式FCU3501嵌入式控制单元发布
飞凌嵌入式FCU3501嵌入式控制单元基于瑞芯微RK3588处理器开发设计,4xCortex-A76+4xCortex-A55架构,A76主频高达2.4GHz,A55核主频高达1.8GHz,支持8K编解码,NPU算力6TOPS,支持算力卡拓展,可以插装Hailo-8 26TOPS M.2算力卡。

接口核心板必选 | 视美泰AIoT-3568SC 、 AIoT-3576SC:小身材大能量,轻松应对多场景设备扩展需求!
在智能硬件领域,「适配」是绕不开的关键词。无论是小屏设备的”寸土寸金”,还是模具开发的巨额成本,亦或是多产品线兼容的复杂需求,开发者总在寻找一款能「以不变应万变」的核心解决方案。视美泰旗下的AIoT-3568SC与AIoT-3576SC接口核心板系列,可以说是专为高灵活适配场景而生!无需为设备尺寸、模具限制或产品线差异妥协,一块核心板,即可释放无限可能。为什

3核A7+单核M0多核异构,米尔全新低功耗RK3506核心板发布
近日,米尔电子发布MYC-YR3506核心板和开发板,基于国产新一代入门级工业处理器瑞芯微RK3506,这款芯片采用三核Cortex-A7+单核Cortex-M0多核异构设计,不仅拥有丰富的工业接口、低功耗设计,还具备低延时和高实时性的特点。核心板提供RK3506B/RK3506J、商业级/工业级、512MB/256MBLPDDR3L、8GBeMMC/256

搭建树莓派网络监控系统:顶级工具与技术终极指南!
树莓派网络监控系统是一种经济高效且功能多样的解决方案,可用于监控网络性能、流量及整体运行状况。借助树莓派,我们可以搭建一个网络监控系统,实时洞察网络活动,从而帮助识别问题、优化性能并确保网络安全。安装树莓派网络监控系统有诸多益处。树莓派具备以太网接口,还内置了Wi-Fi功能,拥有足够的计算能力和内存,能够在Linux或Windows系统上运行。因此,那些为L

STM32驱动SD NAND(贴片式SD卡)全测试:GSR手环生物数据存储的擦写寿命与速度实测
在智能皮电手环及数据存储技术不断迭代的当下,主控 MCU STM32H750 与存储 SD NAND MKDV4GIL-AST 的强强联合,正引领行业进入全新发展阶段。二者凭借低功耗、高速读写与卓越稳定性的深度融合,以及高容量低成本的突出优势,成为大规模生产场景下极具竞争力的数据存储解决方案。

芯对话 | CBM16AD125Q这款ADC如何让我的性能翻倍?
综述在当今数字化时代,模数转换器(ADC)作为连接模拟世界与数字系统的关键桥梁,其技术发展对众多行业有着深远影响。从通信领域追求更高的数据传输速率与质量,到医疗影像领域渴望更精准的疾病诊断,再到工业控制领域需要适应复杂恶劣环境的稳定信号处理,ADC的性能提升成为推动这些行业进步的重要因素。行业现状分析在通信行业,5G乃至未来6G的发展,对基站信号处理提出了极

史上最全面解析:开关电源各功能电路
01开关电源的电路组成开关电源的主要电路是由输入电磁干扰滤波器(EMI)、整流滤波电路、功率变换电路、PWM控制器电路、输出整流滤波电路组成。辅助电路有输入过欠压保护电路、输出过欠压保护电路、输出过流保护电路、输出短路保护电路等。开关电源的电路组成方框图如下:02输入电路的原理及常见电路1AC输入整流滤波电路原理①防雷电路:当有雷击,产生高压经电网导入电源时

有几种电平转换电路,适用于不同的场景
一.起因一般在消费电路的元器件之间,不同的器件IO的电压是不同的,常规的有5V,3.3V,1.8V等。当器件的IO电压一样的时候,比如都是5V,都是3.3V,那么其之间可以直接通讯,比如拉中断,I2Cdata/clk脚双方直接通讯等。当器件的IO电压不一样的时候,就需要进行电平转换,不然无法实现高低电平的变化。二.电平转换电路常见的有几种电平转换电路,适用于
评论