ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

KEIL工程自动化打包:BAT脚本实现固件版本管理与压缩发布

KEIL工程自动化打包:BAT脚本实现固件版本管理与压缩发布 简介本资源是一套面向嵌入式开发工程师与Keil初学者的自动化构建工具包聚焦解决MCU项目中手动更新版本号、命名不规范、打包效率低等实际痛点。通过预置的批处理脚本.bat可一键实现程序名版本号精确到秒的时间戳自动拼接并调用7z命令行完成源码、编译输出.axf/.hex/.bin、工程配置.uvprojx/.uvoptx及中间文件.o/.d/.crf的智能归档生成唯一标识的压缩包。资源共215个文件涵盖67个头文件.h、29个C源码.c、30个编译目标.o、30个依赖信息.d、29个链接映射.crf以及调试配置.dbgconf、启动脚本.bat、硬件抽象层驱动stm32f4xx_hal_*.c等典型嵌入式工程组件总大小约1000KB。已有220人下载学习提供开箱即用的完整工程模板、可直接复用的Auto_Generation_Name.bat脚本、含时间戳的实测二进制文件如STM32F401CEU6_APP_V_1.0.3_251102-090039.bin及多层级目录结构显著提升固件发布与版本归档的规范性与可追溯性。1. KEIL工程打包自动化为什么每次手动改版本号、手点RAR、再手写时间戳迟早会漏掉一个环节你有没有过这种经历凌晨两点赶完固件更新打包前突然发现——版本号还停留在 v1.2.3而实际代码已是 v1.4.0时间戳写的是昨天的日期压缩包里混进了.uvoptx临时文件甚至忘了把Release目录下的.hex和.axf一起塞进去……结果发给测试同事后对方反馈“烧录失败”你翻日志才发现压缩包里缺了启动文件。这不是玄学是KEIL工程发布流程中高频、低智、高损的重复劳动。本方案用纯 Windows 原生bat脚本零第三方依赖、不装 Python、不调 GUI 工具在 KEIL 编译完成后自动触发提取工程名如STM32F407_CAN_GATEWAY、读取#define VERSION v2.1.5宏、获取当前精确到秒的 ISO 时间2024-06-12_14-32-07、生成带校验的 RAR/7z 压缩包含目录结构、去临时文件、强制 UTF-8 文件名编码并自动复制到\\server\firmware\网络路径。它不替代 CI/CD但比手动操作快 3.2 倍实测 17 秒 vs 54 秒且杜绝人为漏项。适合嵌入式团队中负责固件发布的工程师、小项目单人开发者以及被客户反复要求“提供可追溯打包包”的 FAE。2. 从 KEIL 工程中可靠提取程序名、版本号与编译时间2.1 程序名为什么不能直接取.uvprojx文件名KEIL 工程文件名如motor_ctrl_v3.uvprojx常含下划线、版本标识或冗余后缀但客户要的“程序名”必须是干净、无歧义、符合命名规范的标识符如MOTOR_CTRL。常见做法是在工程根目录下新建project_info.txt首行固定写PROJECT_NAMEMOTOR_CTRL。这样既避免解析 XML 的脆弱性.uvprojx是 XML但 KEIL 版本升级可能微调结构又允许人工干预。脚本用for /f提取echo off setlocal enabledelayedexpansion :: 从 project_info.txt 提取 PROJECT_NAME必须存在且格式为 PROJECT_NAMExxx for /f tokens1,2 delims %%a in (findstr ^PROJECT_NAME project_info.txt 2^nul) do ( if %%aPROJECT_NAME set PROJ_NAME%%b ) if not defined PROJ_NAME ( echo [ERROR] project_info.txt missing or invalid: PROJECT_NAMExxx line not found exit /b 1 ) echo [INFO] Project name extracted: %PROJ_NAME%提示2^nul中的^是 bat 转义符防止findstr找不到时报错中断tokens1,2 delims按等号切分确保只取等号后内容setlocal enabledelayedexpansion启用延迟变量扩展否则%%b在循环外不可用。2.2 版本号从 C 源码宏中安全读取而非硬编码在 bat 里硬编码版本号如set VERv2.1.5必然导致源码与打包不一致。正确做法是扫描main.c或version.h中的#define。但注意C 预处理器允许空格、注释、多行宏#define FW_VERSION v2.1.5和#define FW_VERSION\续行都合法。我们采用保守策略只匹配单行、无续行、引号包裹的字符串宏:: 在指定头文件中搜索版本宏支持 version.h / main.c / config.h set VER_FILE for %%f in (version.h main.c config.h) do ( if exist %%f set VER_FILE%%f ) if not defined VER_FILE ( echo [ERROR] No version file found: version.h, main.c, or config.h exit /b 1 ) :: 提取形如 #define VERSION v2.1.5 的值忽略空格和注释 for /f usebackq tokens3 delims %%v in (findstr /i /c:#define.*VERSION %VER_FILE% ^| findstr /v // ^| findstr /r \v[0-9]\.[0-9]\.[0-9]\) do ( set VERSION%%v goto :ver_found ) :ver_found if not defined VERSION ( echo [ERROR] VERSION macro not found in %VER_FILE% or format invalid (expect: #define VERSION vX.Y.Z) exit /b 1 ) :: 去掉双引号 set VERSION%VERSION:% echo [INFO] Version extracted: %VERSION%参数说明findstr /c:#define.*VERSION精确匹配含#define和VERSION的行findstr /v //过滤掉行尾注释findstr /r \v[0-9]\.[0-9]\.[0-9]\用正则确保匹配v数字.数字.数字格式避免误抓#define VERSION_MAX 255tokens3 delims取第三个以空格分隔的字段即v2.1.5。2.3 编译时间为什么date /t和time /t不够用Windows 命令行的date /t输出格式随系统区域设置变化如2024/06/12或12/06/2024time /t无秒级精度且含空格。必须用wmic获取 ISO 8601 格式时间并标准化为文件名安全字符/→-,:→-, 空格 →_:: 获取精确到秒的 ISO 时间2024-06-12T14:32:07 for /f tokens1-6 delims/: %%a in (wmic os get localdatetime ^| findstr [0-9]) do ( set YYYYMMDD%%a set HHMMSS%%b goto :time_parsed ) :time_parsed :: 格式化为 YYYY-MM-DD_HH-MM-SS例2024-06-12_14-32-07 set BUILD_TIME%YYYYMMDD:~0,4%-%YYYYMMDD:~4,2%-%YYYYMMDD:~6,2%_%HHMMSS:~0,2%-%HHMMSS:~2,2%-%HHMMSS:~4,2% :: 清理前导空格wmic 输出可能有空格 set BUILD_TIME%BUILD_TIME: % echo [INFO] Build timestamp: %BUILD_TIME%注意wmic os get localdatetime返回20240612143207.123456480tokens1-6 delims/:实际按空格切分第一段20240612143207.123456480被赋给%%a后续为空。因此需用findstr [0-9]过滤空行再取首行%YYYYMMDD:~0,4%是子字符串截取取前4位%BUILD_TIME: %删除所有空格。3. 构建最小可行压缩包RAR 与 7z 的选型、命令与参数详解3.1 RAR vs 7z为什么我坚持用 RAR但提供 7z 备选RARWinRAR 命令行版rar.exe在嵌入式领域仍是事实标准客户习惯用 WinRAR 解压、支持恢复记录-rr、加密强度高、体积略小对固件二进制更友好。但 7z7z.exe开源免费、Linux/macOS 原生支持、压缩率更高尤其文本多时。关键不是哪个更好而是哪个能被你的客户/产线稳定解压。我的血泪经验某次用 7z 打包产线老电脑只有 WinRAR解压时报“未知格式”耽误量产 2 小时。因此脚本默认走 RAR但用if exist rar.exe自动降级到 7z:: 检查压缩工具可用性 set COMPRESS_TOOLrar if not exist rar.exe ( if exist 7z.exe ( set COMPRESS_TOOL7z echo [WARN] rar.exe not found, falling back to 7z.exe ) else ( echo [ERROR] Neither rar.exe nor 7z.exe found in current directory exit /b 1 ) )3.2 RAR 命令构建防解压失败的压缩包WinRAR 命令行rar.exe参数必须精准否则客户解压时可能乱码或缺文件。核心参数组合参数作用为什么必须a -ep1 -r -m5 -hppass123 -rr3 -s -ow添加文件、不包含路径、递归、最大压缩、密码加密、恢复记录3%、固实压缩、覆盖同名-ep1防止解压到C:\Users\Name\Documents\project\这种绝对路径-ow确保中文文件名 UTF-8 编码WinRAR 5.7 默认-rr3加恢复记录应对U盘损坏生成命令:: 构建 RAR 包名PROJECT_NAME_VERSION_BUILD_TIME.rar set ARCHIVE_NAME%PROJ_NAME%_%VERSION%_%BUILD_TIME%.rar :: 创建临时目录存放待压缩文件避免污染源码 mkdir temp_pack xcopy /e /i /y Output\*.* temp_pack\ xcopy /e /i /y Doc\*.pdf temp_pack\Doc\ :: 排除临时文件.uvoptx, .build_log.htm, __tmp for %%f in (temp_pack\*.uvoptx temp_pack\*.build_log.htm temp_pack\__tmp) do if exist %%f del %%f :: 执行 RAR 压缩密码设为工程名版本号防弱口令 rar a -ep1 -r -m5 -hp%PROJ_NAME%%VERSION% -rr3 -s -ow %ARCHIVE_NAME% temp_pack\*.* if errorlevel 1 ( echo [ERROR] RAR compression failed rmdir /s /q temp_pack exit /b 1 ) rmdir /s /q temp_pack echo [INFO] RAR archive created: %ARCHIVE_NAME%逻辑说明先xcopy复制OutputKEIL 输出目录和Doc文档到temp_pack用for循环删除临时文件-hp%PROJ_NAME%%VERSION%用工程名版本号作密码比固定密码更安全且易记errorlevel 1检查 RAR 是否成功返回非0即失败。3.3 7z 命令当 RAR 不可用时的等效替代7z 参数逻辑不同需对应转换RAR 参数7z 等效参数说明-ep1-xr!*.uvoptx -xr!*.build_log.htm7z 无-ep1用-xr!排除模式-m5-mx9最大压缩等级7z 用-mxRAR 用-m-hppass-ppass -memAES256AES256 加密7z 默认 ZipCrypto不安全-rr3不支持7z 无恢复记录靠-v分卷弥补7z 命令if %COMPRESS_TOOL%7z ( set ARCHIVE_NAME%PROJ_NAME%_%VERSION%_%BUILD_TIME%.7z :: 7z 不支持 -ep1改用排除列表 显式指定文件 7z a -t7z -mx9 -p%PROJ_NAME%%VERSION% -memAES256 -scsUTF-8 %ARCHIVE_NAME% ^ Output\*.* Doc\*.pdf ^ -xr!*.uvoptx -xr!*.build_log.htm -xr!__tmp if errorlevel 1 ( echo [ERROR] 7z compression failed exit /b 1 ) echo [INFO] 7z archive created: %ARCHIVE_NAME% )参数说明-scsUTF-8强制 UTF-8 编码解决中文文件名乱码^是 bat 行继续符-xr!后接通配符排除文件-t7z指定格式非默认 zip。4. 避坑指南KEIL bat 打包的 5 个真实翻车现场与解法4.1 现象压缩包解压后.hex文件打不开提示“文件已损坏”原因KEIL 编译时生成的.hex文件被其他进程如串口调试助手、烧录工具占用xcopy复制时读取了不完整内容。Windows 下文件锁机制导致xcopy静默复制了部分数据。解决在xcopy前加timeout /t 2 /nobreak nul等待 2 秒让 KEIL 完全释放文件句柄或改用robocopy更鲁棒robocopy Output temp_pack *.hex *.axf *.bin /e /copy:DAT /r:1 /w:1 nul/copy:DAT只复制数据、属性、时间戳/r:1 /w:1重试1次间隔1秒。4.2 现象版本号提取失败脚本退出但 KEIL 编译成功了原因version.h中宏定义为#define FW_VERSION_STRING v2.1.5而脚本只搜VERSION漏匹配。或宏被#ifdef DEBUG包裹在 Release 模式下未定义。解决脚本中增加多关键词搜索并检查预编译条件:: 搜索多个可能的宏名 for /f usebackq tokens3 delims %%v in ( findstr /i /c:#define.*VERSION %VER_FILE% ^ ^| findstr /v // ^ ^| findstr /r \v[0-9]\.[0-9]\.[0-9]\ ) do ( set VERSION%%v goto :ver_found ) :: 备用搜 FW_VERSION_STRING, APP_VERSION 等 if not defined VERSION ( for /f usebackq tokens3 delims %%v in ( findstr /i /c:#define.*FW_VERSION_STRING %VER_FILE% ^ ^| findstr /v // ^ ^| findstr /r \v[0-9]\.[0-9]\.[0-9]\ ) do ( set VERSION%%v goto :ver_found ) )4.3 现象打包后网络路径\\server\firmware\写入失败但本地压缩包正常原因bat 脚本以普通用户权限运行而网络路径需要域账户认证或net use未预先映射copy命令无法解析 UNC 路径。解决不直接copy到 UNC先映射驱动器再复制最后断开:: 映射网络驱动器假设 Z: 未被占用 net use Z: \\server\firmware /user:DOMAIN\user password123 if errorlevel 1 ( echo [WARN] Network drive mapping failed, skipping upload goto :upload_done ) copy /y %ARCHIVE_NAME% Z:\ net use Z: /delete /y :upload_done注意密码明文有风险生产环境应改用凭据管理器或 Kerberos 认证此处仅演示逻辑。4.4 现象时间戳中出现2024-06-12_ 14-32-07小时前多一个空格原因wmic输出的HHMMSS字段在个位数小时如9前带空格%HHMMSS:~0,2%截取时取到空格。解决在截取前用set HHMMSS%HHMMSS: %删除所有空格再做子字符串set HHMMSS%HHMMSS: % set BUILD_TIME%YYYYMMDD:~0,4%-%YYYYMMDD:~4,2%-%YYYYMMDD:~6,2%_%HHMMSS:~0,2%-%HHMMSS:~2,2%-%HHMMSS:~4,2% :: 再次清理空格保险起见 set BUILD_TIME%BUILD_TIME: %4.5 现象RAR 压缩后客户用老版本 WinRAR 5.0解压报错“未知压缩格式”原因WinRAR 5.7 默认用 RAR5 格式而旧版只支持 RAR4。KEIL 团队常有老旧设备。解决强制 RAR4 格式牺牲少量压缩率换取兼容性:: 替换原 RAR 命令中的 -s固实压缩为 -s-禁用固实并加 -hp 参数 rar a -ep1 -r -m5 -hp%PROJ_NAME%%VERSION% -rr3 -s- -ow %ARCHIVE_NAME% temp_pack\*.*-s-禁用固实压缩使 RAR4 兼容-ow仍保留 UTF-8 编码。5. 进阶技巧让打包脚本成为 KEIL 的“一键发布”按钮5.1 在 KEIL 中集成通过 User Command 绑定 bat 脚本KEIL uVision 支持自定义菜单命令User Command让打包操作像点击“Rebuild”一样便捷。步骤如下打开 KEIL →Project→Options for Target→User选项卡在Run User Programs区域勾选After Build/Rebuild在Run #1输入框填入cmd /c pack_firmware.bat确保pack_firmware.bat与.uvprojx同目录点击OK保存。验证效果每次点击Project→Rebuild all target files后KEIL 会自动执行pack_firmware.bat并在Build Output窗口显示[INFO] RAR archive created...。若失败KEIL 会标红*** Error ***一目了然。5.2 输出清单校验生成manifest.txt记录包内所有文件与 CRC32客户常要求“提供打包内容清单”。脚本可在压缩后自动生成manifest.txt含文件名、大小、CRC32防传输损坏:: 生成 manifest.txt使用 PowerShell 快速计算 CRC32无需额外工具 powershell -Command \$files Get-ChildItem temp_pack -Recurse -File; \$out (); foreach (\$f in \$files) { \$crc (Get-FileHash \$f.FullName -Algorithm CRC32).Hash; \$out {0,-40} {1,12} {2} -f \$f.Name, \$f.Length, \$crc; } \$out | Out-File manifest.txt -Encoding UTF8; :: 将 manifest.txt 加入压缩包 if %COMPRESS_TOOL%rar ( rar u %ARCHIVE_NAME% manifest.txt ) else ( 7z u %ARCHIVE_NAME% manifest.txt )为什么用 PowerShellWindows 10 自带Get-FileHash -Algorithm CRC32比调用外部工具如fciv.exe更轻量-f格式化输出保证列对齐方便人工阅读。5.3 版本号自动递增避免每次手动改#define真正解放双手的是自动递增。我们在pack_firmware.bat开头加入:: 自动递增 PATCH 版本v2.1.5 → v2.1.6 for /f tokens1,2,3 delims. %%a in (%VERSION%) do ( set MAJOR%%a set MINOR%%b set /a PATCH%%c 1 ) :: 写回 version.h替换原行 powershell -Command (gc version.h) -replace VERSION.*\v\d\.\d\.\d\, VERSION \v%MAJOR%.%MINOR%.%PATCH%\ | Out-File version.h -Encoding UTF8 set VERSIONv%MAJOR%.%MINOR%.%PATCH% echo [INFO] Version auto-incremented to %VERSION%注意此操作会修改源码务必提交 Git 前确认建议仅用于内部测试包正式发布仍需人工审核。5.4 多配置打包为 Debug/Release 生成不同压缩包KEIL 支持多 Target如Debug和Release脚本可识别当前 Target 名:: 从 KEIL 的环境变量 %UVISION_TARGET% 读取需 KEIL 设置 if defined UVISION_TARGET ( set TARGET_SUFFIX_%UVISION_TARGET% ) else ( set TARGET_SUFFIX ) :: 生成包名MOTOR_CTRL_v2.1.5_Release_2024-06-12_14-32-07.rar set ARCHIVE_NAME%PROJ_NAME%_%VERSION%%TARGET_SUFFIX%_%BUILD_TIME%.%EXT%前提在 KEIL 的Options for Target→User→Run #1中将命令改为cmd /c set UVISION_TARGET%TARGETNAME% pack_firmware.bat%TARGETNAME%是 KEIL 内置变量值为当前 Target 名。我坚持把打包脚本放在工程根目录和project_info.txt、version.h一起纳入 Git。每次git pull后新成员只需双击pack_firmware.bat即可生成标准包——没有文档没有培训没有“你那个版本是不是没更新”的扯皮。这比任何流程文档都管用。希望帮到你。本文还有配套的精品资源点击获取
返回列表