首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

嵌入式開發:C 語言實作 Bin 檔轉 Hex 檔 (Intel HEX 格式)

     編輯:關於C語言

格式差異速查

特性Bin (Binary)Hex (Intel HEX)
內容純二進位機器碼ASCII 文字記錄
位址資訊無 (需外部指定偏移)每記錄含載入位址
檢驗和無每行有 Checksum
適用場景大量生產燒錄、固件升級開發除錯、通用燒錄器

Intel HEX 記錄結構

:LLAAAATTDD...DDCC
│ │  │  └─ Data (0~255 bytes)
│ │  └──── Record Type (00=Data, 01=EOF, 02=Ext Segment, 04=Ext Linear)
│ └────── Address (16-bit, big-endian)
└──────── Length (byte count)

Checksum = 兩位元組補數:0x100 - (LL + AA_H + AA_L + TT + ΣDD) & 0xFF

核心編碼函數

#include <stdint.h>
#include <stdio.h>
#include <string.h>

typedef struct {
    uint8_t len;
    uint8_t addr_hi, addr_lo;
    uint8_t type;
    const uint8_t *data;
} HexRecord;

// 將一筆記錄編碼為 HEX 字串,回傳寫入長度
int encode_hex_record(char *out, const HexRecord *rec) {
    int pos = 0;
    uint8_t sum = rec->len + rec->addr_hi + rec->addr_lo + rec->type;

    pos += sprintf(out, ":%02X%02X%02X%02X", rec->len, rec->addr_hi, rec->addr_lo, rec->type);

    for (uint8_t i = 0; i < rec->len; ++i) {
        pos += sprintf(out + pos, "%02X", rec->data[i]);
        sum += rec->data[i];
    }
    uint8_t checksum = (uint8_t)(-sum); // 兩位元組補數
    pos += sprintf(out + pos, "%02X", checksum);
    out[pos++] = '\n';
    return pos;
}

完整 Bin → Hex 轉換程式

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define LINE_MAX_BYTES 16  // 每行 16 位元組 (可調 16/32/64)

int bin2hex(const char *bin_path, const char *hex_path) {
    FILE *fbin = fopen(bin_path, "rb");
    if (!fbin) { perror("open bin"); return -1; }
    FILE *fhex = fopen(hex_path, "w");
    if (!fhex) { perror("open hex"); fclose(fbin); return -1; }

    fseek(fbin, 0, SEEK_END);
    long fsize = ftell(fbin);
    fseek(fbin, 0, SEEK_SET);

    uint8_t buf[LINE_MAX_BYTES];
    uint32_t addr = 0;          // 線性位址
    uint32_t last_high16 = 0xFFFFFFFF;

    while (addr < fsize) {
        uint32_t high16 = (addr >> 16) & 0xFFFF;
        if (high16 != last_high16) { // 需發出 Extended Linear Address Record (Type 04)
            HexRecord er = {2, 0, 0, 0x04, (uint8_t[]){high16 >> 8, high16 & 0xFF}};
            char line[64];
            encode_hex_record(line, &er);
            fputs(line, fhex);
            last_high16 = high16;
        }

        size_t chunk = (fsize - addr >= LINE_MAX_BYTES) ? LINE_MAX_BYTES : (fsize - addr);
        fread(buf, 1, chunk, fbin);

        HexRecord dr = {
            (uint8_t)chunk,
            (uint8_t)((addr >> 8) & 0xFF), // 高 8 位
            (uint8_t)(addr & 0xFF),        // 低 8 位
            0x00,                          // Data Record
            buf
        };
        char line[80];
        encode_hex_record(line, &dr);
        fputs(line, fhex);

        addr += chunk;
    }

    // EOF Record
    fputs(":00000001FF\n", fhex);

    fclose(fbin);
    fclose(fhex);
    return 0;
}

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s  \n", argv[0]);
        return 1;
    }
    return bin2hex(argv[1], argv[2]);
}

使用範例

$ gcc bin2hex.c -o bin2hex
$ ./bin2hex firmware.bin firmware.hex
$ head -5 firmware.hex
:1000000000112233445566778899AABBCCDDEEFF00
:10001000112233445566778899AABBCCDDEEFF0010
:0400000400010000FB
:10000000FFEEDDCCBBAA99887766554433221100EF
:00000001FF

關鍵實作細節

  • 每行位元組數:16/32/64 均可,16 相容性最好
  • 擴展線性位址 (Type 04):每 64KB 切換一次,確保 32 位元位址空間完整覆蓋
  • Checksum 計算:所有欄位 (含長度、位址、類型、資料) 相加取反加一
  • 大端序:位址、資料皆以 Big-Endian 輸出
  • EOF 記錄:固定 :00000001FF

常見坑點

  1. 忘記處理 >64KB 檔案的擴展位址記錄
  2. 位址拆分高低位順序錯誤 (Intel HEX 是 Big-Endian)
  3. Checksum 計算溢位未取模 256
  4. 輸出行尾缺少換行符
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved