一、BIN文件转换为C数组的方法
方法1:Python脚本转换(跨平台、推荐)
编写Python脚本将BIN文件转为C语言数组,操作简单且跨平台,适合任意BIN文件。
步骤1:创建bin2c.py脚本,内容如下:
import sys
def bin_to_c_array(bin_file_path, c_array_name, output_c_file):
# 读取BIN文件二进制数据
with open(bin_file_path, 'rb') as f:
bin_data = f.read()
# 写入C文件
with open(output_c_file, 'w', encoding='utf-8') as f:
# 写入头文件和数组注释
f.write('#include <stdint.h>\n\n')
f.write(f'// 自动生成:{bin_file_path} 转C数组\n')
f.write(f'// 数据长度:{len(bin_data)} 字节\n')
f.write(f'const uint8_t {c_array_name}[] = {{\n')
# 按每行16字节格式化输出,提升可读性
for i in range(0, len(bin_data), 16):
line_bytes = bin_data[i:i+16]
hex_str = ', '.join([f'0x{byte:02X}' for byte in line_bytes])
f.write(f' {hex_str}, // 偏移 0x{i:08X}\n')
f.write('};\n')
# 定义数组长度常量
f.write(f'const uint32_t {c_array_name}_len = sizeof({c_array_name});\n')
if __name__ == '__main__':
# 命令行参数检查
if len(sys.argv) != 4:
print("使用方法:")
print("python bin2c.py <输入BIN文件> <数组名> <输出C文件>")
print("示例:")
print("python bin2c.py Termite_Comm_test.bin upgrade_bin_data upgrade_bin_data.c")
sys.exit(1)
# 解析参数并执行转换
bin_file = sys.argv[1]
array_name = sys.argv[2]
output_file = sys.argv[3]
bin_to_c_array(bin_file, array_name, output_file)
print(f"转换完成!C数组文件:{output_file}")
步骤2:执行脚本转换BIN文件
- 将
Termite_Comm_test.bin和bin2c.py放在同一目录; - 打开命令行,执行以下命令(需安装Python 3.x):
python bin2c.py Termite_Comm_test.bin upgrade_bin_data upgrade_bin_data.c - 执行后生成
upgrade_bin_data.c,包含upgrade_bin_data(BIN数组)和upgrade_bin_data_len(数组长度)。
方法2:Keil fromelf工具(仅Keil环境)
若BIN文件由Keil编译的AXF/ELF生成,可直接用Keil自带的fromelf工具转换:
# 1. (可选)从AXF生成BIN文件(若已有BIN可跳过)
fromelf --bin -o Termite_Comm_test.bin Termite_Comm_test.axf
# 2. 从AXF直接生成C数组
fromelf --c_array -o upgrade_bin_data.c Termite_Comm_test.axf
注:
fromelf.exe路径通常为Keil_v5\ARM\ARMCC\bin\fromelf.exe,需配置环境变量或使用绝对路径。
二、写入BIN数组到指定Flash区域的C代码
结合现有flash.c/flash.h的Flash驱动API,编写代码将C数组写入0x0801F800(升级存储区起始地址)。
步骤1:集成C数组到项目
- 将生成的
upgrade_bin_data.c添加到项目工程; - 在调用写入函数的文件中声明数组(若数组在当前文件定义则无需
extern):#include <stdint.h> // 声明升级BIN数组和长度 extern const uint8_t upgrade_bin_data[]; extern const uint32_t upgrade_bin_data_len;
步骤2:编写Flash写入函数
#include "flash.h" // 现有Flash驱动头文件
#include "boot.h" // 包含blt_bool/blt_addr等类型
#include <stdint.h>
// 声明升级BIN数组(若在当前文件定义则删除extern)
extern const uint8_t upgrade_bin_data[];
extern const uint32_t upgrade_bin_data_len;
/**
* @brief 将升级BIN文件写入Flash升级存储区(0x0801F800起始)
* @retval BLT_TRUE: 写入成功, BLT_FALSE: 写入失败
*/
blt_bool WriteUpgradeBinToFlash(void)
{
blt_bool ret = BLT_TRUE;
// 升级存储区起始地址(扇区63)
const blt_addr upgrade_flash_start = 0x0801F800;
// BIN文件长度
const blt_int32u bin_total_len = upgrade_bin_data_len;
// 1. 擦除Flash区域(向上对齐到扇区大小2048字节)
blt_int32u erase_len = ((bin_total_len + FLASH_ERASE_SECTOR_SIZE - 1) / FLASH_ERASE_SECTOR_SIZE) * FLASH_ERASE_SECTOR_SIZE;
if (FlashErase(upgrade_flash_start, erase_len) == BLT_FALSE)
{
ret = BLT_FALSE;
goto exit; // 擦除失败
}
// 2. 写入BIN数据到Flash
if (FlashWrite(upgrade_flash_start, bin_total_len, (blt_int8u *)upgrade_bin_data) == BLT_FALSE)
{
ret = BLT_FALSE;
goto exit; // 写入失败
}
// 3. 完成Flash操作(刷入缓冲区剩余数据)
if (FlashDone() == BLT_FALSE)
{
ret = BLT_FALSE;
goto exit;
}
// 可选:验证写入数据(对比Flash和数组)
const uint8_t *flash_ptr = (const uint8_t *)upgrade_flash_start;
for (blt_int32u i = 0; i < bin_total_len; i++)
{
if (flash_ptr[i] != upgrade_bin_data[i])
{
ret = BLT_FALSE;
break;
}
}
exit:
return ret;
}
步骤3:调用写入函数
在需要触发升级的逻辑中调用WriteUpgradeBinToFlash():
/**
* @brief 触发应用升级(示例)
*/
void TriggerAppUpgrade(void)
{
blt_bool write_result = WriteUpgradeBinToFlash();
if (write_result == BLT_TRUE)
{
// 写入成功,可执行后续逻辑(如切换APP、重启MCU等)
// ...
printf("升级BIN写入Flash成功!\r\n");
}
else
{
// 写入失败,处理错误(如日志、告警)
// ...
printf("升级BIN写入Flash失败!\r\n");
}
}
三、关键注意事项
- Flash容量限制:升级存储区为55个扇区(110KB),需确保BIN文件大小≤110KB,否则会越界写入其他区域;
- 看门狗处理:现有
flash.c底层函数已调用CopService()喂狗,无需额外处理; - 权限与解锁:
FlashErase/FlashWrite已内置Flash解锁/上锁逻辑,无需手动操作; - 地址对齐:STM32L4 Flash写入按8字节(双字)对齐,现有驱动已处理,无需额外对齐;
- 编译器优化:若数组加
const后被编译器放到Flash,需确保读取时可正常访问(上述代码已兼容)。
四、验证写入结果
- 调试器验证:通过Keil Debugger查看
0x0801F800起始的Flash区域,对比BIN文件十六进制内容; - 代码验证:上述函数中已包含“Flash数据 vs 数组”的对比逻辑,可直接使用。

472

被折叠的 条评论
为什么被折叠?



