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

Keil 增量编译的坑:烧录的固件比代码老了一版,排查一下午

Keil 增量编译的坑:烧录的固件比代码老了一版,排查一下午

一句话: Keil 增量编译下,源码改了但没触发重编译时,hex 文件还是老版本的——直接把旧 hex 复制去烧录,芯片里跑的就是旧代码。烧完功能不对,先查 hex 时间戳,别一头扎进代码里。

适合谁读:用 Keil 命令行UV4 -b编译 + J-Link 脚本烧录,烧完功能不对第一反应是查代码的嵌入式工程师。

现象:烧录很顺利,功能却"丢"了

一次固件改动,改完代码、Keil 命令行编译、日志 0 Error 0 Warning,复制 hex 烧录,输出Downloading file+Program & Verify全都有——烧录过程完美。

然后测功能,坏事了:

  • 新加的逻辑(cmd 6 未使能推 0)完全不存在
  • 另一条命令(cmd 12 带地址读)发出去无响应

于是开始查代码:逻辑明明写了啊?编译也没报错啊?是不是哪里没使能?是不是初始化顺序问题?排查了一下午,一无所获

最后对了一下 hex 文件时间戳,真相大白:烧录的 hex 是上一次编译的旧产物,这次的源码改动根本没编译进去。

根因:Keil 增量编译不重编译 = hex 不更新

Keil 增量编译(Incremental Build)的机制:

  • 源码没变→ 跳过该文件编译 → 链接产物不变 →hex 时间戳不更新
  • 源码变了→ 重编译该文件 → hex 更新

看起来没毛病。但命令行批量编译时有个致命场景:你改的源码和 hex 的时间戳只差几分钟,甚至相同——因为你上一轮编译过,这一轮 Keil 判断"没有变化"直接跳过了,但你自己不知道,还当它编译过了。

更隐蔽的是:上一轮编译是另一份代码(比如调试中途改坏又改回),或者 hex 是从别的目录复制来的。你手上这个 hex,可能比源码老了好几版。

关键认知:"编译日志 0 Error" ≠ "hex 包含最新代码"。增量编译下,日志只能证明"编译没报错",不能证明"编译发生过了"。

对策:烧录前三步走,一步都不能省

从此烧录流程固定为三步,中间不插任何其他操作:

① UV4 -b 重新编译 ② 对比 hex 时间戳 vs 最近源码修改时间(不一致就停) ③ 复制 hex 到烧录目录 → J-Link 烧录

第 ② 步是核心,命令行一条命令就能比:

# 烧录前:hex 时间必须 >= 最近源码修改时间 test "$(stat -c %Y hex/firmware.hex)" -ge "$(find src -name '*.c' -o -name '*.h' | xargs stat -c %Y | sort -n | tail -1)" \ || echo "警告:hex 比源码旧,禁止烧录!"

没有比对工具也可以人肉看:编译输出到烧录复制之间,看一眼 hex 文件的修改时间。它是"几分钟前"还是"昨天"?一目了然。

还有个铁律:编译和复制之间不插别的操作。先编译 → 立刻复制 → 烧录,一气呵成。中间哪怕去改了个宏、加了行注释,hex 都可能是旧的。

事后复盘:为什么排查了一下午?

回过头看,排查之所以浪费时间,是因为默认假设错了:

  1. 默认"烧的就是最新代码"—— 编译日志没问题,烧录输出没问题,自然怀疑代码逻辑。但这个假设恰恰不成立:增量编译 + 手动复制,中间任何一步都可能拿到旧产物。
  2. 没先做"版本自证"—— 设备有读版本号/读状态命令的话,烧完先读一发,功能对不对一目了然。我们这次设备有 cmd 19 读版本,但版本号没改,读出来一样,也没想到去对 hex 文件。

正确顺序应该是:功能不对 → 先自证烧的版本 → 再查代码。版本对了,才能信任"问题在代码里"。

总结

环节陷阱对策
增量编译源码没变就不重编,hex 是旧的烧录前对比 hex 与源码时间戳
手动复制复制了上次的旧 hex编译 → 复制 → 烧录,中间不插操作
烧后测试功能不对就查代码先自证烧录版本,再查代码

"编译通过"只证明编译成功,"时间戳对得上"才证明烧的是最新代码。烧录前 30 秒的比对,省下来的是几个小时的无头排查。


实测对比:改完源码直接复制hex烧录:新功能全失效,排查一下午 | 编译后先比对hex时间戳:一次看穿是旧产物

有用的话点个收藏,下次命令行编译烧录前,先对一眼 hex 时间戳。有问题欢迎评论区交流,看到了都会回。

http://www.jsqmd.com/news/1390019/

相关文章:

  • 无头模式(headless,无GUI)服务器上安装matlab_engine
  • 《扣子开发AI Agent智能体应用》配套的课件和视频下载
  • 为什么深圳实力网站建设能成为企业突围的核心竞争力?揭秘背后真相
  • 斯坦福CS 229机器学习速查手册:告别公式混乱,一套免费速查手册打通知识体系
  • Windows系统文件UIRibbonRes.dll丢失找不到问题解决
  • 全托管还是SaaS?企业GEO运营的成本效率对比指南
  • 吴树平《东观汉记校注》|修复残缺东汉国史,还原当朝文人原始记录
  • 我的研发任务
  • chatgpt-conversation开发者指南:核心组件与代码结构详解
  • Linux解压ZIP文件中文乱码:原理、解决方案与跨平台实践
  • Min浏览器使用全攻略:从首启到深度定制,一篇文章玩转极简隐私浏览器
  • 基于sample_aiisp再创建一路 h264编码流,和jpg的编码流
  • SDC命令详解:使用set_app_var命令进行设置
  • SAP内部订单修改KO02详解:核心功能、风险场景与最佳实践
  • Windows系统文件UIEApi.dll丢失找不到问题解决
  • karateclub,一个强大的 Python 库!
  • 采用v4l2loopback来实现 虚拟Camera
  • 微信防撤回工具 RevokeMsgPatcher 实测:3 步让你的重要消息不再被撤回
  • 建站公司都在推网站建设五合一,小白到底该怎么选?揭秘行业真相与避坑指南
  • 数学建模竞赛三年实战:从技术堆砌到问题本质的思维蜕变
  • 从数据驱动到机理建模:2025数学建模国赛B题解题策略与实战指南
  • 分布式 Geo 优化源码搭建思路与多节点部署数据同步技术方案
  • 【CVPR2026】给医学图像“相面”:视觉大模型驱动下的数据偶然不确定性深度解析
  • 数学建模竞赛B题深度攻略:从问题拆解到模型求解的实战解析
  • Windows系统错误0x80004005排查指南:COM组件、注册表与权限修复
  • Windows CMD下Curl命令全解析:从安装配置到高级应用实战
  • 为何选 Common Lisp 进行代码生成?这 8 大优势给出答案!
  • 洛雪音乐音源怎么配置?从免费无损音质到音源失效解决的一站式指南
  • es search包
  • 复杂自演化网络的测地线控制论:基于 4D 协变时空流形与自适应阻抗矩阵的内生安全范式