这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【原创】STM32之别让Bug毁了你的周末——手把手教你搭建“硬核”日志系统--

共2条 1/1 1 跳转至

【原创】STM32之别让Bug毁了你的周末——手把手教你搭建“硬核”日志系统----From阿沛

工程师
2026-07-20 20:28:54     打赏

各位EEPW的同学,大家好。

今天咱们不聊算法,也不聊架构,聊点“接地气”的——调试。

我相信在座各位都有过这样的经历:程序在仿真器里跑得好好的,一断电重启就翻车;或者客户那边反馈设备偶尔死机,你连上电脑却死活复现不了。这时候,你手里的J-Link和ST-Link仿佛瞬间变成了“摆设”,除了能看看寄存器,什么忙都帮不上。

为什么?因为仿真器依赖“暂停”,而很多Bug恰恰是“动态”的。你一旦暂停,时序就变了,中断就乱了,Bug就跟捉迷藏一样躲起来了。

这时候,能救你的不是更贵的仿真器,而是一个设计良好的日志系统。

---

第一层:别把“printf”当万能药

很多同学一上来就用半主机模式(Semihosting)重定向`printf`到串口。这玩意儿在裸机学习阶段确实香,几句话就能看到数据。但我要泼一盆冷水:在产品级代码里,`printf`是头号性能杀手。

为什么呢?因为`printf`内部有大量的格式解析和字符串处理,动辄耗时几十微秒甚至毫秒级。如果你的串口中断里来一句`printf`,恭喜你,系统响应延迟直接原地爆炸。

那怎么办?我的原则是:用“轻量级日志”替代“万能打印”。

我自己常用的方案是封装一个简单的`log_printf`,但里面不直接调用标准库的`printf`,而是用`vsnprintf`先格式化到本地缓冲区,然后通过DMA+环形队列的方式把数据“悄悄”发出去。核心逻辑是:主循环只管往队列里丢数据,串口发送完全由DMA在后台搬运,CPU几乎零感知。

这样一来,哪怕你每秒打几百条日志,CPU占用率也基本可以忽略不计。

---

第二层:日志分级——别让信息淹没你

调试最怕什么?最怕打开串口助手,满屏滚动的全是“Enter Main”、“Tick+1”这种废话,真正关键的错误信息早就被冲没了。

我建议同学们建立一套日志分级机制,简单分四档就够用:

|级别|关键字|适用场景|

|ERROR|[E]|系统致命错误,比如外设初始化失败、内存分配失败|

|WARN|[W]|异常但可恢复的情况,比如通信重试、超时|

|INFO|[I]|关键流程节点,比如设备上线、参数加载完成|

|DEBUG|[D]|详细调试信息,变量值、状态跳转,仅在开发阶段开启|

关键是:通过一个宏开关,在Release版本里把DEBUG级别的日志全部编译掉,不占ROM也不占RAM。这样既保留了调试手段,又不会拖累最终产品的性能。

---

第三层:日志的“归宿”——不止是串口

很多同学觉得日志就是往串口打印,这其实限制了思路。我来分享几个实战中我觉得很实用的“变通”方案:

1.掉电保存型日志:如果你用的是STM32F4/F7系列,内部Flash通常有多余扇区。当系统触发HardFault或看门狗复位之前,把当前的函数调用栈、关键寄存器值、最后一条心跳消息,一股脑写入后备Flash。下次上电时先读取这段“遗书”,通过串口打印出来。这招排查偶发性死机,屡试不爽。

2.RTT(Real-Time Transfer)替代串口:如果你手头有J-Link,强烈建议试试SEGGER的RTT。它比串口快几个数量级,而且不需要额外的TX/RX引脚。调试时开着RTT Viewer,变量变化实时可见,比干瞪眼看串口数据高效太多了。

3.逻辑分析仪“旁路”监听:对于实在没法打日志的极端情况(比如中断频率太高,打日志反而引发新Bug),我会用GPIO翻转法——在关键函数入口拉高一个闲置IO,出口拉低,然后用逻辑分析仪抓波形。看脉冲宽度和间隔,基本就能推断出函数执行时间和调用频率,这招模拟电路出身的工程师特别爱用。

---

最后说几句掏心窝的话

同学们,调试能力其实是一个嵌入式工程师“段位”的重要分水岭。刚入门时,大家都喜欢“哪里出问题就盯哪里”;但真正成熟之后,你会发现优秀的日志设计,本身就是一种防御性编程。

它不解决问题,但它能让你在问题发生的第一时间,拿到最完整的现场证据。有了证据,查Bug就从“玄学推理”变成了“刑侦破案”,差别有多大,谁用谁知道。

 



院士
2026-07-21 22:40:00     打赏
2楼

RTT(Real-Time Transfer)替代串口

这个策略非常棒,非常建议大家来尝试


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]