在日常开发过程中,项目多的情况下,特别是提供测试部门,每次解决bug后都需要更新版本号,同时提供量产的版本号也是有区别。每次都需要手动修改特别繁琐,还容易搞乱,同时也会出现问题不好定位与追溯是哪个版本导致,在这种糟糕的情况,还是需要一个自动生成项目名的脚本工具,可以省很多繁琐,把时间留给解决项目需求与解决bug上面,废话有点多。好了,进入主题,在此,做个笔录,编写这个示例,方面后续查阅。
前提需要准备工作,需要window,bat开发语言基础,不会也没关系,边百度边学习。
通过批处理脚本(batch script)可用于自动化完成带版本号可执行文件(EXE)和Hex文件生成,如下为脚本实现的过程:
1、设置变量:
1)、CURRENT_SCRIPT_DIR:获取脚本当前目录。
2)、EXE_NAME:设置中的输出文件名。
3)、OBJ_PATH:设置中的输出文件路径。
4)、OUTPUT_PATH:输出文件路径(相对于脚本路径)。
5)、VERSION_FILE_PATH:包含版本字符串文件的路径。
6)、VERSION_PATTERN:在源文件中搜索软件版本号使用的标识符。
7)、FROMELF_PATH:fromelf工具(用于将.axf文件转换为.bin文件)的路径。
2、获取软件版本:
1)、使用findstr命令在VERSION_FILE_PATH指定的文件中搜索SOFTWARE_VERSION。
2)、提取找到的行的第三个标记(默认为空格分隔),并假设这是版本信息。然后,通过删除第一个和最后一个字符(可能是引号)来清理版本字符串。
3、输出指定文件名:
使用EXE_NAME和SW_Ver来构建Hex和Bin文件的输出文件名。
4、转换并定制Bin文件名:
使用fromelf.exe工具将.axf文件转换为.bin文件,并指定输出路径和文件名。
5、显示并复制Hex文件:
这里有一个潜在的问题:脚本试图复制一个Hex文件,但之前并没有生成或转换这个Hex文件。如果%OBJ_PATH%*.hex确实存在,那么复制操作会成功;否则,你会得到一个错误消息。
6、把bin文件打包成rar、7z格式
自动生成RAR、7z压缩文件
7、退出:
脚本执行完毕后退出。
1、硬件平台
STM32F401CEU6
内部Flash : 512Kbytes,SARM : 96 Kbytes

2.1、系统时钟配置

2.2、下载调试配置

2.3、生成代码


2.4、编译工程

1、Auto_Generation_Name.bat源码文件
@REM AUTHOR: champion
@REM VERSION: V1.0.0
@REM 获取脚本当前目录
set CURRENT_SCRIPT_DIR=%~dp0
set CURRENT_SCRIPT_DIR=%CURRENT_SCRIPT_DIR:~0,-1%
@REM 请根据实际情况修改以下变量,注意现在基于脚本当前路径进行设置
@REM KEIL 设置中的输出文件名
set EXEC_NAME=STM32F401CEU6_APP
@REM KEIL 设置中的输出文件路径(假设是相对于脚本路径)后面的也就是新建项目的名称
set OBJ_PATH=%CURRENT_SCRIPT_DIR%STM32F401CEU6_UART_Ringbuffer
@REM 输出文件路径(相对于脚本路径)
set OUTPUT_PATH=%CURRENT_SCRIPT_DIR%Output
@REM 包含版本字符串文件的路径(相对于脚本路径)
set VERSION_FILE_PATH=%CURRENT_SCRIPT_DIR%..CoreIncmain.h
@REM fromelf.exe 的路径(KEIL安装目录)
set FROMELF_PATH=C:Keil_v5ARMARMCCin
@REM 版本字符串的格式 (在源文件中搜索软件版本号使用的标识符)
set VERSION_PATTERN="#define SOFTWARE_VERSION"
@REM 获取日期【这里的日期格式为 YYYY-MM-HH hh:mm:ss,不同时区或配置下格式可能不同,请自行调整】
@REM 解决凌晨时出现空格问题 -> (set time0=%time: =0%)
set time0=%time: =0%
set YEAR=%DATE:~2,2%
set MONTH=%DATE:~5,2%
set DAY=%DATE:~8,2%
set HOUR=%time0:~0,2%
set MINUTE=%TIME:~3,2%
set SECOND=%TIME:~6,2%
@REM 保存格式精确到日月
@REM set CURRENT_DATE=%YEAR%%MONTH%%DAY%
@REM 保存格式精确到日月,时分秒
set CURRENT_DATE=%YEAR%%MONTH%%DAY%-%HOUR%%MINUTE%%SECOND%
@REM echo "Current date: %CURRENT_DATE%"
set output_file_name=%EXEC_NAME%
setlocal EnableDelayedExpansion
REM 将VERSION_FILE_PATH指定路径下的SOFTWARE_VERSION部分复制到临时文件temp.txt
findstr /C:"#define SOFTWARE_VERSION" "%VERSION_FILE_PATH%" > temp.txt
REM 从临时文件中提取版本号
for /F "tokens=3 delims== " %%i in (temp.txt) do (
set SW_Ver=%%i
echo Extracted software version: !SW_Ver!
)
REM 删除临时文件
del /Q temp.txt
@REM 如果没有output文件夹就创建新的文件夹
if not exist "%OUTPUT_PATH%" mkdir "%OUTPUT_PATH%"
echo "---- 1 Clean old files... ----"
REM 在此之后进行删除文件操作,包括rar文件
if exist "%OUTPUT_PATH%" (
for /f "delims=" %%A in ('dir /b "%OUTPUT_PATH%"') do (
echo Deleting file: %%A
del "%OUTPUT_PATH%\%%A"
)
)
echo "---- 2 Output file name... ----"
set output_file_name=%EXEC_NAME%_V_!SW_Ver!_%CURRENT_DATE%
@REM 转换并定制Bin文件名
echo "---- 3 Processing bin file... ----"
if not exist "%OBJ_PATH%*.axf" (
echo Error: Object file not found at "%OBJ_PATH%*.axf"
) else (
echo "Output bin file: %OUTPUT_PATH%\%output_file_name%.bin"
"%FROMELF_PATH%fromelf.exe" --bin "%OBJ_PATH%*.axf" --output "%OUTPUT_PATH%\%output_file_name%.bin"
if not exist "%OUTPUT_PATH%\%output_file_name%.bin" (
echo Error: Failed to generate bin file.
)
)
@REM 显示并拷贝Hex文件
if exist "%OBJ_PATH%*.hex" (
@REM echo.
echo "---- 4 Processing hex file... ----"
echo "Output hex file: %OUTPUT_PATH%\%output_file_name%.hex"
copy "%OBJ_PATH%*.hex" "%OUTPUT_PATH%\%output_file_name%.hex"
if not exist "%OUTPUT_PATH%\%output_file_name%.hex" (
echo Error: Failed to copy hex file.
)
) else (
echo ".hex file not found at: %OBJ_PATH%*.hex"
)
@REM 自动生成RAR、7z压缩文件
echo "---- 5 Generate rar ----"
@REM echo "Output bin file: %OUTPUT_PATH%\%output_file_name%.bin"
"C:Program FilesWinRARRar.exe" a -ep1 "%OUTPUT_PATH%\%output_file_name%.rar" "%OUTPUT_PATH%\%output_file_name%.bin"
@REM "C:Program Files7-Zip7z.exe" a -t7z "%OUTPUT_PATH%\%output_file_name%.7z" "%OUTPUT_PATH%\%output_file_name%.bin"
@REM if not exist "%OUTPUT_PATH%\%output_file_name%.bin" (
@REM echo Error: Failed to generate rar file.
@REM )
endlocal
exit
2、main.c文件
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "iwdg.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "task.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define HARDWARE_VERSION "1.1.2" /* 硬件版本 */
#define SOFTWARE_VERSION "1.0.3" /* 软件版本 */
#define ENABLE_SCT 0 //需要添加 .sct文件里面的内容才行。
/* 编译信息结构体 - 将存储在Flash中 */
typedef struct {
char company_name[25]; /* 公司名称 */
char compile_data[12]; /* 编译日期 "MMM DD YYYY" */
char compile_time[10]; /* 编译时间 "HH:MM:SS" */
char compiler_info[10]; /* 编译器信息 */
char hardware_version[10]; /* 硬件版本号 */
char software_version[10]; /* 软件版本号 */
char mcu_type[15]; /* MCU型号 */
char Cocyright_info[30]; /* 版权信息 */
} __attribute__((packed)) build_info_t;
//#define INFO_ADDR_BASE (0x8000000 + 0x80000 - 0x800) //最后的1k地址,起始地址: 0x8000000, 大小是: 0x80000(512k), 预留2k空间存储, 有个弊端就是固件空间占很大
#define INFO_ADDR_BASE (0x8000000 + 0x4000) //起始地址: 0x8000000, 偏移16k-(0x4000)地址用来存放, 通过map得知,改个合理的地址专门存放该信息即可
/* 编译信息实例 - 使用特定段存储 */
//const build_info_t firmware_build_info __attribute__((section(".build_info"), used)) = {
#if ENABLE_SCT
const build_info_t firmware_build_info __attribute__((section(".build_info"))) = { //要在.sct文件中修改,才能使用
#else
const build_info_t firmware_build_info __attribute__((at(INFO_ADDR_BASE + 0x00))) = {
#endif
"深圳xx科技有限公司",
__DATE__,
__TIME__,
#ifdef __ICCARM__
"IAR-ARM", /* IAR编译器*/
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
"KEIL-MDK", /* keil编译器 */
#else
"Unknown",
#endif
HARDWARE_VERSION, /* 硬件版本 */
SOFTWARE_VERSION, /* 软件版本 */
"STM32F401CEUx", /* MCU型号 */
"Cocyright (c) 2025 champion", /* 版权信息 */
};
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM1_Init();
MX_IWDG_Init();
MX_USART6_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim1);
HAL_UART_Receive_IT_Enable();
printf("heihei min task
");
printf("companyName: %s
", firmware_build_info.company_name);
printf("buildData: %s
", firmware_build_info.compile_data);
printf("buildTime: %s
", firmware_build_info.compile_time);
printf("buildInfo: %s
", firmware_build_info.compiler_info);
printf("hardwareVersion: %s
", firmware_build_info.hardware_version);
printf("softwareVersion: %s
", firmware_build_info.software_version);
printf("mcuType: %s
", firmware_build_info.mcu_type);
printf("CocyrightInfo: %s
", firmware_build_info.Cocyright_info);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
task_process();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d
", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
3、main.h文件
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#ifndef SOFTWARE_VERSION
#define SOFTWARE_VERSION "1.0.3"
#endif
/* USER CODE END Includes */
1、新创建的.bat文件存放路径

2、在工具栏中->找到魔术棒点击,进入下图

3、选中.bat脚本文件

4、编译工程


1、安装压缩软件
下面提示,电脑没有安装rar或者7z软件,安装WinRAR或者7z,重新编译即可。

2、使用rar压缩方式
需修改bat脚本代码,如下所示

没有安装压缩软件,下图报错原因

2、安装压缩软件好后,再编译结果如下


3、使用7z压缩方式
需修改bat脚本代码,如下所示



好了,介绍完毕,希望能帮助到需要的人,一起加油 ^_^!。
参考文章:1、https://blog.csdn.net/qq_41841073/article/details/83274807?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-83274807-blog-5556307.235^v43^pc_blog_bottom_relevance_base2&spm=1001.2101.3001.4242.1&utm_relevant_index=3
2、https://blog.csdn.net/luoqjcandy/article/details/139809325
3、https://blog.csdn.net/u014428915/article/details/135948715?spm=1001.2014.3001.5506
代码