KEIL自动生成:程序名字+版本号+时间戳+打包RAR/7z文件 (使用bat脚本-详解)

  • 时间:2025-11-07 14:47 作者: 来源: 阅读:0
  • 扫一扫,手机访问
摘要:概述         在日常开发过程中,项目多的情况下,特别是提供测试部门,每次解决bug后都需要更新版本号,同时提供量产的版本号也是有区别。每次都需要手动修改特别繁琐,还容易搞乱,同时也会出现问题不好定位与追溯是哪个版本导致,在这种糟糕的情况,还是需要一个自动生成项目名的脚本工具,可以省很多繁琐,把时间留给解决项目需求与解决bug上面,废话有点多。好了,

概述

        在日常开发过程中,项目多的情况下,特别是提供测试部门,每次解决bug后都需要更新版本号,同时提供量产的版本号也是有区别。每次都需要手动修改特别繁琐,还容易搞乱,同时也会出现问题不好定位与追溯是哪个版本导致,在这种糟糕的情况,还是需要一个自动生成项目名的脚本工具,可以省很多繁琐,把时间留给解决项目需求与解决bug上面,废话有点多。好了,进入主题,在此,做个笔录,编写这个示例,方面后续查阅。

前提需要准备工作,需要window,bat开发语言基础,不会也没关系,边百度边学习。

一、自动生成版本号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

二、STM32CubeMx配置

 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 */

四、keil配置事项

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

代码

 

 

 

  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部