深入解析IntelHEX文件结构

 

目录

Intel HEX文件分析

1.扩展线性地址记录(设置高16位地址)

2.数据记录(地址范围:0x08000000-0x0800007F)

3.文件结束记录

Intel HEX文件分析

Intel HEX文件是一种文本格式,用于表示二进制数据,常用于嵌入式系统编程。每个HEX行(记录)的结构如下:

  • 起始字符:冒号(:)。

  • 字节计数(LL):1字节,表示数据字段的长度(十六进制)。

  • 地址(AAAA):2字节,表示数据在内存中的偏移地址(十六进制)。

  • 记录类型(TT):1字节,常见类型包括:

    • 00:数据记录。

    • 01:文件结束记录。

    • 04:扩展线性地址记录(设置高16位地址)。

  • 数据(DD):可变长度,实际数据内容(十六进制)。

  • 校验和(CC):1字节,用于验证记录完整性(计算方式:所有字节和取反加一)。

下面.hex文件由包含128字节数据的.bin文件转换生成,详细分析一下hex文件的内容:

.bin

88 E5 00 20 F5 C3 01 08  01 93 01 08 03 93 01 08  05 93 01 08 07 93 01 08  09 93 01 08 00 00 00 00 
00 00 00 00 00 00 00 00  00 00 00 00 E9 20 01 08  0B 93 01 08 00 00 00 00  91 20 01 08 E7 04 01 08 
45 C4 01 08 49 C4 01 08  4D C4 01 08 C3 93 01 08  51 C4 01 08 55 C4 01 08  59 C4 01 08 5D C4 01 08 
61 C4 01 08 65 C4 01 08  69 C4 01 08 97 93 01 08  6D C4 01 08 43 93 01 08  71 C4 01 08 75 C4 01 08 

.hex: 

:020000040800F2
:2000000088E50020F5C301080193010803930108059301080793010809930108000000006D
:20002000000000000000000000000000E92001080B9301080000000091200108E704010859
:2000400045C4010849C401084DC40108C393010851C4010855C4010859C401085DC401086F
:2000600061C4010865C4010869C40108979301086DC401084393010871C4010875C401081E
:00000001FF

1.扩展线性地址记录(设置高16位地址)

:020000040800F2
  • 格式:LLAAAATT[DD...]CC

  • 字段解析

    • 02:数据长度(2字节)

    • 0000:地址字段(固定0000)

    • 04:记录类型(04=扩展线性地址)

    • 0800:数据(高16位地址值)

    • F2:校验和(有效)

        解释:设置后续数据的高16位地址为 0x0800,实际基地址 = 0x0800 << 16 = 0x08000000(ARM Cortex-M典型Flash起始地址)

2.数据记录(地址范围:0x08000000-0x0800007F)

:20000000[32字节数据]6D
:20002000[32字节数据]59
:20004000[32字节数据]6F
:20006000[32字节数据]1E
  • 统一格式:20AAAA00[数据]CC

    • 20:固定数据长度(32字节)

    • AAAA:16位地址偏移(0000/0020/0040/0060)

    • 00:记录类型(00=数据记录)

    • [32字节数据]:实际二进制内容

    • CC:校验和(全部有效)

3.文件结束记录

:00000001FF

  • 格式:00 0000 01 FF

    • 00:数据长度=0

    • 0000:地址字段=0

    • 01:记录类型(01=文件结束)

    • FF:固定校验和

 bin to hex例程

        工作需要很多时候需要把bin文件转换为hex文件,所以实现了下面的例程,可通过VS生成可执行文件用于脚本增加效率。

#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <algorithm>

using namespace std;

// 计算校验和(包含长度、地址、类型、数据)
uint8_t calculate_checksum(uint8_t length, uint16_t address, uint8_t type, const vector<uint8_t>& data) {
    uint8_t checksum = length;
    checksum += (address >> 8) & 0xFF;
    checksum += address & 0xFF;
    checksum += type;
    for (uint8_t byte : data) {
        checksum += byte;
    }
    return (uint8_t)(~checksum + 1);
}

// 生成HEX记录字符串
string generate_hex_record(uint8_t type, uint16_t address, const vector<uint8_t>& data) {
    stringstream ss;
    ss << uppercase << hex
        << setw(2) << setfill('0') << static_cast<int>(data.size())
        << setw(4) << address
        << setw(2) << static_cast<int>(type);
    for (uint8_t byte : data) {
        ss << setw(2) << static_cast<int>(byte);
    }
    uint8_t checksum = calculate_checksum(data.size(), address, type, data);
    ss << setw(2) << static_cast<int>(checksum);
    return ":" + ss.str();
}

int main(int argc, char* argv[]) {
    if (argc != 4) {
        cerr << "Usage: " << argv[0] << " <input.bin> <output.hex> <32bit_start_address_hex>\n";
        return 1;
    }

    string input_file = argv[1];
    string output_file = argv[2];
    uint32_t start_address;
    istringstream iss(argv[3]);
    iss >> hex >> start_address;

    ifstream bin_file(input_file, ios::binary | ios::ate);
    if (!bin_file.is_open()) {
        cerr << "Error opening input file!\n";
        return 1;
    }

    streamsize size = bin_file.tellg();
    bin_file.seekg(0, ios::beg);

    vector<uint8_t> buffer(size);
    if (!bin_file.read(reinterpret_cast<char*>(buffer.data()), size)) {
        cerr << "Error reading input file!\n";
        return 1;
    }

    ofstream hex_file(output_file, ios::binary);
    if (!hex_file.is_open()) {
        cerr << "Error creating output file!\n";
        return 1;
    }

    const int bytes_per_line = 32; // 每行32字节
    uint32_t current_address = start_address;
    uint16_t current_high = (start_address >> 16) & 0xFFFF;

    // 初始扩展地址记录
    vector<uint8_t> ela_data = {
        static_cast<uint8_t>(current_high >> 8),
        static_cast<uint8_t>(current_high & 0xFF)
    };
    //hex_file << generate_hex_record(0x04, 0x0000, ela_data) << "\r\n";

    for (size_t i = 0; i < buffer.size();) {
        // 每过0x1FFF地址插入一次扩展地址记录
        uint16_t new_high = (current_address >> 16) & 0xFFFF;
        if (new_high != current_high || (current_address % 0x2000 == 0)) {
            current_high = new_high;
            ela_data = {
                static_cast<uint8_t>(current_high >> 8),
                static_cast<uint8_t>(current_high & 0xFF)
            };
            hex_file << generate_hex_record(0x04, 0x0000, ela_data) << "\r\n";
        }

        // 计算当前可写入的最大数据块(不超过0x1FFF边界)
        uint32_t next_boundary = ((current_address / 0x2000) + 1) * 0x2000;
        size_t max_chunk = min(
            static_cast<size_t>(bytes_per_line),
            static_cast<size_t>(next_boundary - current_address)
        );
        size_t chunk_size = min(max_chunk, buffer.size() - i);

        vector<uint8_t> chunk(buffer.begin() + i, buffer.begin() + i + chunk_size);
        uint16_t low_address = current_address & 0xFFFF;
        hex_file << generate_hex_record(0x00, low_address, chunk) << "\r\n";

        // 更新地址和索引
        current_address += chunk_size;
        i += chunk_size;
    }

    hex_file << ":00000001FF\r\n";
    cout << "Conversion completed. Extended address records every 0x2000 bytes.\n";
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值