做过单片机开发的朋友应该对hex和bin文件都比较眼熟了,但你是否真正理解这两种文件的区别和联系吗?今天我想总结一下,做个备忘。水平所限,如有疏漏,欢迎指正。
简单来说,我们的源代码经过单片机编译器编译后,会输出只有CPU能识别的二进制机器码,这也就是bin文件里面的内容。bin文件需要烧写到Flash(Rom)里才能运行。那这些二进制数据应该怎么烧写以及烧写到Flash里的哪块区域呢?这就需要hex文件登场了。所以,也可以这样说,hex文件是bin文件的详细描述,里面添加了二进制数据在Flash中的对应区域地址等信息。
首先要明确一点,bin文件是二进制(也可以说是16进制)文件,但是hex文件可是文本文件(ASSICII格式),并且内容是以行为单位组织的。每两个字符表示16进制的值,比如,bin中的一个字节数据0xFF,在hex文件中表示为字符串“FF”,占两个字节,所以hex文件比bin文件要大很多。下面重点说一下hex文件的格式,不同编译器输出的hex文件可能会稍微有点不同,但基本格式都是一样的,它包含这几部分:
Head + Len + Offset + Type + Data + Checksum
-
Head
占1个字符,固定为冒号“:”。 -
Len
占2个字符,其转化成16机制数的值代表Data域的字节数长度。 -
Offset
占4个字符,代表地址偏移数。 -
Type
占2个字符,用来表示本行内容的类别,它有6种取值:- “00”:数据记录,用来记录bin文件中的数据,Hex文件的大部分内容都是数据记录
- “01”:文件结束记录,用来标识文件结束,放在文件的最后,标识Hex文件的结尾
- “02”:扩展段地址记录,用来标识扩展段地址的记录
- “03”:开始段地址记录,开始段地址记录
- “04”:扩展线性地址记录,用来标识扩展线性地址的记录
- “05”:开始线性地址记录,开始线性地址记录
-
Data
占Len*2个字符,代表bin文件中的数据。 -
Checksum
占2个字符,代表本行数据的检验码,计算方法为:检验和 = 0xFF & (0x100 - 冒号之后的各字节数据的累加和)。
单纯用文字讲清楚hex的每部分的含义比较抽象,尤其是Type的分类,不好描述,咱就举例子说明吧,这样最简单明了。针对6种Type,每1类1个例子,对照结构来分析:
-
: 10 01F0 00 C0E0C0D075D000C000C007309904C299 DB
Type为“00”,所以这一行为数据记录;长度为0x10(即16),可以数一下Data段确实为16个字节;检验码为DB,按照计算公式算出来也没毛病;Offset为0x01F0,如果本行前面没有扩展段地址记录或扩展线性地址记录,则表示Data域的数据烧写到Flash的地址0x01F0处,如果前面有这两类记录,其意义下面再说。 -
: 00 0000 01 FF
Type为“01”,表示这是hex文件结尾,在最后一行。 -
: 02 0010 02 0010 24
Type为“02”,所以这一行为扩展段地址记录,扩展段地址为0x0010,它表示该行以后的数据记录烧写地址为:0x0010 x 0x0F + Offset。如果1中的那行数据之前有这个扩展段地址记录,那么1中的数据烧写地址变为:0x0010 x 0x0F + 0x01F0 = 0x02E0。 -
: 04 0000 03 00003800 C1
Type为“03”,表示该行为开始段地址记录,这一类很少见,我在我的hex文件中没找到,写一个网上的例子,它指定程序起始执行地址,对于80x86处理器,可指定CS:IP寄存器的初始内容,Offset字段是0x0000,Len始终为4,Data的前两个字节代表CS寄存器的值,后两个字节代表IP值。 -
: 02 0000 04 0800 F2
Type为“04”,表示该行为扩展线性地址记录。因为Offset只有两个字节,表示的地址范围有线,所以对于空间比较大的情况,可以用“04”指定扩展地址,表示地址的高位,这样地址就可以用4个字节表示了。本例中指定的地址高位为0x0800,如果1中的那行数据之前有这个扩展线性地址记录,那么1中的数据烧写地址变为:0x0800 << 0x0F + 0x01F0 = 0x080002E0。 -
: 04 0000 05 08000189 65
Type为“05”,表示该行为开始线性地址记录,一般表示程序的入口地址,比如该例子中的地址为0x08000189,可以在Map文件中找到。
说到底,其实烧写工具就是根据hex文件的描述,get到程序数据和地址,然后逐个烧写到Flash中对应的区域。好了,先写这么多。
网友评论