这是一个非常经典的问题,也是嵌入式开发初学者经常会困惑的地方。简单来说,HEX文件和BIN文件都是机器代码的载体,但它们的"包装"不同,因此用途和适用场景也不同。
下面我们来详细拆解一下它们的区别以及为什么MCU会使用不同的格式。
核心区别:一句话概括
- BIN文件 :是纯二进制数据,是MCU可执行代码的"裸数据",没有任何修饰。它是什么,MCU就执行什么。
- HEX文件 :是带有地址信息的文本文件,可以看作是BIN文件+地址信息+校验和的"包装版"。
深入解析两种格式
1. BIN 文件
- 格式:纯粹的二进制序列。文件内容就是MCU Flash内存中从起始地址开始,按顺序排列的机器码。
- 优点 :
- 最原始:没有冗余信息,文件体积最小。
- 直接可执行:烧录器只需将其原封不动地写入Flash的连续地址即可。
- 通用性强:任何需要处理原始二进制数据的场景都可以使用。
- 缺点 :
- 缺乏地址信息:它本身不包含"我应该被放在Flash的哪个位置"的信息。这个起始地址通常需要由烧录器或用户额外指定。如果程序在Flash中不是从0x0000开始连续存放的(比如有中断向量表在0x08000000,而代码在另一个区域),单一的BIN文件就无法完整描述。
- 无校验:文件传输或读取过程中如果出现错误,无法自我检查。
2. HEX 文件
- 格式 :一种ASCII文本格式,遵循Intel HEX规范。每一行都是一条"记录",包含特定信息。
- 一条典型的HEX记录:
:10010000214601360121470136007EFE09D2190140 :起始符10本行数据长度(16字节)0100本行数据的起始地址(偏移)00记录类型(00=数据,01=文件结束,...)214601360121470136007EFE09D21901真正的数据40校验和
- 一条典型的HEX记录:
- 优点 :
- 自带地址信息:可以描述不连续的数据块。例如,它可以轻松地说"把接下来的数据写到0x08000000地址",然后又说"把另一段数据写到0x08002000地址"。这对于程序存储在非连续内存区域(如Bootloader和App分区)非常有用。
- 自带校验和:每行都有校验和,确保数据传输的准确性。
- 易于阅读和调试:因为是文本格式,人类可以(勉强)阅读,有时可以通过看HEX文件的开头地址来推断一些信息。
- 缺点 :
- 体积大:由于是文本格式,并且包含额外信息,文件体积通常比同程序的BIN文件大。
- 需要解析:烧录器需要先解析这个文本文件,提取出数据和地址,才能执行烧录。
为什么有的MCU用HEX,有的用BIN?
这主要取决于芯片的启动流程、内存布局以及开发工具链的偏好。
倾向于使用 HEX 文件的情况:
-
复杂的内存映射:
- 最典型的例子是ARM Cortex-M系列 的MCU。它们的Flash起始地址通常是
0x08000000,而中断向量表必须放在这个起始位置。但用户的程序代码可能从稍后的地址开始。编译器生成的代码可能不是单一连续块。HEX文件能完美地描述这种"把数据A放在地址X,把数据B放在地址Y"的需求。 - 如果使用BIN文件,你需要确切地知道起始地址,并且程序在Flash中必须是完全连续的。对于有Bootloader的系统,应用程序的BIN文件起始地址就不是0x08000000,而是0x0800C000之类的,这个地址必须明确告知烧录器。
- 最典型的例子是ARM Cortex-M系列 的MCU。它们的Flash起始地址通常是
-
开发和生产的不同阶段:
- 开发阶段:工程师更倾向于使用HEX文件。因为编译器(如ARM GCC, IAR, Keil)默认输出的就是HEX(或类似格式如ELF)。调试时,HEX文件包含的地址信息与源码映射更清晰。
- 量产阶段:当程序固件最终确定,并且烧录地址固定后,为了追求效率和减小文件体积,可能会转换为BIN文件用于批量生产烧录。
-
烧录器/工具的支持:
- 很多通用的烧录器软件(如J-Flash, ST-Link Utility)都完美支持HEX格式,因为它们需要处理灵活的内存地址。
倾向于使用 BIN 文件的情况:
-
简单的、固定地址的MCU:
- 一些简单的8位MCU(如某些51单片机、PIC、AVR),它们的程序存储空间从0开始,并且程序是连续存放的。对于它们来说,一个从0地址开始的BIN文件就足够了,烧录器直接从头开始写即可,非常简单直接。
-
Bootloader 升级:
- 在通过MCU内部的Bootloader进行OTA(空中升级)或串口升级时,传输的固件通常是BIN格式。因为Bootloader程序本身已经知道应用程序应该被写入的起始地址(例如
0x08004000),它只需要接收纯粹的二进制数据流并写入这个固定地址即可。使用BIN可以节省带宽和存储空间。
- 在通过MCU内部的Bootloader进行OTA(空中升级)或串口升级时,传输的固件通常是BIN格式。因为Bootloader程序本身已经知道应用程序应该被写入的起始地址(例如
-
批量生产:
- 在生产线上,烧录的固件版本是固定的,烧录地址也是固定的。使用体积更小的BIN文件可以加快从电脑传输到烧录器的速度,并节省存储空间。
-
嵌入式系统内核:
- 比如引导Linux内核时,U-Boot通常是从存储设备(如eMMC, SD卡)中加载一个
uImage或zImage文件,这本质上就是一个加了头信息的BIN文件,或者直接就是BIN文件。
- 比如引导Linux内核时,U-Boot通常是从存储设备(如eMMC, SD卡)中加载一个
总结对比表
| 特性 | HEX 文件 | BIN 文件 |
|---|---|---|
| 格式 | ASCII 文本 | 纯二进制 |
| 地址信息 | 内置在文件中 | 需要外部指定 |
| 数据连续性 | 支持不连续的数据块 | 必须是连续的数据块 |
| 文件大小 | 较大(有冗余信息) | 较小(纯数据) |
| 可读性 | 可用文本编辑器查看 | 不可读(乱码) |
| 错误校验 | 每行有校验和 | 无 |
| 典型应用 | 开发调试、复杂内存布局的MCU | 量产烧录、Bootloader升级、简单MCU |
结论:
选择HEX还是BIN,并非由MCU本身绝对决定,而是由**"工具链 + 内存布局 + 应用场景"**共同决定的。
- 如果你的程序很简单,内存映射是线性的,或者用于二次传输(如Bootloader),BIN是更高效的选择。
- 如果你的程序结构复杂,内存地址不连续,或者处于开发调试阶段,HEX文件提供了更大的灵活性和可靠性。
在现代ARM Cortex-M开发中,你经常会同时看到这两种文件,HEX用于开发和备份,BIN用于量产和OTA。