|
含有单片机的电子产品在量产的时候会用到.hex文件或者.bin。hex是十六进制的,包含地址信息和数据信息,而bin文件是二进制的,只有数据而不包含地址。任何文件都有一定的格式规范,hex文件同样具有完整的格式规范。今天和大家分享一下,hex是如何解析的。
3 ]1 S, [: L8 T+ H& u! N$ h
/ R b1 O5 c+ B$ g一hex文件解析hex文件可以通过UltraEdit、Notepad++、记事本等工具打开,用Notepad++打开之后会看到如下数据内容。 使用Notepad++打开后会不同含义的数据其颜色不同。每行数据都会有一个冒号开始,后面的数据由:数据长度、地址、标识符、有效数据、校验数据等构成。以上图的第一行为例,进行解析: 第1个字节10,表示该行具有0x10个数据,即16个字节的数据; 第2、3个字节C000,表示该行的起始地址为0xC000; 第4个字节00,表示该行记录的是数据; 第5-20个字节,表示的是有效数据; 第21个字节73,表示前面数据的校验数据,校验方法:0x100-前面字节累加和; 其中,第4个字节具有5种类型:00-05,含义如下: | 字段 | 含义 | | 00 | 表示后面记录的是数据 | | 01 | 表示文件结束 | | 02 | 表示扩展段地址 | | 03 | 表示开始段地址 | | 04 | 表示扩展线性地址 | | 05 | 表示开始线性地址 |
单片机的hex文件以00居多,都用来表示数据。hex文件的结束部分如下图所示。 最后一行的01表示文件结束了,最后的FF表示校验数据,由0x100-0x01=0xFF得来。
' z2 y7 [2 P8 P$ r8 \1 V
6 _6 M* e( ?/ v+ J0 D 6 I; D- ^, j0 ^5 L$ [ _6 v1 ]
二扩展地址细心的同学可能发现了,上面的地址都是两个字节,范围从0x000-0xFFFF,如果地址是0x17FFFF该怎么办呢?这就要用到扩展字段了,举例如下:
5 h) B& V' N+ O2 w% ` 第一行中,第一个字节为0x02,表示只有两个字节的数据,而扩展段的标识符为0x04表示后面的数据0x0800为扩展线性地址,基地址的计算方法为: (0x0800<<16)=0x08000000,在0x04标识段出现之前,下面的数据都是这个基地址。 第二行的地址是0x0000,那么实际地址应是0x08000000+0x0000=0x08000000; 第二行的地址是0x0010,那么实际地址应是0x08000000+0x0010=0x08000010; 使用Notepad++工具,可以根据颜色的不同来确认校验数据是否正确,如果校验数据的颜色不是绿色,则表示校验结果是错的。
5 r: o" ~4 s, w4 G1 R3 d7 M ( P: W7 ]* Y$ I
三程序如何实现hex解析经常会用到上位机软件来实现单片机的烧录,那上位机就要解析hex文件,程序如何实现hex文件的解析呢?
}( ^+ a! @9 ]1 I4 y: U
头文件代码如下所示: - # ]% O5 y# Y& z1 `. ?# L- l
- #ifndef _HEXLEXER_H_/ p& G/ q( i, _' g
- #define _HEXLEXER_H_+ |, J1 b% n7 u8 Y: s4 s% D! W
- #include <cstdio>+ O' @+ ~7 Y5 D5 Q
- #include <cstring>
. ?8 J& b& j& |2 n" v9 B5 P - #include <cstdlib>2 P& T! C5 \ t2 N0 _- n) p3 a/ f
- /*) k. p+ r1 i2 o; x, z8 F/ l
- Intel Hex文件解析器V1.08 A8 c* F7 P4 ^$ M
- Hex文件的格式如下:$ [6 {& r/ n z) _6 g
- RecordMark RecordLength LoadOffset RecordType Data Checksum: w$ E. I- X m$ h
- 在Intel Hex文件中,RecordMark规定为“:”
: d5 ^7 ], h5 o - */
$ c" l1 k( i' P. P/ C6 S - #pragma warning(disable:4996)3 ~8 g" H5 U6 g5 M, H) }$ B
- #define MAX_BUFFER_SIZE 43* [2 q4 D) ]* I* D4 }( Y
- class Hex9 a: e# g& }0 y- f9 t
- {8 G7 k) E n0 V9 {+ o. p
- public:
8 [- v- i# l: Y2 c7 @ - Hex(char mark);
% k* R4 B ]0 i- m' n& o1 z l - ~Hex();4 Q3 H/ `+ G5 l- }( @5 k
- void ParseHex(char *data);//解析Hex文件
& M* N* x0 @; ?- e - void ParseRecord(char ch);//解析每一条记录 h/ B6 e) b# f, p0 e, k
- size_t GetRecordLength();//获取记录长度, {9 w b! x# J$ B
- char GetRecordMark();//获取记录标识 m/ T2 Z0 l; X6 u8 C
- char *GetLoadOffset();//获取内存装载偏移( C ~( R- f# Z; \( W; X& K4 X
- char *GetRecordType();//获取记录类型
/ V+ K+ t2 S h/ B1 K0 p" i - char *GetData();//获取数据
3 c' @3 ~- K" j0 _1 ~( l - char *GetChecksum();//获取校验和/ Y/ I+ }7 o% o2 k! h1 j( L) _& M
-
) i9 q# @ K* F3 @( n# W - private: E! T, h j' Y9 t
- char m_cBuffer[MAX_BUFFER_SIZE];//存储待解析的记录5 X* H! t) Q8 b4 E5 X- W& t7 j ?
- char m_cRecordMark;//记录标识
- H. V" v! K/ j7 J; d - size_t m_nRecordLength;//记录长度
( @* z1 |' Y6 d- _/ i - char *m_pLoadOffset;//装载偏移0 D& z" s/ l: \: Q4 N
- char *m_pRecordType;//记录类型7 n4 D N4 |1 l0 w! f3 F
- char *m_pData;//数据字段
7 N3 I% J( B/ j/ k0 }6 t" M - char *m_pChecksum;//校验和
% g; f9 {1 M4 {9 A a3 u, t! `! y - bool m_bRecvStatus;//接收状态标识
7 o1 z% {) M7 @% A7 |2 P9 G+ Z - //size_t m_nIndex;//缓存的字符索引值
) \$ W7 p4 P) ^0 l" {) { - };
: V: @; V' _. g% ~
# @9 n- j( E& L) W- Hex::Hex(char mark)1 A2 O* ~- q- x* a! B! ?
- {0 t8 _2 N; Y! k8 A4 p3 @5 ]
- this->m_cRecordMark = mark;) v; t: m6 ]( R: g* O. D& u2 E
- m_cBuffer[0] = '\0';* `' f; Z! G# Q
- //m_pBuffer = NULL;7 }( z/ |5 _% q0 H1 c W2 {$ ^
- m_nRecordLength = 0;8 V* k! M* l8 {7 X8 Y$ }
- m_pLoadOffset = NULL;
2 y) d r) t" e/ O+ h$ R" I& I7 t - m_pRecordType = NULL;
, H( z# O( y9 u' f( x - m_pData = NULL;' d, Q3 p$ J! B( V
- m_pChecksum = NULL;
9 s3 w: l3 H" E. Q* M - m_bRecvStatus = false;
7 S E6 z4 Z; B/ W+ j - //m_nIndex = 0;/ `4 W" K& R, F4 A/ Q" C
- }. G7 n5 Y1 A2 c' e; Q! W) e4 S
9 I& ~9 z! x; f- Hex::~Hex()
6 N% i- Z. n0 j- Q; k - {; s' {' N T% K6 ]" X$ ]
- delete m_pLoadOffset, m_pRecordType, m_pData, m_pChecksum;
+ z2 n. q1 {: N5 | T - }- K2 |% v1 |- q" j4 f
- #endif
复制代码 : i- P, {* {7 P! R
代码如下所示。
, R. t1 L9 M" Q: \9 n: z# ?
( F- x2 H& a, l- #include "HexLexer.h"
9 y4 n) }* L0 | - #include <iostream>, d* s) J i Q5 C
- using namespace std; w! i( O! k" e% Y u
- //获取记录标识' X) S/ y, J9 d6 l; J
- char Hex::GetRecordMark()
4 R, ]- F& c8 X0 h7 I. Q* p) N: m - {
) y& k" v' n: y4 h& | - return this->m_cRecordMark;
1 X. N7 o: L7 W( S - }2 }5 A' A( M7 K. {8 \1 a9 a% i+ v' ], [
- //获取每条记录的长度
& E5 `7 Q4 W5 Y - size_t Hex::GetRecordLength()
3 j7 y5 M/ }1 y$ J* I* d P2 y - {, `# n2 E5 K) U
- //char *len = (char*)malloc(sizeof(char)* 3);4 H" F* r! \$ U
- if (strlen(m_cBuffer)>=2)+ J \9 B1 e8 `, v4 y
- {
- H" Z* e* ]5 c* z& o - char len[3];
& R1 N$ }( `2 |7 K1 N4 {5 K( n - len[0] = m_cBuffer[0];
! Y2 h9 m! [* M - len[1] = m_cBuffer[1];
: J6 Q7 ^# F1 Q/ I - len[2] = '\0';
8 g- w7 e$ P/ o, x - char *p = NULL;/ G+ G5 h$ W7 f# k) V% x4 k
- return strtol(len, &p, 16);: ^1 N% B7 V; q* _
- }% P9 E) Z& K; b5 H, y
- else S* R( q1 q$ B. |% j0 `) z: u0 e
- {
# `( K4 l6 W1 D/ N/ Y+ R' l - return 0;. ^1 [+ M! |6 }' s0 r x
- }
9 p/ z1 M" B. Y# v( G8 t - }# S- r& @* Q# S3 P
- //获取装载偏移
: e. ~; k. X/ o. _" U' X H - char* Hex::GetLoadOffset(): \, E7 h1 X& E i! ]
- {! M4 s9 X1 h. y7 j0 j7 [9 ^
- if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
8 u4 \+ k9 R1 T. ~ - {
# y0 o# ?/ i6 x' S: Z& R - char *offset = (char*)malloc(sizeof(char)* 5);; J( k/ V' c0 x X( w! p' r
- for (int i = 0; i < 4; ++i)4 \4 W8 H. ]) q
- {
7 a, E2 a3 v1 I, U! W- ] - offset[i] = m_cBuffer[i + 2];
3 h5 E# h* m+ v$ v* c0 a8 E* Y0 G - }1 W2 D4 u+ q9 Y, w/ o0 }
- offset[4] = '\0';
* H6 k- m! j+ k" S - m_pLoadOffset = offset;
+ A4 E* u, ~( K! `) x" F- \/ ^ - offset = NULL;9 V# C' M/ S9 S' E" [; j
- }
1 O; R$ B8 C" q' t - return m_pLoadOffset;; p5 W3 W# k8 G4 x% g
- }
) B1 b2 w+ u7 t) L: r8 y3 p u - //获取记录类型2 M" W( z- M0 W; q$ |4 D$ Z$ c/ W
- char* Hex::GetRecordType()5 G. S& E' z, q- d0 X# y8 c
- {. q7 F( V* L/ S
- if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
4 L& j; u8 F5 X5 F9 @( ~8 m3 E1 Y8 I - {! k) O+ _$ r+ m+ b' D6 W H
- char *type=(char*)malloc(sizeof(char)*3);
' y) _/ g5 ~, z9 z2 V# X - type[0] = m_cBuffer[6];
# i! D8 i$ x! t- p6 T" j1 U - type[1] = m_cBuffer[7];
! h$ Z# [3 m9 p - type[2] = '\0';
" t P1 ]! R) x5 W - m_pRecordType = type;
8 _/ A7 J% j: F+ f) _' C - type = NULL;
. i( R+ ?+ u7 R. F - }" c, l' x) E$ p8 r2 X, C7 g
- return m_pRecordType;
, H3 A" z; O9 J# w I& R3 {/ V1 p - }: G1 K& O6 M: B) x% ~% c
- //获取数据
, H, r* N$ | i/ {1 m1 u' |( E - char* Hex::GetData()) D4 c4 y1 |$ R: b
- {
8 g$ L( _8 _: z. V; ` - if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
2 i# C& K9 A* U7 G! M( ] - {8 @& I7 Z) i1 j# }4 l
- int len = GetRecordLength();% b, N" j9 ~' l# ?1 G
- char *data = (char*)malloc(sizeof(char)*(len * 2 + 1));
5 G# B" k) G0 R$ D* c- E% F - for (int i = 0; i < len * 2;++i)
: p0 Z, V! n- E' ?! u/ e3 w - {* `$ T7 n0 O( n) w) K# U4 H# R i
- data[i] = m_cBuffer[i + 8];
6 C, L7 |& x+ `0 T - }
+ j4 g+ X) o: u, C3 i- _: D - data[len * 2] = '\0';
# a, [" o% h- h2 x# h - m_pData = data;
) N: n1 t+ `1 U$ W: V6 r; i0 k - data = NULL;
. o5 t5 @! d1 Y - }4 W2 u9 o$ `( ?
- return m_pData;* w9 ?: w* y6 `3 V) k) C
- }& i$ Q3 Z3 `/ f5 P
- //获取校验和
! ^& c; O9 A; W+ s - char* Hex::GetChecksum()- v4 G6 F+ q) P2 s' I3 G0 G, T
- {0 }, _' ~8 C& E) _+ }# Y
- int len = GetRecordLength();7 S6 G3 l: g. z @* g
- if (strlen(m_cBuffer) == (len + 5) * 2)
3 v) R' ^( B$ S - {( f$ p4 z: E% t. @- U# v& O
- char *checksum=(char*)malloc(sizeof(char)*3);
. J7 S# l1 W% i - checksum[0] = m_cBuffer[(len + 5) * 2 - 2];1 ]# Q y4 v, v7 w
- checksum[1] = m_cBuffer[(len + 5) * 2-1];
! L( i7 V& ?& S2 v- A1 h - checksum[2] = '\0';3 `( m5 P4 s0 X2 f+ o$ [" [
- m_pChecksum = checksum;
( t1 e; z' i( {7 b - checksum=NULL;* t8 E U6 f. G3 a& w5 a' x
- }* z" c4 n; q1 _8 w/ F( P+ C7 G$ F
- return m_pChecksum;- T7 M& z ?9 R- }6 Z( g
- }: w& x" {1 z r* A. Q' e. }
- //解析Hex文件中的每一条记录4 W3 O! D. ]( Q- d; t. d; ^
- void Hex::ParseRecord(char ch) G& |$ Z- D! R( R: U
- {7 K8 l% `3 g% G+ j9 w4 S% r1 o
- size_t buf_len = strlen(m_cBuffer);
/ {) o) u2 N* d( V7 x) j - if (GetRecordMark()==ch)
5 o6 \! W" L! |, Q# Z6 f; x - {4 R( }/ ?7 i: m% Z1 y, n
- m_bRecvStatus = true;3 z4 f! A, t; `- S$ {) p
- m_cBuffer[0] = '\0';
5 d, b" [4 s$ W - //m_nIndex = 0;
7 c+ ~4 N, p' X - return;
3 \, C, b; I; V, X2 R5 z - }. ]# X1 ?: y1 m& @
- if ((buf_len==(GetRecordLength()+5)*2-1))3 i( F$ r+ d! \! ?3 Q
- {
0 i9 }: O3 w: Y, t$ I. P - //接收最后一个字符
( C* ~# P3 v: U" U W - m_cBuffer[buf_len] = ch;
o* s5 u5 w! Q" y& f$ s1 T# B" a - m_cBuffer[buf_len + 1] = '\0';
/ m: k+ J1 o: Q( q0 ~- { - //检验接收的数据
/ ]) ^3 z& E# O - char temp[3];
\ }, h0 E2 i* ^! l7 f - char *p = NULL;
: D* m+ S( P% c5 s& X - long int checksum = 0;
" [1 m# a2 _" e9 m |( Q q - for (int i = 0; i < strlen(m_cBuffer);i+=2)( g# \( D2 T# Y. r1 @# p
- {4 N0 V, R! {1 O$ Q4 B- K3 B0 f
- temp[0] = m_cBuffer[i];
0 y0 |7 [8 y9 i" [ - temp[1] = m_cBuffer[i + 1];
0 @( l* w4 ^. H, p" l$ `! h+ k# D - temp[2] = '\0';
$ R: l7 b8 @* g) p+ p* O: J s& y - checksum += strtol(temp, &p, 16);
/ ]' s' Y- B5 G7 {( P* ` - temp[0] = '\0';2 ^ q0 u+ A& U
- }
; `6 m4 g, ]! U2 G8 p - checksum &= 0x00ff;//取计算结果的低8位
1 ~' f4 l% v3 o) h+ N+ s8 }% h - if (checksum==0)//checksum为0说明接收的数据无误: k: s7 N( f9 Y3 [, t3 U! z
- {
8 L2 q# o+ l; v! h+ {6 p5 D5 g - cout << "RecordMark " << GetRecordMark() << endl;! B: k' \8 E- X9 m
- cout << "RecordLength " << GetRecordLength() << endl;
7 ~ [. X B, w# \8 z" t - cout << "LoadOffset " << GetLoadOffset() << endl;
0 h. l0 a9 t4 y; S* o' b - cout << "RecordType " << GetRecordType() << endl;: L/ C( r1 x% |; V
- cout << "Data " << GetData() << endl;9 q/ F1 ]7 v6 C( g" G6 T
- cout << "Checksum " << GetChecksum() << endl;
X- d/ p) y; F7 L4 {/ ^, ]6 \ n - }
/ E& M* g2 h( V - else//否则接收数据有误4 O' ^4 s2 X* @4 r9 m: g
- {5 K% q1 C+ _+ V i Y) V
- cout << "Error!" << endl;
% H7 n* z8 u& m - }6 f2 q3 \1 |7 l+ ^4 E( [
- m_cBuffer[0] = '\0';! Q" f5 x# Y/ |# |
- m_bRecvStatus = false;
5 P8 ~4 {3 w! T1 Q - m_nRecordLength = 0;
; w5 a/ E% [! y' V - m_pLoadOffset = NULL;8 G8 o/ Z& v! d# {
- m_pRecordType = NULL;( W& g% Y' f4 e7 W8 H' }/ l
- m_pChecksum = NULL;
0 q( s) x5 C2 T3 B - m_bRecvStatus = false;7 }0 {9 {8 g( z3 [! @
- }
! y' e5 R3 `3 z0 K6 P - else if (m_bRecvStatus)
9 ]5 d5 o8 P& H& c - {' y0 m2 P0 ^+ o: ]
- m_cBuffer[buf_len] = ch;; ^$ `* g Z# z8 |- [
- m_cBuffer[buf_len + 1] = '\0';6 ?, U7 H- k1 i5 t' @/ L
- //m_nIndex++;
8 S A8 }4 ~% j- W% K! _. Y - }/ F' l e! {: l2 R* t( M
- }6 Q$ W2 }4 ]% |. o
- //解析Hex文件
& H5 [ W4 p4 n5 M5 N - void Hex::ParseHex(char *data)
1 M- u# N/ L; r/ ]8 K v2 n3 D - {
) _( e! I N2 J - for (int i = 0; i < strlen(data);++i)/ _& p1 q& ? w) z& c& U/ X) J6 \
- {. Q m z' B k/ W1 i8 t: }
- ParseRecord(data[i]);
' C. L% a# a* ]" D+ l+ Y- Q: N - }% J5 |$ N+ R" z* F2 Y1 B
- }/ F) O3 P6 E9 \0 c! c" g
- int main(int argc, char *argv[])
" E) @9 R9 g5 O" I! A2 ]* a - { G' q" [) C* Z1 I
- freopen("in.txt", "r", stdin);) N. F% I; k6 J
- freopen("out.txt", "w", stdout);$ G6 p- \) p# f$ q9 ?; P' s
# I; L& e7 J0 d/ r% H- Hex hex(':');, _9 d( W0 T9 q" k% C+ _9 R
- char ch; _+ f2 e- _" C* z
- while (cin>>ch)! v' C: t8 l" @1 x
- {+ s* N) \2 u! G y, r: V& Z7 e
- hex.ParseRecord(ch);: I2 Y+ Q# o- @, ~, ^: A T
- }
7 O$ ]7 w, ~" s+ b+ U - fclose(stdout);
& C7 M5 U* ^7 o; P4 L' o8 t - fclose(stdin);
5 o: o, |5 i& `2 g# u - return 0;
5 k5 w0 l/ ~7 J4 B2 i: S2 K - }
复制代码
_' K$ T% ?, s5 C$ _' T4 Y2 o- e是不是这样呢?赶紧打开.hex文件来看一下吧。
+ J7 n/ n& P! ]8 q+ ] F |