Intel HEX文件格式是一种用于表示二进制数据的ASCII文本格式,广泛应用于嵌入式系统的固件存储和传输。
1. Intel HEX文件格式简介
Intel HEX文件格式是一种将二进制数据转换为ASCII文本的格式,适用于8位、16位和32位微处理器。它的主要优点是可以将二进制数据存储在非二进制介质(如纸带、穿孔卡片)上,并且可以通过CRT终端或行式打印机显示。
- ASCII表示:每个字节的二进制值被转换为两个ASCII字符。例如,二进制值
00111111
(十六进制3F
)被表示为ASCII字符'3'
和'F'
。 - 记录结构:HEX文件由多个记录组成,每个记录包含记录类型、长度、地址、数据和校验和。
2. HEX文件记录格式
每个HEX记录由以下字段组成:
字段名 | 长度 | 描述 |
---|---|---|
RECORD MARK | 1字节 | 记录起始标志,固定为ASCII字符':' (十六进制03AH )。 |
RECLEN | 1字节 | 数据字段的长度(以字节为单位),最大值为FF (255)。 |
LOAD OFFSET | 2字节 | 数据加载的起始偏移地址,仅用于数据记录。 |
RECTYP | 1字节 | 记录类型,用于解释记录的内容。 |
INFO/DATA | 可变长度 | 数据字段,包含实际的数据字节。 |
CHKSUM | 1字节 | 校验和,用于验证记录的有效性。 |
3. 记录类型
Intel HEX文件定义了六种记录类型:
-
数据记录(
00
):- 包含实际的数据字节。
- 用于将数据加载到内存中。
-
文件结束记录(
01
):- 表示HEX文件的结束。
- 必须出现在文件的最后。
-
扩展段地址记录(
02
):- 用于16位或32位格式,定义段基地址的高16位。
- 影响后续数据记录的地址计算。
-
起始段地址记录(
03
):- 用于16位或32位格式,定义代码的起始执行地址(CS和IP寄存器)。
-
扩展线性地址记录(
04
):- 仅用于32位格式,定义线性基地址的高16位。
- 影响后续数据记录的地址计算。
-
起始线性地址记录(
05
):- 仅用于32位格式,定义代码的起始执行地址(EIP寄存器)。
4. 地址计算
-
线性地址(32位格式):
- 绝对地址 = 线性基地址(LBA) + 数据记录的偏移地址(DRLO) + 数据字节索引(DRI)。
- 线性基地址由扩展线性地址记录定义。
-
段地址(16位格式):
- 绝对地址 = 段基地址(SBA) + (数据记录的偏移地址(DRLO) + 数据字节索引(DRI)) MOD 64K。
- 段基地址由扩展段地址记录定义。
地址计算示例
在Intel HEX文件中,地址计算可以分为线性地址和段地址两种格式。以下是几个示例,帮助读者理解如何计算绝对地址。
示例1:线性地址(32位格式)
假设我们有以下Intel HEX文件记录:
:020000040001F9
:10000000112233445566778899AABBCCDDEEFF00F0
-
扩展线性地址记录:
:020000040001F9
- 字节数:02(2字节)
- 地址:0000
- 记录类型:04(扩展线性地址记录)
- 数据:0001(线性基地址)
- 校验和:F9
线性基地址(LBA) = 0x0001 << 16 = 0x00010000
-
数据记录:
:10000000112233445566778899AABBCCDDEEFF00F0
- 字节数:10(16字节)
- 地址:0000
- 记录类型:00(数据记录)
- 数据:112233445566778899AABBCCDDEEFF00
- 校验和:F0
绝对地址计算:
- 数据字节索引(DRI) = 0, 1, 2, …, 15
- 绝对地址 = 线性基地址(LBA) + 数据记录的偏移地址(DRLO) + 数据字节索引(DRI)
- 绝对地址 = 0x00010000 + 0x0000 + DRI
具体地址和数据:
0x00010000: 11 0x00010001: 22 0x00010002: 33 0x00010003: 44 0x00010004: 55 0x00010005: 66 0x00010006: 77 0x00010007: 88 0x00010008: 99 0x00010009: AA 0x0001000A: BB 0x0001000B: CC 0x0001000C: DD 0x0001000D: EE 0x0001000E: FF 0x0001000F: 00
示例2:段地址(16位格式)
假设我们有以下Intel HEX文件记录:
:020000021000EC
:10000000112233445566778899AABBCCDDEEFF00F0
-
扩展段地址记录:
:020000021000EC
- 字节数:02(2字节)
- 地址:0000
- 记录类型:02(扩展段地址记录)
- 数据:1000(段基地址)
- 校验和:EC
段基地址(SBA) = 0x1000 << 4 = 0x10000
-
数据记录:
:10000000112233445566778899AABBCCDDEEFF00F0
- 字节数:10(16字节)
- 地址:0000
- 记录类型:00(数据记录)
- 数据:112233445566778899AABBCCDDEEFF00
- 校验和:F0
绝对地址计算:
- 数据字节索引(DRI) = 0, 1, 2, …, 15
- 绝对地址 = 段基地址(SBA) + (数据记录的偏移地址(DRLO) + 数据字节索引(DRI)) MOD 64K
- 绝对地址 = 0x10000 + (0x0000 + DRI) MOD 64K
具体地址和数据:
0x10000: 11 0x10001: 22 0x10002: 33 0x10003: 44 0x10004: 55 0x10005: 66 0x10006: 77 0x10007: 88 0x10008: 99 0x10009: AA 0x1000A: BB 0x1000B: CC 0x1000C: DD 0x1000D: EE 0x1000E: FF 0x1000F: 00
通过上述示例,我们可以看到如何计算Intel HEX文件中线性地址和段地址的绝对地址。希望这些示例能够帮助读者更好地理解Intel HEX文件的地址计算方法。
5. 校验和计算
每个记录的校验和是记录中所有字节(从RECLEN
到INFO/DATA
字段)的二进制和的补码。校验和的计算公式如下:
校验和 = 0xFF - (所有字节的和 MOD 0xFF)
校验和字段的值应使得整个记录的所有字节(包括校验和)的和为0
。
6. 示例解析
以下是一个简单的HEX文件示例:
:10010000214601360121470136007EFE09D2190140
:00000001FF
-
第一条记录:
RECORD MARK
::
。RECLEN
:10
(16字节)。LOAD OFFSET
:0100
。RECTYP
:00
(数据记录)。DATA
:214601360121470136007EFE09D21901
。CHKSUM
:40
。
-
第二条记录:
RECORD MARK
::
。RECLEN
:00
。LOAD OFFSET
:0000
。RECTYP
:01
(文件结束记录)。CHKSUM
:FF
。
Intel HEX文件的用途
Intel HEX文件广泛应用于嵌入式系统开发中,主要用于以下几个方面:
- 程序代码加载:将编译后的程序代码存储在Intel HEX文件中,通过编程器或其他工具将代码加载到微控制器或嵌入式设备中。
- 配置数据存储:将设备的配置数据存储在Intel HEX文件中,方便设备初始化和配置。
- 固件升级:通过Intel HEX文件进行固件升级,将新版本的固件加载到设备中。
生成和解析Intel HEX文件
生成Intel HEX文件
在嵌入式系统开发中,编译器通常会提供生成Intel HEX文件的选项。例如,使用GCC编译器可以通过以下命令生成Intel HEX文件:
avr-gcc -mmcu=atmega328p -o main.elf main.c
avr-objcopy -O ihex main.elf main.hex
解析Intel HEX文件
解析Intel HEX文件可以使用多种编程语言实现,以下是一个使用Python解析Intel HEX文件的示例:
def parse_hex_line(line):
if line[0] != ':':
raise ValueError("Invalid start code")
byte_count = int(line[1:3], 16)
address = int(line[3:7], 16)
record_type = int(line[7:9], 16)
data = line[9:9 + byte_count * 2]
checksum = int(line[9 + byte_count * 2:11 + byte_count * 2], 16)
return byte_count, address, record_type, data, checksum
def verify_checksum(line):
total = 0
for i in range(1, len(line) - 2, 2):
total += int(line[i:i + 2], 16)
total = (total & 0xFF) ^ 0xFF
return total == int(line[-2:], 16)
def parse_hex_file(file_path):
with open(file_path, 'r') as file:
for line in file:
line = line.strip()
if not verify_checksum(line):
raise ValueError("Checksum error")
byte_count, address, record_type, data, checksum = parse_hex_line(line)
print(f"Byte Count: {byte_count}, Address: {address:04X}, Record Type: {record_type}, Data: {data}, Checksum: {checksum:02X}")
# 示例使用
parse_hex_file('example.hex')
通过上述代码,我们可以解析Intel HEX文件的每一行记录,并验证校验和的正确性。
总结
Intel HEX文件是一种常见的文件格式,用于存储和传输二进制数据。它广泛应用于嵌入式系统开发中,用于程序代码加载、配置数据存储和固件升级等场景。本文详细讲解了Intel HEX文件的结构和用途,并结合实例深入分析了如何生成和解析Intel HEX文件。希望本文的讲解和实例分析能够帮助读者深入理解Intel HEX文件格式,并在实际开发中灵活运用。
参考
- Intel Hexadecimal Object File Format Specification(本文翻译自该文档)。
- 相关嵌入式系统开发文档和工具手册。
希望本文能帮助你更好地理解Intel HEX文件格式!如果你有任何问题或建议,欢迎在评论区留言。
公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top