Hex文件格式介绍(介绍部分转载地址:http://www.forwhat.cn/post-240.html)
Hex文件是可以烧录到MCU中,被MCU执行的一种文件格式。如果用记事本打开可发现,整个文件以行为单位,每行以冒号开头,内容全部为16进制码(以ASCII码形式显示)。Hex文件可以按照如下的方式进行拆分来分析其中的内容:
例如 “:1000080080318B1E0828092820280B1D0C280D2854”可以被看作“0x10 0x00 0x08 0x00 0x80 0x31 0x8B 0x1E 0x08 0x28 0x09 0x28 0x20 0x28 0x0B 0x1D 0x0C 0x28 0x0D 0x28 0x54”
第一个字节 0x10表示本行数据的长度;
第二、三字节 0x00 0x08表示本行数据的起始地址;
第四字节 0x00表示数据类型,数据类型有:0x00、0x01、0x02、0x03、0x04、0x05。
'00' Data Rrecord:用来记录数据,HEX文件的大部分记录都是数据记录
'01' End of File Record: 用来标识文件结束,放在文件的最后,标识HEX文件的结尾
'02' Extended Segment Address Record: 用来标识扩展段地址的记录
'03' Start Segment Address Record:开始段地址记录
'04' Extended Linear Address Record: 用来标识扩展线性地址的记录
'05' Start Linear Address Record:开始线性地址记录
然后是数据,最后一个字节 0x54为校验和。
校验和的算法为:计算0x54前所有16进制码的累加和(不计进位),检验和 = 0x100 - 累加和
在上面的后2种记录,都是用来提供地址信息的。每次碰到这2个记录的时候,都可以根据记录计算出一个“基”地址。对于后面的数据记录,计算地址的时候,都是以这些“基”地址为基础的。
HEX文件都是由记录(RECORD)组成的。在HEX文件里面,每一行代表一个记录。记录的基本格式为:
Record mark ‘:’
Length
Load offset
Record type
INFO or DATA
CHKSUM
1 byte
1 byte
2 bytes
1 byte
n bytes
1 byte
看个例子:
:020000040008F2
:10000400FF00A0E314209FE5001092E5011092E5A3
:00000001FF
对上面的HEX文件进行分析:
第1条记录的长度为02,LOAD OFFSET为0000,RECTYPE为04,说明该记录为扩展段地址记录。数据为0008,校验和为F2。从这个记录的长度和数据,我们可以计算出一个基地址,这个地址为(0x0008 << 16)。后面的数据记录都以这个地址为基地址。
第2条记录的长度为10(16),LOAD OFFSET为0004,RECTYPE为00,说明该记录为数据记录。数据为FF00A0E314209FE5001092E5011092E5,共16个BYTE。这个记录的校验和为A3。此时的基地址为0X80000,加上OFFSET,这个记录里的16BYTE的数据的起始地址就是0x80000 + 0x0004 = 0x80004.
第3条记录的长度为00,LOAD OFFSET为0000,TYPE = 01,校验和为FF。说明这个是一个END OF FILE RECORD,标识文件的结尾。
在上面这个例子里,实际的数据只有16个BYTE:FF00A0E314209FE5001092E5011092E5,其起始地址为0x0004.
以下是我的代码实现:头文件:
#ifndef CHEX_H
#define CHEX_H
#include <QFile>
const quint8 MIN_HEX_LINE_COUNT_LENGHT = 12;
typedef enum __tagHexErrorCode
{
HEX_NO_ERROR = 0,
HEX_FORMAT_ERROR,
HEX_VERIFY_ERROR,
HEX_LENGHT_ERROR,
HEX_USERPAPR_EEROR,
}EHexErrorCode;
typedef enum __tagHexType
{
RECORD_DATA = 0,
RECORD_END_OF_FILE,
RECORD_EXTENDED_SEGMENT_ADDRESS,
RECORD_START_SEGMENT_ADDRESS,
RECORD_EXTENDED_LINEAR_ADDRESS,
RECORD_START_LINEAR_ADDRESS,
RECORD_HEX_MAX,
}emHexType;
typedef struct __tagHexLineData
{
emHexType type;
quint8 count;
quint32 address;
quint8 data[80];
quint8 checksum;
quint8 datalen;
}stHexLineData;
class CHex
{
public:
CHex();
EHexErrorCode getHexLineData(QByteArray bydata,stHexLineData *p);
private:
char ConvertHexChar(char ch);
};
#endif // CHEX_H
源文件:
#include "chex.h"
const QString HexTypeTable[6] =
{
"00","01","02","03","04","05",
};
CHex::CHex()
{
}
char CHex::ConvertHexChar(char ch)
{
if((ch >= '0') && (ch <= '9'))
return (ch-0x30);
else if((ch >= 'A') && (ch <= 'F'))
return ((ch-'A')+10);
else if((ch >= 'a') && (ch <= 'f'))
return ((ch-'a')+10);
else return (-1);
}
EHexErrorCode CHex::getHexLineData(QByteArray bydata,stHexLineData *p)
{
quint8 i = 0;
quint8 cs_temp = 0;
QString str(bydata);
char *pcdata = bydata.data();
quint32 linelen = str.size();
if((linelen < MIN_HEX_LINE_COUNT_LENGHT)) {return HEX_LENGHT_ERROR;}
if(*pcdata != 0x3A) {return HEX_FORMAT_ERROR;}//必须以":"号开始
//获取Type
QString stype = str.mid(7,2);
for(i = 0; i < RECORD_HEX_MAX; i++)
{
if(stype == HexTypeTable[i])
{
p->type = (emHexType)i;
break;
}
}
if(i == RECORD_HEX_MAX) {qDebug("HEX_FORMAT_ERROR");return HEX_FORMAT_ERROR;}
cs_temp += (ConvertHexChar(*(pcdata + 7)) << 4) | ConvertHexChar(*(pcdata + 8));
//获取count
p->count = (ConvertHexChar(*(pcdata + 1)) << 4) | ConvertHexChar(*(pcdata + 2));
cs_temp += p->count;
if(p->count != (((linelen - 2) / 2) - 5)) {qDebug("HEX_FORMAT_ERROR");return HEX_FORMAT_ERROR;}
//获取address
p->address = (ConvertHexChar(*(pcdata + 3)) << 12) | (ConvertHexChar(*(pcdata + 4)) << 8) | (ConvertHexChar(*(pcdata + 5)) << 4) | ConvertHexChar(*(pcdata + 6));
cs_temp += (p->address >> 8) & 0xFF;
cs_temp += p->address & 0xFF;
//获取data
for(i = 0; i < p->count; i++)
{
p->data[i] = (ConvertHexChar(*(pcdata + 2*i + 9)) << 4) | ConvertHexChar(*(pcdata + 2*i + 10));
cs_temp += p->data[i];
}
p->checksum = (ConvertHexChar(*(pcdata + 2*i + 9)) << 4) | ConvertHexChar(*(pcdata + 2*i + 10));
if(p->checksum != ((0x100 - cs_temp) & 0xFF))
{
qDebug("HEX_VERIFY_ERROR");
return HEX_VERIFY_ERROR;
}
p->datalen = p->count;
return HEX_NO_ERROR;
}