自动以版本号命名keil生成的bin文件

0、 前言

在做项目中一直遇到一个小问题。一直也没管,最近花了点时间处理了,效果还不错。问题是这样的:每次编译后的生成的bin文件需要给客户,烧录到设备里进行更新。每次生成的bin文件都是固定的文件名,发给客户前,需要人为将bin文件改为vx.x.x.bin再发送。这一步需要人工命名,虽然花不了几分钟,但是还是觉得体验不太好,因为如果一次编译的版本多的话,人容易命名出现纰漏。所以如果能生成bin文件后,自动进行重命名,那可靠性比人工高多了。

1、方案:

仔细想了下,以及跟同事交流后,主要有两种方案:
方案一,编写一个可执行文件,来读取keil项目中的.c .h文件,找到其中的版本号信息,然后自动将版本号信息填写到生成bin文件名称中。

方案二,将版本号信息,写入bin文件的固定地址。然后编写一个可执行文件,来读取bin文件固定地址的版本号信息。最后将读到的版本号信息,写入生成的bin文件名称中。

最优的方案是方案一,但是难度比较大,兼容性较差,不利于移植到其他项目,还没想好如何实现。方案二兼容性更强,不过需要修改项目文件,将版本信息写入bin文件的固定地址。实现更为简单。

本次是基于方案二的实现。

2、版本号写入bin文件固定地址

写入固定地址的方式其实很简单。只需要在main函数前面添加1行代码即可

uint16_t version_addr[3]  __attribute__((at(0x8010000))) = {MAIN_VERSION_MAJOR,MAIN_VERSION_MINOR,MAIN_VERSION_BUILD}; 

这句话的意思是将version_addr数组写入到固定地址为0x8050000,其内容是版本号,版本号每个字段占2个字节。为什么要用两个字节来表示,主要是考虑到兼容性,一个字节最多是255,假如有个版本号是1.2.300,那么每个字段用一字节表示,就无法满足需求。

0x8050000是stm32的flash地址,那么对应bin文件的偏移地址是多少呢?已知stm32 内部flash的首地址是0x8000000,0x10000是偏移地址,bin文件地址是从0开始,则bin文件的0x10000开始就是version_addr数据。
下面验证下。
当前的
MAIN_VERSION_MAJOR 4
MAIN_VERSION_MINOR 2
MAIN_VERSION_BUILD 50
在这里插入图片描述
bin文件的0x10000地址后面的数据是0x0004 0x0002 0x0035,35十进制是50。
接下来的可执行文件只需要读取到这个地址的数据,然后重命名bin文件即可。

3、重命名bin文件

对于重命名的可执行文件,需要知道2个信息。
其一:生成的bin文件的路径
其二:版本信息的偏移地址

对于版本号而言,最好加上前缀,可以是公司简称,设备简称。比如abc_v1.1.1.bin这种形式。

所以要实现比较完成的名称,还需要告知可执行文件,版本号的前缀。

这san个信息可以抽象成可执行文件的3个输入参数。

比如:version.exe aa/bb/cc/dd.bin 0x10000 abc_v

可执行文件实现原理见后文。这里先说下操作方式。在keil的项目options里面按照Run #2输入,实际上就是上文说的可执行的3个参数。
自动以版本号命名keil生成的bin文件_第1张图片
编译以后生成效果如下:

在这里插入图片描述
可以看到,确实生成了对应的版本号。

至此功能全部实现,bin_read.exe下载链接如下:
https://download.csdn.net/download/sinat_36568888/87621034

4、bin_read.exe源码

bin_read源码采用c编写,编译采用gcc编译器,源码如下:

#include 
#include 
#include 
#include 


/**
 * @description: 获取当前文件所在的路径
 * @return {*}
 * @Date: 2023-03-24 17:01:37
 * 比如aa/bb/cc/123.bin,则返回的路径是aa/bb/cc
 * 目的是为了后面修改新的文件名称
 */
int get_file_dir(char*filename, char*file_dir)
{
	int res = 0;
	char *file_name = strrchr(filename, '/');
	if(file_name != NULL)
	{
		int file_dir_len =strlen(filename)-strlen(file_name) ;
		printf("file dir len: %d\r\n", file_dir_len);
		memcpy(file_dir, filename, strlen(filename)-strlen(file_name));
		file_dir[file_dir_len] = '\0';
		printf("file dir:%s\r\n", file_dir);
		res = 0;
	}
	else
	{
		res = 1;
	}
	return res;

}
char file_dir[256] = {0};
char new_name[24] = {0};
char new_file_name[24] = {0};
int main(int argc, char **argv)
{
	int rename_res = 0;
	FILE *fp;
	uint16_t buf[10]={0};
	
	// printf("%s\r\n", argv[1]);
	
	fp = fopen(argv[1], "rb");
	if(fp == NULL)
	{
		printf("Error: file open failed\r\n");
		return 1;
	}
	uint32_t version_addr = strtol(argv[3],NULL,16);
	fseek(fp, version_addr, SEEK_SET);
	uint16_t len = fread(buf,2,3,fp);
	printf("len:%d data:",len);
	for(int i =0;i<len;i++)
	{
		printf("%02X ",buf[i]);
	}
	sprintf(new_name,"%s%d.%d.%d.bin",argv[2],buf[0],buf[1],buf[2]);
	printf("\r\n");
	fclose(fp);
	int ret = get_file_dir(argv[1],file_dir);
	if(ret ==0)//文件不在当前目录
	{
		sprintf(new_file_name,"%s/%s",file_dir,new_name);
	}
	else
	{
		sprintf(new_file_name,"%s",new_name);
	}
	remove(new_file_name);
	rename_res = rename(argv[1],new_file_name); //如果修改后的名称不加路径,rename函数就会把命名后的文件移动到当前的根目录
	printf("new name:%s\r\n",new_file_name);
	printf("res = %d\r\n",rename_res);
}

编译,win下打开powershell,在read_bin.c目录下,输入

 gcc bin_read.c -o bin_read.exe

想自己研究的,可以直接编译源码。不想研究的,下载可执行文件即可使用。

windows下配置gcc编译环境请参考:
https://blog.csdn.net/sinat_36568888/article/details/129091766

你可能感兴趣的:(STM32,stm32,嵌入式硬件,keil,bin,版本号)