你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

hex是如何解析的

[复制链接]
gaosmile 发布时间:2020-10-22 23:01
含有单片机的电子产品在量产的时候会用到.hex文件或者.bin。hex是十六进制的,包含地址信息和数据信息,而bin文件是二进制的,只有数据而不包含地址。任何文件都有一定的格式规范,hex文件同样具有完整的格式规范。今天和大家分享一下,hex是如何解析的。
$ }; ~3 I  P4 ~, s$ L. G+ G
. J! x  E) `  k1 m2 @2 I
一hex文件解析
hex文件可以通过UltraEdit、Notepad++、记事本等工具打开,用Notepad++打开之后会看到如下数据内容。
微信图片_20201022230025.png
使用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文件的结束部分如下图所示。
微信图片_20201022230028.png
最后一行的01表示文件结束了,最后的FF表示校验数据,由0x100-0x01=0xFF得来。7 K: [* _! N3 r7 q" q  d6 n$ N9 t
' K% _/ j; f4 I( k

/ i3 V1 h: w0 F8 i* U6 {二扩展地址
细心的同学可能发现了,上面的地址都是两个字节,范围从0x000-0xFFFF,如果地址是0x17FFFF该怎么办呢?这就要用到扩展字段了,举例如下:
微信图片_20201022230031.png
- ]" V8 d' d* W: s( c 第一行中,第一个字节为0x02,表示只有两个字节的数据,而扩展段的标识符为0x04表示后面的数据0x0800为扩展线性地址,基地址的计算方法为:
(0x0800<<16)=0x08000000,在0x04标识段出现之前,下面的数据都是这个基地址。
第二行的地址是0x0000,那么实际地址应是0x08000000+0x0000=0x08000000;
第二行的地址是0x0010,那么实际地址应是0x08000000+0x0010=0x08000010;
使用Notepad++工具,可以根据颜色的不同来确认校验数据是否正确,如果校验数据的颜色不是绿色,则表示校验结果是错的。
# g7 R$ ~6 E: V. b% E! _+ B) t

% o: S; G4 y0 B! N/ |三程序如何实现hex解析
经常会用到上位机软件来实现单片机的烧录,那上位机就要解析hex文件,程序如何实现hex文件的解析呢?
1 }( c+ W' Z7 e( `- x9 m( f/ ]
头文件代码如下所示:

  1. * k" W1 O0 `% [
  2. #ifndef _HEXLEXER_H_
    6 M( o2 g4 n) a7 Q; i2 ~( c
  3. #define _HEXLEXER_H_" k; t& q2 N( l( i. ?
  4. #include <cstdio>' O/ j) V. `4 f/ ~6 W
  5. #include <cstring>3 c# ?% u4 p9 y5 l5 |1 o
  6. #include <cstdlib>
    ( S3 Y7 l) q4 t- k6 c% j
  7. /*
    3 X" x0 B! u! G( U
  8. Intel Hex文件解析器V1.0, i+ G4 ]) S( ]4 a
  9. Hex文件的格式如下:
    : V, j' j3 C" L/ n( I
  10. RecordMark  RecordLength  LoadOffset  RecordType  Data  Checksum6 M' T- A  W: ?" Z
  11. 在Intel Hex文件中,RecordMark规定为“:”
    - P' J( Y9 N0 ?+ _# d/ ^" u
  12. */: z& n3 }0 l: Q' P4 o+ }
  13. #pragma warning(disable:4996)
    6 C2 u* P+ w0 x. z" @  ]1 M3 O
  14. #define MAX_BUFFER_SIZE 43% u6 ^( x% @$ C
  15. class Hex/ w6 {7 o7 @0 {
  16. {
    % n* L; o: F2 R% F( C
  17. public:
    # m* `" o1 s6 L1 k7 Q
  18.   Hex(char mark);
    9 ?1 b/ y- q7 h
  19.   ~Hex();. t% h6 M3 M5 d& p* x
  20.   void ParseHex(char *data);//解析Hex文件) t" [7 c* {+ h6 U, I: O# }0 c4 A
  21.   void ParseRecord(char ch);//解析每一条记录
    1 `+ a# ?* N6 {4 c# M4 i; ]) F
  22.   size_t GetRecordLength();//获取记录长度
    & v& `4 M/ T, w! X1 z( b' h
  23.   char GetRecordMark();//获取记录标识
    ( s' `8 e, {" M( z; s6 l1 F- g, s3 M
  24.   char *GetLoadOffset();//获取内存装载偏移) C2 O5 T- N' {8 U$ Q3 Q9 z6 T
  25.   char *GetRecordType();//获取记录类型; z3 X0 G& C9 X8 h% _3 u* m
  26.   char *GetData();//获取数据
      [9 _2 o+ ?1 \3 }
  27.   char *GetChecksum();//获取校验和
    9 i( g0 N: Y" B1 B& g
  28.   9 Y7 O5 O! l3 R: Z. R* s# s
  29. private:
    ) W* {4 S# _! e' P9 ^5 N  I3 U
  30.   char m_cBuffer[MAX_BUFFER_SIZE];//存储待解析的记录1 S" _# O8 H9 _7 {4 b0 ^( Q/ P
  31.   char m_cRecordMark;//记录标识! _' t( h& `" G6 J' T4 }
  32.   size_t m_nRecordLength;//记录长度9 |+ o" ?5 o6 n3 \& `9 v( K- b
  33.   char *m_pLoadOffset;//装载偏移1 i2 O0 K% g, A  g- Y. ~
  34.   char *m_pRecordType;//记录类型, ^7 k6 K  d. e2 \7 @
  35.   char *m_pData;//数据字段$ O, R+ x$ H. W! O6 b
  36.   char *m_pChecksum;//校验和
    ; X9 i4 I  c1 w$ k9 o
  37.   bool m_bRecvStatus;//接收状态标识. z( F( s; t- O7 ?+ j7 f- x1 N3 \, Q7 Z
  38.   //size_t m_nIndex;//缓存的字符索引值! q3 ^" U: P/ h  b1 Z. Y7 o1 S
  39. };: Q& O* E9 C4 x, a& b! s$ M7 ^
  40. 7 y6 ^8 j, _: }8 j- I
  41. Hex::Hex(char mark)1 c8 R6 D1 f3 }2 O) u/ H  B
  42. {; G1 ~: }6 ^" u
  43.   this->m_cRecordMark = mark;
    ) R& L$ D& A! z# l5 C1 P' Z7 O
  44.   m_cBuffer[0] = '\0';6 c4 G: C/ Z3 f9 i( x* c
  45.   //m_pBuffer = NULL;
    3 O" t/ \8 [0 P+ \) x- ^
  46.   m_nRecordLength = 0;+ H; b2 m8 ^. W. f: j5 Y' h
  47.   m_pLoadOffset = NULL;1 {# h) u' h. y5 m, V) }: q
  48.   m_pRecordType = NULL;% s/ H. |- l9 r" r9 j9 {- F
  49.   m_pData = NULL;
    , E; d7 U6 A4 ?5 i
  50.   m_pChecksum = NULL;" T, V/ a+ p5 w2 `
  51.   m_bRecvStatus = false;) h+ \. q' R2 m. Y1 U2 f
  52.   //m_nIndex = 0;
    ! L1 V! s. R+ k# m! ?5 g% n9 T" y
  53. }: N' o5 e7 Q$ S; r* J( V

  54. ' m0 o8 K$ b5 b6 ?  X" f/ S
  55. Hex::~Hex()
    ' K: d' @5 l* o1 K. H" D8 t
  56. {7 a" C. X. n- k  T* h
  57.   delete m_pLoadOffset, m_pRecordType, m_pData, m_pChecksum;
    0 A* O3 x5 s! z' _
  58. }
    7 y9 [: K" Y! f0 ^
  59. #endif
复制代码

! P+ n* D" K9 s  W; Z# A# |* T
代码如下所示。
3 k- |0 s) Y8 O$ N, B, {$ a- M

  1. ; B$ G$ Z5 c% y( b: V8 C% a" |
  2. #include "HexLexer.h"* ?# \7 k, X' p, X
  3. #include <iostream>
    . ]7 S; u9 \% O) R3 z5 C0 ?, N
  4. using namespace std;. }9 l5 K: o; X2 s& M* h% z
  5. //获取记录标识
      P+ ?: n4 m; x
  6. char Hex::GetRecordMark()  l; p) [8 M. r) c1 t% @% ^
  7. {
    4 o" h% P5 ]6 G, j+ r- ]3 y. f
  8.   return this->m_cRecordMark;6 w" t0 h3 U+ Z4 Y) w
  9. }# p2 P4 N; Z' J- A( K3 G
  10. //获取每条记录的长度
    # @# {/ K2 ?- q9 A/ A0 q* t
  11. size_t Hex::GetRecordLength()
    ; u3 D  }1 L4 ?& V
  12. {% z5 h% p- L+ n
  13.   //char *len = (char*)malloc(sizeof(char)* 3);' G$ t6 Y9 e& i, K
  14.   if (strlen(m_cBuffer)>=2), Q. ?- `+ d1 k5 W; m5 U
  15.   {
    & @9 z, B% [5 s4 U1 `; c
  16.     char len[3];
    ! o( {" K& A# ?  O
  17.     len[0] = m_cBuffer[0];
    : e; P' P- k' g+ D! N/ b1 N
  18.     len[1] = m_cBuffer[1];
    * s7 w' ]: F! P) y& e9 |
  19.     len[2] = '\0';& }+ O6 c2 R) [" v* o
  20.     char *p = NULL;
    8 |4 H* p- y6 ~7 E! \" P
  21.     return strtol(len, &p, 16);
    ) {; O: ]5 I, C* [9 |! r
  22.   }
    $ v* a. v, s; i( [! s
  23.   else( \: K( Y% ]! Q' j" m, v: @
  24.   {' q* k( E! t' O7 J- ?
  25.     return 0;& [! c" @' u1 l& r6 H
  26.   }
      a, t9 f. K: L
  27. }
    % D( C0 e) W' t  K" I3 R  Z) D+ \
  28. //获取装载偏移
    8 i0 M" O, n2 j9 j. _# ~* w7 s
  29. char* Hex::GetLoadOffset(). _, j, D9 c. [, n
  30. {
    5 x$ t. ~( J9 J) {
  31.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
    ) i# U9 s# @( N7 Z/ c1 P0 o
  32.   {) H4 f3 Q: u- X- v" Z% P
  33.     char *offset = (char*)malloc(sizeof(char)* 5);
    8 ]& U( A. V6 B  ^: y2 m) u% r& o
  34.     for (int i = 0; i < 4; ++i)
    , Y& z. n  G  e1 H) ^) _5 p" Y
  35.     {4 I. f! y- ?) r" X+ u8 w
  36.       offset[i] = m_cBuffer[i + 2];
    * F- N7 c. Y' v) C
  37.     }+ U- u: f6 u+ a! G% l) t# y  i" E
  38.     offset[4] = '\0';; Y) R9 p  W; |$ ~- H' U9 M
  39.     m_pLoadOffset = offset;' E) o" L: v& F7 t0 M1 Y6 W# j
  40.     offset = NULL;( d+ L3 n: l9 [& k2 L& _( y/ Z
  41.   }
    . T$ }' P+ \/ L" B5 V8 N
  42.   return m_pLoadOffset;
    7 {  G8 J# C& o  W) c- ~" t
  43. }
    ( A9 I$ A* y& n9 n/ G
  44. //获取记录类型
    , L! a5 i$ M+ I- m$ e4 [
  45. char* Hex::GetRecordType()
    4 B5 E( W$ N' [( |4 h
  46. {
    " Z- @* }3 l0 q3 S, {
  47.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
    ! _. o+ p! K) R- h" _
  48.   {
    8 Q0 X! h, F3 F) M0 o: n1 B( a
  49.     char *type=(char*)malloc(sizeof(char)*3);  t! ~1 p" G5 d6 P' M
  50.     type[0] = m_cBuffer[6];: S: X9 t9 ^& L! q& z' \# b
  51.     type[1] = m_cBuffer[7];$ I8 T% W" r/ O0 I6 ^0 ~/ G3 d
  52.     type[2] = '\0';- G. ]2 r1 t- k* X3 o
  53.     m_pRecordType = type;+ H0 T$ W5 i* R6 s( e" x
  54.     type = NULL;
    1 T+ Y) I3 V, @7 R
  55.   }
    ' G+ u4 v% o8 A. x, p+ w
  56.   return m_pRecordType;
    + d$ a" b3 D( X
  57. }
    * r' _8 G3 v( L& b% S* E0 w
  58. //获取数据
    ( F+ a9 n( _6 r2 T: s" e) D
  59. char* Hex::GetData()
    # @9 N7 A! T5 v+ `2 G( N4 h6 i, [
  60. {; n4 i2 r* q# f' k2 |' C3 \: {% a
  61.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
    % l- ?9 @# z3 K5 ?5 H9 l6 R6 g( s
  62.   {
    . O; k$ A/ p5 w, R
  63.     int len = GetRecordLength();
    3 q2 ]7 l- \. ]1 g/ C" ?+ H8 ?
  64.     char *data = (char*)malloc(sizeof(char)*(len * 2 + 1));' @3 I+ P# m/ Q  M3 N; C2 n
  65.     for (int i = 0; i < len * 2;++i)
    + k- N8 _7 C' O; s2 D5 ?9 a8 Q1 [
  66.     {
    , r" O' E1 V2 e* f( g
  67.       data[i] = m_cBuffer[i + 8];: f0 d3 E( C2 y; Q& ?
  68.     }
    ( i. H2 P( G; d
  69.     data[len * 2] = '\0';
    5 f3 F2 d% d# n. I1 J
  70.     m_pData = data;
    ) q0 J5 H+ X# L. r- f6 M/ @7 I
  71.     data = NULL;
    2 I  _" F$ p- T
  72.   }9 F$ ]" B/ h! }
  73.   return m_pData;& d# g& Y* [7 Y; z
  74. }
    " o' I. Y7 o1 h5 Q1 V. I$ ]7 l, [6 Z
  75. //获取校验和3 P2 a9 b3 f# l; {' R. v
  76. char* Hex::GetChecksum()! e: `9 P3 I& D0 e: |/ D7 v2 j4 o% k
  77. {* {$ ^/ v. g; a: m. ]
  78.   int len = GetRecordLength();( w' E) ~( V, X* e6 k
  79.   if (strlen(m_cBuffer) == (len + 5) * 2)9 f& h$ A) A; D) C7 ~/ o* ]* r
  80.   {+ [$ {' e* j1 M+ y4 I
  81.     char *checksum=(char*)malloc(sizeof(char)*3);
    % ?7 E2 T( |9 f8 e9 b/ k
  82.     checksum[0] = m_cBuffer[(len + 5) * 2 - 2];9 p" @; Q. Q  u& V, N- G  U
  83.     checksum[1] = m_cBuffer[(len + 5) * 2-1];* K; x# |. H' @% u
  84.     checksum[2] = '\0';) m- e/ M4 e; W/ x( X
  85.     m_pChecksum = checksum;1 E+ M7 c( r1 {" s) G' _5 A
  86.     checksum=NULL;
    3 @4 c& r" _# K
  87.   }
    7 \6 W+ R$ [. I3 d. T
  88.   return m_pChecksum;. l4 ^  {+ t0 X' S- \2 d, M
  89. }
    : i; u  X$ j% N$ g  L2 D
  90. //解析Hex文件中的每一条记录" y( L9 ?5 k2 U; }9 |
  91. void Hex::ParseRecord(char ch)
    2 ^9 c( j4 _* U0 u
  92. {
    / q# p# K* \/ r
  93.   size_t buf_len = strlen(m_cBuffer);
    4 H* V) l# v/ r& f4 H
  94.   if (GetRecordMark()==ch)/ F8 |8 D; ]% P
  95.   {6 Q9 |; i8 I+ R2 K: W  A/ R
  96.     m_bRecvStatus = true;5 R2 `& H* ?) G- L2 U% m
  97.     m_cBuffer[0] = '\0';9 B" W$ l; J" c' T
  98.     //m_nIndex = 0;- O1 D8 A- F: Q7 J+ c3 d0 S) L7 o
  99.     return;* l. @7 M5 W( Y  ~
  100.   }
    8 j/ [* G5 O' V- q
  101.   if ((buf_len==(GetRecordLength()+5)*2-1))' Y: D$ p: ?# i/ X+ Y" A
  102.   {
    ) H- T! M, Y. w1 {
  103.     //接收最后一个字符
    6 t. m: f- B: z& P! ?
  104.     m_cBuffer[buf_len] = ch;: S4 q8 \0 c, _/ C  N8 a8 b% s
  105.     m_cBuffer[buf_len + 1] = '\0';7 F# g) F6 ~' v3 L. p: s
  106.     //检验接收的数据0 r1 L1 W( s! S; E2 c; O
  107.     char temp[3];1 h- P& M. w/ V5 z5 J. ?
  108.     char *p = NULL;
    4 W/ e+ ]# P5 h6 i* I) _* }) E% T
  109.     long int checksum = 0;
    - @0 C* ?0 ?/ r$ k
  110.     for (int i = 0; i < strlen(m_cBuffer);i+=2)
    $ X" `9 B$ C% n1 g
  111.     {
    ) ^7 [3 D. ~( }# N. R, ]
  112.       temp[0] = m_cBuffer[i];
    1 k8 `+ a8 H  R; A- \
  113.       temp[1] = m_cBuffer[i + 1];
    ) c+ I9 a! l8 V0 j( U: P
  114.       temp[2] = '\0';
      ?8 r8 Z; l) G4 a9 v. S# f
  115.       checksum += strtol(temp, &p, 16);; q. g) x6 D7 m1 F; F
  116.       temp[0] = '\0';
    2 _" k1 J8 k, s. L! P; u* }# _: d2 k
  117.     }, `! e9 k4 v+ P% O; W
  118.     checksum &= 0x00ff;//取计算结果的低8位
    7 t6 T+ n/ O0 q( c* K: R' s
  119.     if (checksum==0)//checksum为0说明接收的数据无误) j$ c% r, @: z; s8 ^/ l: D  h
  120.     {3 R" T( R9 A2 M+ O% Z' v( ~6 k* k$ w
  121.       cout << "RecordMark " << GetRecordMark() << endl;
    8 k/ G) b, p3 }7 d
  122.       cout << "RecordLength " << GetRecordLength() << endl;
    5 ~8 w) W6 I9 c; O9 U! k' a
  123.       cout << "LoadOffset " << GetLoadOffset() << endl;
      j: o, v) d/ y  i
  124.       cout << "RecordType " << GetRecordType() << endl;
    ! R# H' T- Q' L7 v
  125.       cout << "Data " << GetData() << endl;
    ( k: N5 q" D6 H0 `
  126.       cout << "Checksum " << GetChecksum() << endl;
    ! r$ Z6 w9 h  O' H' |/ Q. x) q" b
  127.     }
    ( v8 L1 f# n( F7 A% n
  128.     else//否则接收数据有误
    : [; C8 A0 p$ s
  129.     {. y1 p$ u9 R2 f. ]! D
  130.       cout << "Error!" << endl;. C# g, s' C$ b4 W! y* Y
  131.     }
    7 o( _8 r- l' g. h5 M, i
  132.     m_cBuffer[0] = '\0';9 b. [/ }1 ~6 n
  133.     m_bRecvStatus = false;! v" {+ f' X+ c9 G3 t* y6 d6 P( N
  134.     m_nRecordLength = 0;6 Y5 y/ {6 X) g0 Y
  135.     m_pLoadOffset = NULL;
    % T( k& m1 t& X3 g' L3 N
  136.     m_pRecordType = NULL;# v! Y* ^1 F  A
  137.     m_pChecksum = NULL;8 G; I! l0 O' n( q( S# m8 u% s
  138.     m_bRecvStatus = false;
    4 M0 @& Z0 x$ W
  139.   }$ b1 g  |  i) f" ^
  140.   else if (m_bRecvStatus)
    + t0 c! _% h# h; s) m
  141.   {
    8 |. M$ j6 |. S0 {7 u0 F
  142.     m_cBuffer[buf_len] = ch;
      Q  h+ q( l% H" t* h6 u
  143.     m_cBuffer[buf_len + 1] = '\0';2 y4 j: w# y# y* o# J( `2 _
  144.     //m_nIndex++;5 T; ~# Z1 x7 [& d( g9 |& q' N
  145.   }
    3 A3 s6 V- R4 |! s7 F$ `. ~' _1 `3 E
  146. }
    ) R7 m; h3 p) u. C
  147. //解析Hex文件& V2 |' H5 \' y! l- E: F0 G
  148. void Hex::ParseHex(char *data)
    : d) _( o# `) U& n" L
  149. {
    / o* [) {* V) J% s( B) l+ m
  150.   for (int i = 0; i < strlen(data);++i)4 w5 H: Z+ o( J, T/ `8 A
  151.   {. b- k3 {& J6 l4 K
  152.     ParseRecord(data[i]);' o# S% B/ K# \# n6 C; w
  153.   }
    2 V7 U7 b8 ]  g. Z
  154. }5 U0 A* J4 `8 V0 K# C- w8 t
  155. int main(int argc, char *argv[])
    5 t  h0 j4 w! m3 J/ [3 @
  156. {
    ) M! i+ A, C- h' T
  157.   freopen("in.txt", "r", stdin);
    0 O1 V$ \% i1 a( n& r
  158.   freopen("out.txt", "w", stdout);
    5 e9 k; y" @7 ]8 T" Q
  159. ! U$ p- }. l- A! e  n& Q( t/ _
  160.   Hex hex(':');
    ! ]& [7 r; d3 W5 i$ z! E' M
  161.   char ch;
    0 T$ K8 g9 |" J- k/ d  T
  162.   while (cin>>ch)
    / X4 m# ]; ~5 C
  163.   {
    $ [( ~& k5 m# s  ~1 m. p
  164.     hex.ParseRecord(ch);
    5 A2 i8 v4 a2 k. I) Z! ~; C
  165.   }
    + w/ ^# x1 C4 \5 [
  166.   fclose(stdout);
    * j! s9 D; k/ [% d9 p- ~8 N2 m8 H
  167.   fclose(stdin);
    ; Y& ?7 ^- Z; Q6 L+ r: p! ]
  168.   return 0;
    - F( `# q& H! O7 t" j- Y
  169. }
复制代码
  _1 C* T$ a* o
是不是这样呢?赶紧打开.hex文件来看一下吧。

7 w7 w# x6 b# ?/ X+ g: w
收藏 1 评论2 发布时间:2020-10-22 23:01

举报

2个回答
jasonZJR 回答时间:2020-10-23 09:26:10
mark~~~~~
heart蓝色CD 回答时间:2020-10-23 20:04:40
不错

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版