将bin文件转换成C语言数组,然后写入flash指定位置

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

一、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文件

  1. Termite_Comm_test.binbin2c.py放在同一目录;
  2. 打开命令行,执行以下命令(需安装Python 3.x):
    python bin2c.py Termite_Comm_test.bin upgrade_bin_data upgrade_bin_data.c
    
  3. 执行后生成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数组到项目
  1. 将生成的upgrade_bin_data.c添加到项目工程;
  2. 在调用写入函数的文件中声明数组(若数组在当前文件定义则无需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");
    }
}

三、关键注意事项

  1. Flash容量限制:升级存储区为55个扇区(110KB),需确保BIN文件大小≤110KB,否则会越界写入其他区域;
  2. 看门狗处理:现有flash.c底层函数已调用CopService()喂狗,无需额外处理;
  3. 权限与解锁FlashErase/FlashWrite已内置Flash解锁/上锁逻辑,无需手动操作;
  4. 地址对齐:STM32L4 Flash写入按8字节(双字)对齐,现有驱动已处理,无需额外对齐;
  5. 编译器优化:若数组加const后被编译器放到Flash,需确保读取时可正常访问(上述代码已兼容)。

四、验证写入结果

  1. 调试器验证:通过Keil Debugger查看0x0801F800起始的Flash区域,对比BIN文件十六进制内容;
  2. 代码验证:上述函数中已包含“Flash数据 vs 数组”的对比逻辑,可直接使用。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值