
hex文件的内容都是有规律的编码,我们可以对它进行解析,以第一行 :020000040800F2 为例:
1) 每一行都以 :(0x3A)开头
2) 第1个字节0x02 ,表示数据区的字节个数
3) 第2、3字节0x00, 0x00 ,表示偏移地址或无用填0
4) 第4个字节0x04, 表示本行记录的数据类型
‘00’ Data Record :用来记录数据, HEX文件的大部分记录都是数据记录
‘01’ End of File Record :用来标识文件结束,放在文件的最后,标识HEX文件的结尾
‘02’ Extended Segment Address Record :用来标识扩展段地址的记录
‘03’ Start Segment Address Record :段地址 STM32不用
‘04’ Extended Linear Address Record :用来标识扩展线性地址
‘05’ Start Linear Address Record :程序启动运行的地址
5) 第5、6个字节0x08, 0x00即是数据
6) 第7个字节0xF2是校验字节,校验和的算法为:计算从0x3A 以后(不包括0x3A)的所有各字节的和模256的余。即各字节二进制算术和,不计超过256的溢出值,然后用0x100减去空枣行这个算数累加和,得出得值就是此行岩辩得校验和。
7) 每条数据最后还有<0x0d>(回车键)、 <0x0a>(换行键)
<0x3a> [数据长度-1Byte] [数据地址-2Byte] [数据类型-1Byte] [数据-nByte] [验证码-1Byte] <0x0d><0x0a>
注意:由于每行标识数据地址的只有2Byte,所以最大只能到64K,为了可以保存高地址的数据,就有了Extended Linear Address Record。如果这行的数据类型是0x04,那么,这行的数据就是随后数据的基地址。例如:
第一行,是Extended Linear Address Record,里面的数据,也就是基地址是0x0004,
第二行是Data Record,里面的地址值是0x0000。那么数据18F09FE518F09FE518F09FE518F09FE5要写入FLASH中的地址为(0x0004 <<16) | 0x0000,也就是写入FLASH的0x40000这个地址。
第三行的数据的写入地址为0x40010。当一个HEX文件的数据超过7k的时候,文件中就会出现多个Extended Linear Address Record。
----------------------------------------------------
: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.
计算从(0x3a)以后的所有各字节的和模256的余。
即各字节二进制算术和,不计超过256的溢出值,然后用0x100减去这个算数累加和,得出的值就是此行校验码。举一个简单的例子,
如第一行020000040800F2
0x02+0x00+0x00+0x00+0x04+0x08+0x00 = 0x0E
0x100 – 0x0E = 0xF2
for (i = 0i <pHexFileFormat->DataSizei++)
{
tempCheckSum += pHexFileFormat->bData[i]
}
tempCheckSum = 0x100 - tempCheckSum
if (tempCheckSum != pHexFileFormat->CheckSum)
{
//Error
}
#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 = 0i <RECORD_HEX_MAXi++)
{
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 = 0i <p->counti++)
{
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
}
hex文件看程序:hex文件是不能直接读出程序的。这是ASCII码形式的二进制代码文件。
如果单片机没加密的话可以从里面读到二进制程序,一般是用编程器,有些单片机支持下载线的用下载线也可以修改改程序比较难,首先你得到二进制程序,然后反汇编,再修改汇编程序。
此类文件通常用于传输将被存于ROM或者EPROM中的程序和数据。符合Intel HEX文件格式的文本所构成的ASCII文本基轿文件。大多数EPROM编程器或模拟器使用Intel HEX文件。HEX文件记录由对应机器语言码和/或常量数据的十六进制编码数字组成。
记录类型包括:
'00' Data Rrecord:用来记录碧锋梁数据,HEX文件的大部分记录都是数据记录 '01' End of File Record: 用来标识文件结束。
放在文件的最后,标识HEX文件的结尾 '04' Extended Linear Address Record: 用来标识扩展线性悔运地址的记录 '02' Extended Segment Address Record: 用来标识扩展段地址的记录 在上面的后2种记录,都是用来提供地址信息的。
每次碰到这2个记录的时候,都可以根据记录计算出一个“基”地址。 对于后面的数据记录,计算地址的时候,都是以这些“基”地址为基础的。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)