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

【国产单片机】华大HC32L13系列printf调试实战:从半主机模式到MicroLib的深度解析

1. 为什么printf在华大HC32L13上不工作第一次用华大HC32L13开发板时我像往常一样在代码里写了个printf(Hello World)结果发现串口死活没输出。这个问题困扰了我整整两天后来才发现问题出在ARM内核的特殊机制上。这个国产单片机采用的是ARM Cortex-M0内核和常见的STM32一样直接调用标准库的printf函数是行不通的。根本原因在于ARM架构的两种特殊机制半主机模式Semihosting和微库MicroLib。标准C库的printf默认会尝试通过半主机模式与调试主机通信而我们的开发板显然没有这个功能。这时候就需要我们手动重定向输出到串口这也是嵌入式开发中的常见操作。2. 半主机模式看不见的通信桥梁2.1 半主机模式的工作原理半主机模式是ARM提供的一种特殊调试机制。当我们在代码中调用printf时ARM内核会通过BKPT指令触发调试异常调试器如J-Link捕获这个异常后会将输出内容传递给主机端的IDE显示。这种方式在模拟器环境下很好用但在实际硬件上就会出问题。我在项目中就遇到过这种情况代码在模拟器运行正常但烧录到HC32L13开发板后printf就失效了。这是因为开发板没有实现半主机模式所需的调试接口。要解决这个问题我们需要在代码开头加上#pragma import(__use_no_semihosting)这行代码告诉编译器不要使用半主机模式。但光这样还不够我们还需要实现一些必要的底层函数。2.2 关闭半主机模式的完整操作在华大HC32L13的官方库文件ddl.c中大约208行位置我们需要添加以下代码#if defined (__CC_ARM) #pragma import(__use_no_semihosting) void _sys_exit(int x) { x x; } struct __FILE { int handle; }; FILE __stdout; #endif这段代码做了三件事禁用半主机模式提供一个空的_sys_exit函数避免链接错误定义标准输出所需的FILE结构体3. MicroLib为嵌入式而生的精简库3.1 MicroLib的特点与限制MicroLib是Keil提供的一个特殊C库专为资源受限的嵌入式系统设计。相比标准库它有以下几个特点代码体积小可以节省最多10KB的Flash空间不支持文件操作和缓冲I/O不需要半主机模式对浮点数支持有限在华大HC32L13这种Flash只有32KB的单片机上使用MicroLib可以显著节省空间。但要注意MicroLib的printf性能比标准库慢特别是在处理浮点数时。3.2 启用MicroLib的正确姿势在Keil中启用MicroLib很简单打开Options for Target对话框切换到Target标签页勾选Use MicroLIB选项但仅仅这样还不够我们还需要重定向fputc函数告诉printf如何输出字符。这就是为什么很多新手勾选了MicroLib还是看不到输出的原因。4. 三种实战解决方案4.1 方法一修改Debug_Output函数在华大官方库的ddl.c文件中约173行有一个被注释掉的Debug_Output函数。我们可以取消注释并修改为void Debug_Output(uint8_t u8Data) { M0P_UART0-SCON_f.REN 0; M0P_UART0-SBUF u8Data; while (TRUE ! M0P_UART0-ISR_f.TC) { ; } M0P_UART0-ICR_f.TCCF 0; }这个方法的特点是直接操作寄存器效率最高需要自行处理换行符转换\n→\r\n只适用于查询方式发送我在实际项目中发现这个方法代码量最小但灵活性较差。如果需要使用中断发送就得换其他方法。4.2 方法二重定向fputc使用库函数在ddl.c文件中约231行我们可以修改fputc函数int fputc(int ch, FILE *f) { Uart_SendDataPoll(M0P_UART0, ch); return ch; }这种方法使用了华大提供的库函数优点是代码更简洁可以方便地切换查询/中断模式兼容性更好需要注意的是使用这个方法前要在ddl.h中添加#include uart.h4.3 方法三混合寄存器与fputc结合前两种方法的优点我们可以这样实现fputcint fputc(int ch, FILE *f) { while (0 (M0P_UART0-ISR 0x08)) { ; } M0P_UART0-SBUF_f.DATA (unsigned char)ch; return ch; }这种实现的特点是比纯寄存器方式可读性更好比纯库函数方式效率更高方便在不同串口间切换5. 如何选择最佳方案根据我的项目经验选择方案时需要考虑以下因素代码空间限制如果Flash非常紧张比如小于16KB建议使用方法一如果有足够空间方法二或三更易维护性能要求高波特率115200时方法一性能最好低波特率下差异不大开发效率方法二最容易实现和调试方法一需要更熟悉寄存器操作功能需求如果需要支持多个串口输出方法三最灵活如果只需要基础调试输出方法一足够在我的HC32L13低功耗项目中最终选择了方法二因为项目对Flash空间不敏感需要支持中断发送模式代码可读性更重要6. 常见问题与调试技巧6.1 为什么修改后还是没输出遇到这种情况建议按以下步骤排查确认串口引脚配置正确特别是复用功能检查波特率设置确保PC端和MCU端一致用逻辑分析仪抓取TX引脚信号确认没有其他代码关闭了串口时钟6.2 输出乱码怎么办乱码通常是波特率不匹配导致的。华大HC32L13的时钟树比较复杂要注意确认系统时钟配置正确检查UART时钟源是否稳定避免在低功耗模式下使用高波特率6.3 如何减少printf的代码体积如果只需要输出字符串可以考虑使用更轻量的实现void simple_print(const char *str) { while(*str) { Debug_Output(*str); } }这样可节省约2KB的Flash空间。7. 进阶技巧实现变参打印有时候我们可能需要比printf更灵活的打印功能。可以自己实现一个简易版#include stdarg.h void my_printf(const char *fmt, ...) { va_list args; va_start(args, fmt); char buffer[32]; vsnprintf(buffer, sizeof(buffer), fmt, args); const char *p buffer; while(*p) { Debug_Output(*p); } va_end(args); }这个实现虽然功能有限但比标准printf节省了大量空间。

相关文章:

【国产单片机】华大HC32L13系列printf调试实战:从半主机模式到MicroLib的深度解析

1. 为什么printf在华大HC32L13上不工作? 第一次用华大HC32L13开发板时,我像往常一样在代码里写了个printf("Hello World"),结果发现串口死活没输出。这个问题困扰了我整整两天,后来才发现问题出在ARM内核的特殊机制上。…...

HarmonyOS APP<玩转React>开源教程二十:收藏功能实现

第20次:收藏功能实现收藏功能让用户可以标记感兴趣的课程,方便后续快速访问。本次课程将完整实现收藏功能,包括服务层、状态管理和收藏页面。项目效果学习目标 掌握 BookmarkService 设计学会收藏状态管理实现收藏列表持久化完成收藏页面开发…...

nnUNetV2实战:从零构建医学影像2D分割数据集全流程解析

1. 环境准备与框架安装 第一次接触nnUNetV2时,我被它繁琐的环境依赖搞得焦头烂额。现在回想起来,其实只要掌握几个关键点就能避开大部分坑。建议使用Python 3.9的环境,我实测Python 3.10的兼容性最好。先通过conda创建隔离环境: c…...

从吾爱论坛到开源神器:EternalBlaze作者的技术初心与硬链接工具诞生记

在国产软件生态中,有这样一群开发者——他们不为商业利益,只为解决实际问题; 他们不求声名远播,只愿作品惠及他人。 EternalBlaze的创作者Henglie正是这样一位典型的技术实践者。 这款源于吾爱破解论坛的硬链接工具&#xff0c…...

大容量硬盘空间管理实战:用EternalBlaze硬链接技术优化TB级存储资源

在数据爆炸式增长的时代,个人用户拥有数TB存储空间已不罕见。 从4K视频素材到高分辨率照片,从虚拟机镜像到开发环境快照,大容量硬盘承载着日益庞大的数字资产。 然而,存储容量的扩张往往伴随着效率的下降——重复文件在庞大的数…...

python cosyVoice实现tts文本转语音、音频(未完成)

文章目录步骤chatTts需要连外网不好用,想着本地弄个。阿里开源项目cosyVoice(舒适语音)(是cosy,不是cos)评级比较不错。步骤 1、pycharm工作区新建文件夹cosyVoice-demo,进入文件夹clone代码。 https://github.com/FunAudioLLM/CosyVoice.gi…...

深搜算法 6300:Grid Path Construction(2418)

6300:Grid Path Construction(2418)时间限制: 1000 ms 内存限制: 524288 KB 提交数: 0 通过数: 0 Special Judge【题目描述】Given an nm grid and two squares a(y1,x1) and b(y2,x2), create a path from a to b that visits each square exactly…...

别再乱用jet了!Matplotlib中5个最值得推荐的科学可视化colormap及使用场景

科学可视化中的色彩艺术:Matplotlib最佳colormap实践指南 在科研论文和工程报告中,数据可视化是传递复杂信息的核心手段。然而,许多研究者至今仍在无意识地使用已被科学可视化领域淘汰的jet色标——这种彩虹色标不仅会造成数据特征的误读&…...

3DTiles白膜性能优化指南:如何让SHP建筑模型在Cesium中流畅加载

3DTiles白膜性能优化实战:从SHP到Cesium的高效加载策略 当我们将城市级建筑SHP数据转换为3DTiles白膜时,最令人头疼的莫过于浏览器中缓慢的加载速度和卡顿的交互体验。我曾在一个智慧园区项目中处理过包含2万多栋建筑的SHP数据集,初始转换后的…...

从YouTube到国内大厂,VPU(视频处理单元)如何重塑视频云的技术栈?

VPU技术革命:解码下一代视频云架构的三大范式转移 当你在深夜用手机观看4K直播时,是否想过每秒数GB的视频数据如何穿越千里依然清晰流畅?当城市每个角落的摄像头都在实时上传画面时,这些海量视频流又如何在云端被高效处理&#xf…...

NRF52系列选型终极指南:从52810到52840,5个关键指标帮你省下30%成本

NRF52系列选型终极指南:从52810到52840,5个关键指标帮你省下30%成本 在物联网设备开发中,芯片选型往往决定了项目60%以上的成本结构。作为Nordic Semiconductor的明星产品线,NRF52系列凭借其出色的低功耗性能和丰富的外设资源&…...

联发科MTK Sensor Bring Up避坑指南:以STK3321为例的常见问题解析

联发科MTK Sensor Bring Up深度实战:STK3321典型问题与系统化解决方案 在联发科(MTK)平台进行传感器(Sensor) Bring Up是智能设备开发中的关键环节,却也是最容易踩坑的技术难点之一。作为MTK生态中广泛使用的环境光传感器,STK3321的集成过程看…...

ARM64服务器上Docker跑Redis总崩溃?3种配置文件调试方案实测

ARM64服务器上Docker跑Redis总崩溃?3种配置文件调试方案实测 最近在ARM64架构服务器上部署Redis时,不少开发者都遇到了容器启动后立即退出的问题。这并非简单的配置错误,而是ARM架构与x86环境的差异导致的兼容性问题。本文将分享三种经过实测…...

Ubuntu20.04下微信中文输入终极解决方案:修改deepin-wine配置全记录

Ubuntu 20.04下微信中文输入问题的深度解决方案 作为一名长期使用Linux系统的开发者,我深知在Ubuntu上使用微信时遇到中文输入问题的痛苦。特别是在需要频繁与同事、客户沟通时,这个问题会严重影响工作效率。本文将分享一套经过实战验证的解决方案&#…...

锂离子电池恒流恒压充电Simulink仿真模型(CC-CV)及其电路结构与充电过程说明

锂离子电池恒流恒压充电Simulink仿真模型(CC-CV) 电路结构包括:直流电压源、DC/DC变换器、锂离子电池、CCCV控制系统 [hot]赠送2000多字的说明文档和参考文献,帮助您更快理解 恒流恒压充电过程: [1]在CC阶段对电池施加…...

利用Mermaid在Markdown中高效构建数据库ER图

1. 为什么选择Mermaid画ER图 第一次接触数据库设计时,我用Visio画了三天ER图,结果产品经理说要改两个字段,所有连线都得重新调整。直到发现Markdown里用Mermaid画ER图的玩法,才明白什么叫"降维打击"。这个组合有多香&am…...

OpenHarmony开发避坑指南:手把手教你写对BUILD.gn,解决90%的编译问题

OpenHarmony开发避坑指南:手把手教你写对BUILD.gn,解决90%的编译问题 在OpenHarmony开发中,BUILD.gn文件是构建系统的核心配置文件,它决定了代码如何被编译、链接和打包。然而,许多开发者在编写BUILD.gn时常常陷入各种…...

8、C语言指针专题:指针与字符串

在C语言中,字符串本质是“以空字符\0结尾的字符序列”,而指针是操作字符串最灵活、高效的工具。字符串的存储、访问、修改、排序及各类处理,都可以通过指针实现,且指针操作相比数组下标操作,更节省内存、执行效率更高。…...

从Maya到Max:如何完美转换Bone骨骼并优化飘带动画效果

从Maya到Max:专业级骨骼转换与飘带动画优化全流程 在3D动画制作中,角色服装、头发等飘动元素的自然表现往往决定了作品的真实感与视觉冲击力。作为资深动画师,我经常需要在Maya和3ds Max这两个行业标准软件之间切换工作流程。本文将分享一套…...

7、C语言指针专题:多级指针

在C语言中,指针的核心是“指向内存地址”,而多级指针则是“指向指针的指针”——二级指针指向一级指针的地址,三级指针指向二级指针的地址,以此类推。多级指针看似复杂,实则是一级指针逻辑的延伸,其核心用途…...

MAC和PHY到底在搞什么?用大白话拆解网卡工作原理

MAC和PHY到底在搞什么?用大白话拆解网卡工作原理 作为硬件工程师,调试网卡时最常遇到的灵魂拷问就是:"为什么ping不通?"这时候如果连MAC和PHY在搞什么都不清楚,那真是两眼一抹黑。今天我们就用修车师傅看发动…...

LLM 大语言模型 训练的时候 batchsize 调整大导致梯度爆炸问题解决

LLM 大语言模型 训练的时候 batchsize 调整大导致梯度爆炸问题解决 优化器AdamW 确实比 SGD 更容易在大 batch 下梯度爆炸,因为自适应学习率会放大稀疏梯度的更新步长。 针对 AdamW 大 batch,给你几个立竿见影的修复方案: 1. 优化器参数调整…...

第8章 时序数据的洞察:从构建到分析的全链路实践

第8章 时序数据的洞察:从构建到分析的全链路实践 时间序列数据是数据分析领域中最具挑战性也最具价值的类型之一。与普通的横截面数据不同,时间序列数据带有一个天然的顺序维度——时间。股票价格、气温变化、网站流量、销售额趋势,这些数据都随着时间推移而产生,前后观测…...

第7章 时间维度的雕琢:日期时间数据的清洗与计算艺术

第7章 时间维度的雕琢:日期时间数据的清洗与计算艺术 在数据分析的世界里,时间维度是最常见的分析轴线之一。无论是销售趋势分析、用户行为轨迹追踪,还是项目进度监控,日期时间数据都扮演着核心角色。然而,原始的日期时…...

第5章 数据融合之道:多源文件的聚合与分发艺术

第5章 数据融合之道:多源文件的聚合与分发艺术 在数据分析的实战过程中,单一数据文件往往无法满足复杂业务需求。真实的商业场景中,数据可能分散在数十个甚至上百个Excel工作簿中,每个工作簿可能包含多个工作表。例如,连锁企业的各门店每日上传销售报表,财务系统每月导出…...

UnityShader实战指南:从ShaderLab到Surface Shader的进阶之路

1. ShaderLab基础语法入门 第一次接触UnityShader时,我完全被ShaderLab的语法搞懵了。记得当时为了修改一个简单的颜色参数,花了整整一下午研究Properties块的写法。现在回头看,ShaderLab其实就像乐高积木的说明书,只要掌握几个核…...

从LangChain到Dify:手把手构建生产级AI工作流

摘要:本文深入解析从LangChain到Dify的技术演进,通过真实业务场景演示如何构建生产级AI工作流。涵盖从"胶水代码"到"企业级平台"的架构变迁,提供完整的代码实现、踩坑经验、性能优化策略,助你快速从原型走向生…...

养狗管理拟参照道路交通法个人观点:计分、吊证、入刑,这些行为将被终身禁养

近年来,犬只伤人事件频发,每年全国被猫狗咬伤抓伤人数高达4000万。这一数字远超交通事故发生量,但长期以来,养犬管理始终停留在“办个证、罚点款”的层面。如果养犬管理能够参照道路交通安全法的逻辑,建立“记分制”“…...

保姆级教程:用FFmpeg+Nginx把监控摄像头RTSP流转成HLS网页播放

从RTSP到HLS:零基础构建浏览器兼容的监控视频流系统 在智能安防和物联网应用场景中,监控摄像头产生的视频流通常采用RTSP协议传输,但现代浏览器却无法直接播放这种流媒体格式。本文将手把手带您实现RTSP到HLS的完整转换方案,通过F…...

PyAV实战:如何用TCP协议稳定拉取RTSP视频流(附超时解决方案)

PyAV实战:TCP协议拉取RTSP视频流的工程化解决方案 引言 在视频处理项目中,稳定获取RTSP流是许多开发者面临的共同挑战。不同于简单的本地文件读取,网络视频流传输涉及复杂的协议交互和实时性要求。PyAV作为FFmpeg的Python绑定,提供…...