HEX 文件是一种 ASCII 文本格式,常用于存储 微控制器或EPROM 的机器码。 它以十六进制形式表示二进制数据,常见扩展名为:.hex / .ihx

基本格式

每一行(称为一条“记录 record”)的通用格式为:

:llaaaatt[dd…]cc

字段长度(字节)说明
:1每行的起始标志
ll1数据字节数(该行数据的长度)
aaaa2起始地址(偏移地址)
tt1记录类型
dd...ll实际数据内容
cc1校验和

记录类型(tt)

类型值含义
00数据记录(最常见)
01文件结束记录(EOF)
02扩展段地址记录(16位段地址)
04扩展线性地址记录(高16位地址,用于32位地址)
05启动地址记录(执行起始地址)

校验和计算规则

校验和(checksum)用于验证每行数据的正确性。

计算方法:

Sum = (ll + aaaa高字节 + aaaa低字节 + tt + 所有数据字节)
取低8位
Checksum = (0x100 - Sum) & 0xFF

验证时: 每行所有字节(包括校验和)之和的低8位应为 0。

示例解析

示例行:

:10010000214601360121470136007EFE09D2190140

逐项解析:

部分含义
:起始符
10数据长度 = 16字节
0100起始地址 = 0x0100
00记录类型 = 数据记录
214601360121470136007EFE09D21901数据内容(16字节)
40校验和

验证校验和:

Sum = 0x10 + 0x01 + 0x00 + 0x00 + (16个数据字节)
Sum = 0xC0
Checksum = (0x100 - 0xC0) & 0xFF = 0x40 ✅

文件结束行示例

:00000001FF

  • 长度 = 0

  • 地址 = 0000

  • 类型 = 01 (文件结束)

  • 校验和 = FF

扩展地址记录示例

扩展线性地址记录(用于 32 位地址)

:020000040001F9

  • 长度 = 2

  • 地址 = 0000

  • 类型 = 04

  • 数据 = 0001(高 16 位)

  • 校验和 = F9

  • → 之后的数据记录地址应加上 (0x0001 « 16) = 0x00010000

python 解析脚本

  1
  2# :llaaaatt[dd...]cc
  3
  4# :	1	每行的起始标志
  5# ll	1	数据字节数(该行数据的长度)
  6# aaaa	2	起始地址(偏移地址)
  7# tt	1	记录类型
  8# dd...	ll	实际数据内容
  9# cc	1	校验和
 10
 11# 00	数据记录(最常见)
 12# 01	文件结束记录(EOF)
 13# 02	扩展段地址记录(16位段地址)
 14# 04	扩展线性地址记录(高16位地址,用于32位地址)
 15# 05	启动地址记录(执行起始地址)
 16
 17import sys
 18import io
 19
 20# 强制设置 stdout 编码为 UTF-8
 21sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
 22
 23def parse_hex_fragments(hex_file_path):
 24    """
 25    解析HEX文件,返回所有独立数据块及起始地址,严格保留地址不连续性。
 26    
 27    返回值:
 28        - data_blocks: 列表,每个元素为字典,包含 'address' 和 'data'
 29        - start_address: 首个数据块的地址(若文件无数据,返回None)
 30    """
 31    with open(hex_file_path, 'r') as f:
 32        lines = f.readlines()
 33    
 34    data_blocks = []          # 存储所有数据块 [{address: int, data: bytes}, ...]
 35    upper_address = 0x0000    # 扩展线性地址(类型04)
 36    current_segment = 0x0000  # 扩展段地址(类型02)
 37    start_address = None
 38    
 39    for line in lines:
 40        line = line.strip()
 41        if not line.startswith(':'):
 42            continue
 43        
 44        # 解析字段
 45        byte_count = int(line[1:3], 16) # 1-2
 46        address = int(line[3:7], 16)
 47        record_type = int(line[7:9], 16)
 48        data_bytes = bytes.fromhex(line[9:-2])
 49        checksum = int(line[-2:], 16)
 50        
 51        # 校验和验证
 52        computed_sum = sum(bytes.fromhex(line[1:-2])) & 0xFF # Sum = (ll + aaaa高字节 + aaaa低字节 + tt + 所有数据字节)
 53        computed_checksum = (0x100 - computed_sum) & 0xFF # Checksum = (0x100 - Sum) & 0xFF
 54        if checksum != computed_checksum:
 55            raise ValueError(f"校验和错误: {line}")
 56        
 57        # 处理记录类型
 58        if record_type == 0x00:  # 数据记录
 59            # 计算完整地址(支持段地址和线性地址)
 60            if upper_address != 0x0000:
 61                full_address = (upper_address << 16) + address
 62            else:
 63                full_address = (current_segment << 4) + address
 64            
 65            # 记录数据块(即使地址不连续也独立存储)
 66            data_blocks.append({
 67                'address': full_address,
 68                'data': data_bytes
 69            })
 70            
 71            # 更新起始地址(仅首个数据块)
 72            if start_address is None:
 73                start_address = full_address
 74        
 75        elif record_type == 0x02:  # 扩展段地址
 76            current_segment = int.from_bytes(data_bytes, byteorder='big')
 77        
 78        elif record_type == 0x04:  # 扩展线性地址
 79            upper_address = int.from_bytes(data_bytes, byteorder='big')
 80        
 81        # 05 启动地址记录(执行起始地址)
 82        elif record_type == 0x01:  # 文件结束
 83            break
 84    
 85    return data_blocks, start_address
 86
 87if __name__ == '__main__':
 88    # 示例用法
 89    filename=r'AppDemo.hex'
 90    data_blocks, start_addr = parse_hex_fragments(filename)
 91
 92    # 打印输出
 93    if start_addr is not None:
 94        print(f"文件起始地址: 0x{start_addr:08X}")
 95        for idx, block in enumerate(data_blocks):
 96            print(f"数据块 {idx + 1}:")
 97            print(f"  起始地址: 0x{block['address']:08X}")
 98            print(f"  数据长度: {len(block['data'])} 字节")
 99            print(f"  数据内容: {block['data'].hex().upper()}")
100    else:
101        print("HEX文件中未找到有效数据记录!")