2024年1月1日发(作者:)
Intel HEX文件是记录文本行的ASCII文本文件,在Intel HEX文件中,每一行是一个HEX记录,由十六进制数组成的机器码或者数据常量。Intel HEX文件经常被用于将程序或数据传输存储到ROM、EPROM,大多数编程器和模拟器使用Intel HEX文件。
很多编译器的支持生成HEX格式的烧录文件,尤其是Keil c。但是编程器能够下载的往往是BIN格式,因此HEX转BIN是每个编程器都必须支持的功能。
HEX格式文件以行为单位,每行由“:”(0x3a)开始,以回车键结束(0x0d,0x0a)。行内的数据都是由两个字符表示一个16进制字节,比如”01”就表示数0x01;”0a”,就表示0x0a。对于16位的地址,则高位在前低位在后,比如地址0x010a,在HEX格式文件中就表示为字符串”010a”。下面为HEX文件中的一行:
:10000000FF0462FF051EFF0A93FF0572FF0A93FFBC
“:”表示一行的开始。
“:”后的第1,2个字符“10”表示本行包含的数据的长度,这里就是0x10即16个。
第3,4,5,6个字符“0000”表示数据存储的起始地址,这里表示从0x0000地址开始存储16个数据,其中高位地址在前,低位地址在后。
第7,8个字符“00”表示数据的类型。该类型总共有以下几种:
00 ----数据记录
01 ----文件结束记录
02 ----扩展段地址记录
04 ----扩展线性地址记录
这里就是0x00即为普通数据记录。
自后的32个字符就是本行包含的数据,每两个字符表示一个字节数据,总共有16个字节数据跟行首的记录的长度相一致。
最后两个字符表示校验码。
每个HEX格式的最后一行都是固定为:
:00000001FF
以上的信息其实就足够进行HEX转BIN格式的程序的编写。首先我们只处理数据类型为0x00及0x01的情况。0x02表示对应的存储地址超过了64K,由于我的编程器只针对64K以下的单片机,因此在次不处理,0x04也是如此。
我的编程思路是从文件中一个一个读出字符,根据“:”判断一行的开始,然后每两个字符转换成一个字节,并解释其对应的意义。然后将数据从该行中剥离出来保存到缓冲区中,并最终输出到文件中。
具体程序如下,该程序在VC2005下采用控制台项目编译,需要在release下编译,在debug模式中会提示一个dll文件无法找到,这可能是VC自身的错误。
// : 定义控制台应用程序的入口点。
//
#i nclude "stdafx.h"
#i nclude
#i nclude
typedef unsigned char BYTE;
//将两个字符转化为一个字节量
void CharToByte(char* pChar,BYTE* pByte)
{
char h,l;
h=pChar[0];//高位
l=pChar[1];//低位
if(l>='0'&&l<='9')
l=l-'0';
else if(l>='a' && l<='f')
l=l-'a'+0xa;
else if(l>='A' && l<='F')
l=l-'A'+0xa;
if(h>='0'&&h<='9')
h=h-'0';
else if(h>='a' && h<='f')
h=h-'a'+0xa;
else if(h>='A' &&h <='F')
h=h-'A'+0xa;
*pByte=(BYTE)h*16+l;
}
int _tmain(int argc, _TCHAR* argv[])
{
char fileName[100];
char data[2];
BYTE *outBuf;
FILE *myFile;
int len;
int i;
BYTE adressHigh;
BYTE adressLow;
BYTE dataLen;
BYTE dataType;
BYTE byteData;
int totalLen;
totalLen = 0;
len = 0;
adressHigh = 0;
adressLow = 0;
dataLen = 0;
dataType = 0;
printf("请输入HEX格式文件名:");
scanf_s("%s",fileName);
printf("n");
if (fopen_s(&myFile,fileName,"r") != 0)
{
printf("打开文件%s失败!",fileName);
}
//将文件长度计算出来用于申请存储数据的缓冲区
while (!feof(myFile))
{
++len;
fgetc(myFile);
}
rewind(myFile);
//因为是每两个字符表示一个字节,所以最大的数据个数要少于文件字符个数的一半
outBuf = (BYTE*)malloc(len/2);
memset(outBuf,0xff,len/2);
while (!feof(myFile))
{
//:号表示一行的开始
if (fgetc(myFile) == ':')
{
//一行的头两个字符表示该行包含的数据长度
data[0] = fgetc(myFile);
data[1] = fgetc(myFile);
CharToByte(data,&dataLen);
//一行的第、个字符表示数据存储起始地址的高位
data[0] = fgetc(myFile);
data[1] = fgetc(myFile);
CharToByte(data,&adressHigh);
//一行的第、个字符表示数据存储起始地址的低位
data[0] = fgetc(myFile);
data[1] = fgetc(myFile);
CharToByte(data,&adressLow);
//一行的第、个字符表示数据类型
data[0] = fgetc(myFile);
data[1] = fgetc(myFile);
CharToByte(data,&dataType);
//当数据类型为时,表示本行包含的是普通数据记录
if (dataType == 0x00)
{
for (i=0;i { data[0] = fgetc(myFile); data[1] = fgetc(myFile); CharToByte(data,&byteData); outBuf[adressHigh*256+adressLow+i] = byteData; } totalLen += dataLen; } //当数据类型为时,表示到了最后一行 if (dataType == 0x01) { printf("文件结束记录!"); } //当数据类型为时,表示本行包含的是扩展段地址记录 if (dataType == 0x02) { printf("不支持扩展段地址记录!"); return 0; } //当数据类型为时,表示本行包含的是扩展线性地址记录 if (dataType == 0x04) { printf("不支持扩展线性地址记录!"); return 0; } } } fclose(myFile); printf("请输入保存的BIN格式文件名:"); scanf_s("%s",fileName); if (fopen_s(&myFile,fileName,"w") != 0) { printf("打开文件%s失败!",fileName); } for (i=0;i { fputc(outBuf[i],myFile); } return 0; } HEX文件以行为单位。每行以字符 ‘:’ (0x3a)开头,以回车换行符0x0d, 0x0a为结束。每行开始和结束之间的所有内容,都是以字符形式表现的。例如数据如果是 0x1A ,那么转换到HEX格式的行里面就是0x31 0x41。如果数据是16bit的,例如地址,则先显示高位,后显示底位。例如 0x1234,转换成HEX格式文件后变成 0x31 0x32 0x33 0x34,显示出来以后就是1234。将数据部分内容每2个字符看做一个字节得HEX数据,例如: :FA , 我把它看做 0x02 0x00 0x00 0x04 0x00 0x00 0xFA 第一个 0x02 为数据长度。 紧跟着后面的0x00 0x00 为地址。 再后面的0x04为数据类型,类型共分以下几类: '00' Data Record '01' End of File Record '02' Extended Segment Address Record '03' Start Segment Address Record '04' Extended Linear Address Record '05' Start Linear Address Record 然后,接着0x04后面的两个 0x00 0x00就是数据。最后一个0xFA是校验码。 HEX文件的每一行都是这样的格式: <0x3a> [数据长度1Byte] [数据地址2Byte] [数据类型1Byte] [数据nByte] [校验1Byte] <0x0d> <0x0a> 在例如: :1000000018F09FE518F09FE518F09FE518F09FE5C0 按照上面的数据行格式分析如下: <0x3a> [数据长度1Byte] [数据地址2Byte] [数据类型1Byte] 10 00 00 00 [数据nByte] [校验1Byte] <0x0d> <0x0a> 18F09FE518F09FE518F09FE518F09FE5 C0 每行中的数据并不是一定有的,第二个字节数据长度为0,那么这行就没有数据。 由于每行标识数据地址的只有2Byte,所以最大只能到64K,为了可以保存高地址的数据,就有了Extended Linear Address Record。如果这行的数据类型是0x04,那么,这行的数据就是随后数据的基地址。例如: :F6 :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE5805F20B9F0FF1FE518F09FE51D 第一行,是Extended Linear Address Record,里面的数据,也就是基地址是0x0004,第二行是Data Record,里面的地址值是0x0000。那么数据18F09FE518F09FE518F09FE518F09FE5要写入FLASH中的地址为 (0x0004 << 16) | 0x0000,也就是写入FLASH的0x40000这个地址。同样,第三行的数据的写入地址为0x40010。当一个HEX文件的数据超过64k的时候,文件中就会出现多个Extended Linear Address Record。 End of File Record 行是每一个HEX文件的最后一行。例如: :00000001FF 这样的一行数据内容是固定的,数据长度为0,地址为0。 校验值:每一行的最后一个值为此行数据的校验和。例如: :1000000018F09FE518F09FE518F09FE518F09FE5C0 这行中的 0xC0 :1000100018F09FE5805F20B9F0FF1FE518F09FE51D 这行中的 0x1D 校验和的算法为:计算从0x3A 以后(不包括0x3A)的所有各字节的和模256的余。即各字节二进制算术和,不计超过256的溢出值,然后用0x100减去这个算数累加和,得出得值就是此行得校验和。 Intel HEX文件格式(整理) Intel HEX文件是用来保存单片机或其他处理器的目标程序代码的文件,它保存物理程序存储器中的目标代码的映像,以便编程器和仿真器调用.绝大多数编程器都支持Intel HEX格式。 下面是一个Intel HEX文件用记事本打开后看到的内容: :FA :1000000018F09FE518F09FE518F09FE518F09FE5C0 :1000100018F09FE5805F20B9F0FF1FE518F09FE51D :10002000C800000044 :100030004C00000024 ...... :103020005C300000A8E65C300000BA :1140D7 :104094E6000032FFF0FFE8030000A7 :0C30FFFFFFFF :00000001FF Intel HEX文件是文本行的ASCII文本文件,文件内容全部由可打印的ASCII字符组成,可以用记事本打开. Intel HEX由一条或多条记录组成,每行一个记录,每条记录都以冒号":"开始,以回车(0DH)和换行(0AH)结束. 除":"外,每条记录有五个域,每一域由2N(N>=1)个HEX字符组成,格式如下 :[AA][BBBB][CC][DD....DD][EE] 其中: [AA]:表示该记录的实际数据的长度; [BBBB]:表示该记录所包含的数据在实际的存储区中的起始地址; [CC]:为该记录的类型; [DD....DD]:为该记录的实际数据,由2N(N>=1)个HEX字符组成,该域的长度应当与[LL]域所指出长度一致. [EE]:为该记录的数据校验和. 例如对上面例子中的第一行: :FA 用"["和"]"分开后如下: :[02][0000][04][0000][FA] [02]:该记录的实际数据的长度[AA]为2个字节(4个HEX字符); [0000]:该记录所包含的数据在实际的存储区中的起始地址[BBBB]为0000H; [04]:该记录的类型[CC]为04——扩展线性地址; [0000]:该记录的实际数据[DD....DD]; [FA]:该记录的数据校验和[EE]; 对上面例子中的倒数第三行 :1140D7 用"["和"]"分开后如下: :[10][3030][00][00000000][D7] [10]:该记录的实际数据的长度[AA]为16D(10H)个字节(20H个HEX字符); [3030]:该记录所包含的数据在实际的存储区中的起始地址[BBBB]为3030H; [00]:该记录的类型[CC]为00——数据(实际要烧写到存储器中的数据); [0000]:该记录的实际数据[DD....DD]; [FA]:该记录的数据校验和[EE]; 常见的记录类型[CC]如下: 00 :数据记录.表示该记录所包含的数据为实际要烧写到存储器中的数据。 01 :文件结束记录.表示该记录为本文件的最后一个记录。 02 :扩展段地址记录.表示该记录所包含的数据为段地址。 04 :扩展线性地址记录。表示该记录所包含的数据为线性地址。 校验和的计算规则: 以字节(2个HEX字符)为单位,除“:”以外,当前行所有数据的和为00H.注意对和只取低8位. 例如对上面例子中的第一行: :FA 02 00 00 04 00 00 FA 02H+00H+00H+00H+04H+00H+00H+00H+FAH=100H 对上面例子中的倒数第三行 :1140D7 10 30 30 00 00 00 01 40 00 00 00 00 48 30 00 00 00 00 00 00 D7 10H+30H+00H+00H+00H+30H+01H+40H+00H+00H+00H+00H+48H+30H+00H+00H+00H+00H+00H+00H+D7H=200H 扩展线性地址: 当一个扩展线性地址记录被读到后,扩展线性地址将被保存并应用到后面从Intel HEX文件中读出的记录,这个扩展线性一直有效,直到读到下一个扩展线性地址记录. 绝对地址与扩展线性地址的关系如下: 绝对地址=数据记录中的地址[BBBB]+移位后的扩展线性地址 扩展段地址记录 当一个扩展段地址记录被读到后,扩展段地址将被保存并应用到后面从Intel HEX文件中读出的记录,这个扩展段地址一直有效,直到读到下一个扩展段地址记录. 绝对地址与扩展段地址的关系如下: 绝对地址=数据记录中的地址[BBBB]+移位后的扩展段地址


发布评论