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

hex是如何解析的

[复制链接]
gaosmile 发布时间:2020-10-22 23:01
含有单片机的电子产品在量产的时候会用到.hex文件或者.bin。hex是十六进制的,包含地址信息和数据信息,而bin文件是二进制的,只有数据而不包含地址。任何文件都有一定的格式规范,hex文件同样具有完整的格式规范。今天和大家分享一下,hex是如何解析的。

1 c& d3 i8 q- Q# C
( j2 o/ C# \; ^0 q, M7 ^  p" m
一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得来。
+ x& ^) T7 F& M0 o2 F2 o
$ t3 Q( q: I4 V1 @/ W

2 B, ^4 T1 E4 ]二扩展地址
细心的同学可能发现了,上面的地址都是两个字节,范围从0x000-0xFFFF,如果地址是0x17FFFF该怎么办呢?这就要用到扩展字段了,举例如下:
微信图片_20201022230031.png
$ ?8 r6 v& D- \8 b 第一行中,第一个字节为0x02,表示只有两个字节的数据,而扩展段的标识符为0x04表示后面的数据0x0800为扩展线性地址,基地址的计算方法为:
(0x0800<<16)=0x08000000,在0x04标识段出现之前,下面的数据都是这个基地址。
第二行的地址是0x0000,那么实际地址应是0x08000000+0x0000=0x08000000;
第二行的地址是0x0010,那么实际地址应是0x08000000+0x0010=0x08000010;
使用Notepad++工具,可以根据颜色的不同来确认校验数据是否正确,如果校验数据的颜色不是绿色,则表示校验结果是错的。
: }) o3 f% W# v

. U) T1 ]! u1 v$ D$ h5 P三程序如何实现hex解析
经常会用到上位机软件来实现单片机的烧录,那上位机就要解析hex文件,程序如何实现hex文件的解析呢?
% V2 C; \: N+ @9 b
头文件代码如下所示:

  1. " E/ @) z! j' ^; K" \- k8 ]
  2. #ifndef _HEXLEXER_H_5 z8 r! ]. t# t0 S! Q% s+ U; V
  3. #define _HEXLEXER_H_
    $ k$ {  |8 t5 J, p
  4. #include <cstdio>3 ~& S$ j$ z  n7 ~+ L! I6 Z* H$ M
  5. #include <cstring>  r; }% c# _# R: B$ c5 y1 J, ~; e' k
  6. #include <cstdlib>
    + L4 {; N* t$ _. r- |
  7. /*- F% y! i. C6 G4 i6 O1 @
  8. Intel Hex文件解析器V1.04 R8 L$ d; c9 O, I! N
  9. Hex文件的格式如下:& R0 e* y& B/ s( G% D/ F0 {9 X
  10. RecordMark  RecordLength  LoadOffset  RecordType  Data  Checksum$ V/ o/ L+ E/ @+ g6 S: @
  11. 在Intel Hex文件中,RecordMark规定为“:”: P+ w: l8 L9 G9 C5 g& Q& _$ I
  12. */% x! z( s5 \; R" }, K0 n( u. T
  13. #pragma warning(disable:4996)
    % `) x  Y' z. R! |' D3 @5 o9 b
  14. #define MAX_BUFFER_SIZE 43
    : q7 K( Y% z$ b( U" x% G$ U) g3 _
  15. class Hex
    , f4 i. l! B* Q
  16. {  S% R  a6 G& D! I; K9 c# k
  17. public:6 c+ P  H( H7 I0 t
  18.   Hex(char mark);
    1 S2 H% J! o( J6 c5 c, R0 z" }9 P
  19.   ~Hex();
    ' K# S$ }% w) G* R$ s) A! }' N( B# W
  20.   void ParseHex(char *data);//解析Hex文件" c  B( \8 \/ D, C1 g2 K# `$ L' M
  21.   void ParseRecord(char ch);//解析每一条记录  H2 W, q3 e: x2 ?: H
  22.   size_t GetRecordLength();//获取记录长度
    ; u4 x. H; n2 k' L) f
  23.   char GetRecordMark();//获取记录标识  }7 p8 A* e7 B6 T' |
  24.   char *GetLoadOffset();//获取内存装载偏移1 T1 |  ], O) A2 O: ?
  25.   char *GetRecordType();//获取记录类型
    4 _. @% R' P( [3 m, D
  26.   char *GetData();//获取数据0 X0 U( ]6 C8 s8 ^4 s
  27.   char *GetChecksum();//获取校验和1 L; x( N; j% [! f9 }
  28.   - `6 D* W: h. m' `' q, n1 {' c& F/ u
  29. private:/ \8 [, y) x# o: q
  30.   char m_cBuffer[MAX_BUFFER_SIZE];//存储待解析的记录+ q( l8 t' \, ?9 _& N2 u& o
  31.   char m_cRecordMark;//记录标识5 E' j; z4 ]$ \% c7 i
  32.   size_t m_nRecordLength;//记录长度
    7 R' @3 m/ h. Z
  33.   char *m_pLoadOffset;//装载偏移
    9 A2 @; h7 p" e& I- f6 E, W2 d
  34.   char *m_pRecordType;//记录类型" b2 }% |! _# ~: n2 ~
  35.   char *m_pData;//数据字段
    0 v& ]2 {  V" ]8 }, w. E6 ~
  36.   char *m_pChecksum;//校验和
    $ k9 ^1 ~  ^$ u
  37.   bool m_bRecvStatus;//接收状态标识
    + y- G! K7 G( }
  38.   //size_t m_nIndex;//缓存的字符索引值+ O2 V  ?, a) R1 V8 A+ @
  39. };0 F& h6 a1 O" L5 R6 U

  40. ( G7 M" n6 r$ G# ^1 }- I
  41. Hex::Hex(char mark)
    ! h$ u8 o& O- c" V/ B1 ~( a
  42. {
    / [2 H0 B7 ?  M
  43.   this->m_cRecordMark = mark;: I7 `! _0 G9 O% l, p2 @- d
  44.   m_cBuffer[0] = '\0';
    2 s# ?% t4 J: e
  45.   //m_pBuffer = NULL;/ m2 W. }5 c0 x* k  a
  46.   m_nRecordLength = 0;
    " A, B+ F3 ~8 Z9 ^1 t
  47.   m_pLoadOffset = NULL;/ I! n2 G7 C4 M4 n7 x1 i
  48.   m_pRecordType = NULL;9 D* T" `9 A# l% {. I
  49.   m_pData = NULL;0 O3 [+ w7 W5 K5 f# C
  50.   m_pChecksum = NULL;+ p7 O4 s9 k0 y/ L" O
  51.   m_bRecvStatus = false;4 w$ A# H: T. W2 \' ]+ d; G( r
  52.   //m_nIndex = 0;/ B+ }0 z6 {+ B
  53. }
    8 [4 K( d! X/ q- L( N6 u4 M  y) |
  54. ; e: H( d& U$ q& ^3 r9 K
  55. Hex::~Hex()
    ! X9 |/ d' N  b
  56. {
    8 D5 L' C4 v+ K, l) P
  57.   delete m_pLoadOffset, m_pRecordType, m_pData, m_pChecksum;
    ' \' i& I) b8 t7 z4 L
  58. }6 U- _& Q9 s) H6 Q$ ^
  59. #endif
复制代码
5 H7 ?! L/ r7 E4 E& L+ A
代码如下所示。
; ?/ a9 T* I0 X* `- @4 C" o9 J9 l( r

  1. ; {' L* S& F, G" }( L# Y% k0 K6 X
  2. #include "HexLexer.h"3 a$ j6 Y) W: _: c. ~  Y3 i6 P
  3. #include <iostream>
    % f" o9 ?4 W* y0 Q' a2 P
  4. using namespace std;
    ( c7 Z, r. n7 _. ~& _" P4 s/ a- @
  5. //获取记录标识; U# w" O+ \/ O+ w1 ~' f0 X
  6. char Hex::GetRecordMark()
    3 Y' f1 z9 M$ U+ `: A$ T
  7. {
    : C/ C- o9 H. W9 B: L; Q& {( u
  8.   return this->m_cRecordMark;; A) f2 _( V: f. {9 Z
  9. }
    6 C- i$ l" k) i/ P$ I0 D; I
  10. //获取每条记录的长度8 @  z( h/ ?. w/ v5 C# |$ z5 z& d4 I6 Z# y
  11. size_t Hex::GetRecordLength()
    ' \$ `8 R& Q, E6 d1 a. a7 q' G, q
  12. {' s  f+ _. F) p  g& D# O  E  G
  13.   //char *len = (char*)malloc(sizeof(char)* 3);
    6 \1 E9 S0 U& W4 T. E
  14.   if (strlen(m_cBuffer)>=2)$ @( P# s- n% w5 d2 P$ j5 H) Y
  15.   {6 z# L6 r' t$ [- w
  16.     char len[3];0 Z3 ~0 P7 g( l9 z4 c* V! t) B6 d2 `$ \
  17.     len[0] = m_cBuffer[0];& w; H5 x0 C4 K
  18.     len[1] = m_cBuffer[1];* P) [" o5 B  g* G' Z% i; Q/ C
  19.     len[2] = '\0';9 u! O4 H. k7 k% f0 @2 K& V
  20.     char *p = NULL;
    ) Y8 z- H0 ]& v+ L3 b7 K8 A
  21.     return strtol(len, &p, 16);
    % _  X/ J0 {* r% z+ C1 S
  22.   }# {$ Q: y& \0 l+ Q1 A! G% L$ J4 l
  23.   else4 V% R1 u  u: j' f3 I
  24.   {/ R% F: Z6 C/ p/ ^% x7 Q" v
  25.     return 0;
    , a' o6 o  x& \
  26.   }4 g. ]4 A8 Y4 M; |2 q- s" p
  27. }
    , f3 j. P2 A! M* _7 E
  28. //获取装载偏移8 w1 Y# ^  @$ S2 a' P# m" [8 ]
  29. char* Hex::GetLoadOffset()3 ?! R  V2 i3 M  P* L  U3 v; e
  30. {
    5 ]. }% B; _' Z4 n& U; R' Q" z
  31.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
      {: z/ |+ C* q( d
  32.   {- h8 V2 I2 ~* U- Q+ m. s: o7 O
  33.     char *offset = (char*)malloc(sizeof(char)* 5);6 v1 b* s. Q+ k1 l- R
  34.     for (int i = 0; i < 4; ++i)
    / S; T2 e; ~8 P1 k6 }
  35.     {* r1 ]( E# e0 Y  y2 m9 \& E; c2 l
  36.       offset[i] = m_cBuffer[i + 2];
    ' M# s6 U8 N( u( U2 V
  37.     }
    " C0 @' D) [2 q/ d. y2 C/ v
  38.     offset[4] = '\0';; l$ P1 Y1 Y6 w2 @. C
  39.     m_pLoadOffset = offset;5 }; T! A" I4 b) @) j- G' F( M: s
  40.     offset = NULL;
    " U9 S) u, q) M1 o
  41.   }& N8 ^+ g6 {7 s5 M
  42.   return m_pLoadOffset;
    ! n5 m* v/ O% ~
  43. }
    + v9 J/ {: b% P
  44. //获取记录类型' o( [5 Q" K5 D3 T" t& \) r! p
  45. char* Hex::GetRecordType()8 T( Z% I, \! p# j
  46. {' u0 Z3 G2 }8 _9 ]7 N* e3 [
  47.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)7 e9 }8 i. ~+ A/ E1 c
  48.   {
    3 q' X5 N% f* v- A
  49.     char *type=(char*)malloc(sizeof(char)*3);. u. _7 c# Y9 S5 j' L- }7 ^. F
  50.     type[0] = m_cBuffer[6];
    8 E/ q% Z( H: N6 H
  51.     type[1] = m_cBuffer[7];0 C! j% p$ E6 B; q# |/ l
  52.     type[2] = '\0';" p+ O' L; \! m/ D9 ?
  53.     m_pRecordType = type;  l6 I: |0 s) [
  54.     type = NULL;* L( z  L8 [" F% a& R
  55.   }
    " `. Z+ S1 E$ E
  56.   return m_pRecordType;; ~+ D0 t' f8 s8 C2 y# y
  57. }
    3 D# d5 V: a; X# ^
  58. //获取数据  p: E7 F, O0 q8 n; o
  59. char* Hex::GetData()6 b' b. l- Q, H
  60. {
    " x2 P. ~5 o' p0 s" M& t0 u
  61.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)% h( `+ e# y/ x3 M' O* d& M
  62.   {4 r: r2 l* ~2 A- L' w
  63.     int len = GetRecordLength();; N5 g! M* k" v& q* O
  64.     char *data = (char*)malloc(sizeof(char)*(len * 2 + 1));
    ! H: A, s/ Z3 ^1 g; @
  65.     for (int i = 0; i < len * 2;++i)' L8 u1 c1 [1 ]  n
  66.     {5 i7 v3 P4 H- i/ ]/ R
  67.       data[i] = m_cBuffer[i + 8];
    7 X) O: L% @7 {/ k
  68.     }
    / q) a4 m$ m  W/ G
  69.     data[len * 2] = '\0';. h" O. k. t7 h" l" ~% L
  70.     m_pData = data;
    ) n+ `. a' m, Q+ T
  71.     data = NULL;
    $ ~0 F. p6 W4 G9 `
  72.   }
    * z! `( `3 J" [$ i  o) [# l4 t- s; M2 D
  73.   return m_pData;
    7 y& C: z$ @  f% b7 i4 N5 _4 D
  74. }- a4 {1 p2 p! P% {4 T
  75. //获取校验和
    : o) d/ B, h. W! `. h8 L* V
  76. char* Hex::GetChecksum()
    # I/ c0 h9 ~' K+ F+ \' i- C% K
  77. {
    9 x3 k& t. }7 [. O6 j
  78.   int len = GetRecordLength();
    / `% C2 e  c  t2 b) }1 b7 F
  79.   if (strlen(m_cBuffer) == (len + 5) * 2)
    0 V8 Y. a8 z  F
  80.   {2 d4 o9 p8 T, Y5 K8 n3 D
  81.     char *checksum=(char*)malloc(sizeof(char)*3);3 z- m5 c( E; i2 w
  82.     checksum[0] = m_cBuffer[(len + 5) * 2 - 2];9 Q- i: r8 Z& H' p  E
  83.     checksum[1] = m_cBuffer[(len + 5) * 2-1];
    ( d6 z4 I! ^7 N% w. h
  84.     checksum[2] = '\0';
    & U$ b4 ^4 i8 N
  85.     m_pChecksum = checksum;
    ! K0 x/ w/ T; i! O1 u/ @/ z( T
  86.     checksum=NULL;& t# ]6 t- y( x1 ?8 h6 @0 R9 @9 B
  87.   }
    ( _5 g6 A- ]7 T( F
  88.   return m_pChecksum;8 n1 r) n/ L/ @" g0 D1 Y8 r+ r
  89. }: S% z) j: E. e; l' Q( B
  90. //解析Hex文件中的每一条记录: S( l6 R8 V" g9 ^5 q9 [6 g
  91. void Hex::ParseRecord(char ch): \9 ]& V$ ]. K* N
  92. {& [5 f5 C; {8 z4 s+ g- F5 S
  93.   size_t buf_len = strlen(m_cBuffer);
    1 K6 z, m# T( C) o6 B# W, J8 t, ^
  94.   if (GetRecordMark()==ch)
    ( \8 e8 H/ j7 y2 p# |  @3 p4 ~
  95.   {$ A- f: g# S. |5 x
  96.     m_bRecvStatus = true;' ]4 k) k) }* I. {6 ~  T! m9 G
  97.     m_cBuffer[0] = '\0';
    ! f. }; ], F' l8 I
  98.     //m_nIndex = 0;/ z; j4 }, F; n1 L) Q- P
  99.     return;: G" ]: D# v( \3 V& S: L1 p$ f
  100.   }3 b0 d9 b" X! F" k$ n' g
  101.   if ((buf_len==(GetRecordLength()+5)*2-1))0 `+ p, {, j" v" Z
  102.   {/ z5 b: w$ Y* A6 E2 d
  103.     //接收最后一个字符) I5 I1 N" ^, }% h
  104.     m_cBuffer[buf_len] = ch;
    0 F# k7 @4 ~* c% H4 h+ |
  105.     m_cBuffer[buf_len + 1] = '\0';
    1 V. P2 h& C# E) f: e/ d2 u
  106.     //检验接收的数据+ {! S; K/ l! U1 m& a* e
  107.     char temp[3];" C* q4 f5 F6 e) o+ E, b4 [7 s+ Z7 R
  108.     char *p = NULL;0 e1 n* C; [2 Z% O& e- @+ n9 b
  109.     long int checksum = 0;
    2 k6 Q+ S6 |( z9 S( q  r( N' e( ?
  110.     for (int i = 0; i < strlen(m_cBuffer);i+=2)
    ! N  j/ |6 @4 h( }$ I' j
  111.     {
    2 _, b2 r1 G$ t7 Z$ M; L
  112.       temp[0] = m_cBuffer[i];/ ?. ]$ D3 ?& o. b( r# L
  113.       temp[1] = m_cBuffer[i + 1];
    / e0 O% V9 ~/ J) t
  114.       temp[2] = '\0';
    3 j# h! _( G  T- w
  115.       checksum += strtol(temp, &p, 16);( V1 c  T! B& k, d
  116.       temp[0] = '\0';
    * h, {5 `5 c6 z* L% F7 u- ^
  117.     }; X# e  z2 b3 W; V$ ^
  118.     checksum &= 0x00ff;//取计算结果的低8位
    2 h, S- d% ^1 [$ T4 R, x0 Y' y) T! n
  119.     if (checksum==0)//checksum为0说明接收的数据无误
    & y% _/ S# ^( b4 T$ N1 B
  120.     {4 F, H2 O- J" g& {/ H# W( D
  121.       cout << "RecordMark " << GetRecordMark() << endl;
    5 B5 v+ Q/ n5 o  O
  122.       cout << "RecordLength " << GetRecordLength() << endl;6 M" B" U% U1 E& i
  123.       cout << "LoadOffset " << GetLoadOffset() << endl;9 B& P! y$ F" d8 q! ?3 D1 ^
  124.       cout << "RecordType " << GetRecordType() << endl;
    + `6 E7 k" O' Q7 V- f" u0 G
  125.       cout << "Data " << GetData() << endl;
    " }( O+ \9 T8 k% F1 P2 J
  126.       cout << "Checksum " << GetChecksum() << endl;" v1 O9 k5 c. @7 H6 ?% |
  127.     }3 d1 L4 e8 U9 t; ]
  128.     else//否则接收数据有误2 B, R2 }3 z" {: m$ j4 j+ x# h
  129.     {' S$ s7 e; v4 b0 s& V
  130.       cout << "Error!" << endl;7 O) U  L. Q6 X, e  q7 M7 x4 }1 d7 c
  131.     }
    + H3 N. t2 V/ ?7 H5 Y, W
  132.     m_cBuffer[0] = '\0';
    ; C+ ]& e& L9 \8 j" n4 y/ G
  133.     m_bRecvStatus = false;
    . u8 S4 L* k  x9 A2 B
  134.     m_nRecordLength = 0;
    & e: m# H$ A# w5 q
  135.     m_pLoadOffset = NULL;' g' r! h2 w- K
  136.     m_pRecordType = NULL;
    * z) q; @; r  N9 u
  137.     m_pChecksum = NULL;
    9 m$ x0 s# p  Q) W
  138.     m_bRecvStatus = false;
    - |3 _9 t* w  H; d7 J3 A& V4 E
  139.   }$ b  F9 [6 i- m2 Y" C) r
  140.   else if (m_bRecvStatus)1 x, r. y% S+ ?/ g1 M6 Z+ m
  141.   {5 g4 ^* M+ F- s; T% z: a
  142.     m_cBuffer[buf_len] = ch;
    5 A) [7 T4 F+ D0 Q, \
  143.     m_cBuffer[buf_len + 1] = '\0';
    - c" I" \/ n7 P, J3 n' ~
  144.     //m_nIndex++;5 D( W  ^, L: N
  145.   }4 S6 N1 J; J) Z1 R1 H
  146. }/ X& T' l& v3 b- \; R8 K* O" b9 w! H
  147. //解析Hex文件0 m. C! J9 T2 N' B1 Q' l6 b% k% x
  148. void Hex::ParseHex(char *data)
    6 Y* R9 H5 ]5 y4 ~8 w  u# P' L# R: C
  149. {
    7 O) S  p) `; t; G) v. n1 @
  150.   for (int i = 0; i < strlen(data);++i)4 P! C4 K4 O9 Q/ _+ o
  151.   {
    ( F- {% X  s( F, ?& \; j# ?% V
  152.     ParseRecord(data[i]);
    & [, ^! B4 G. f- P8 F4 g* o& S
  153.   }! g$ i$ R1 Q% J
  154. }
    1 O: c: ^7 P* `, E
  155. int main(int argc, char *argv[])
    & m6 W) A% _9 k: \
  156. {% f  Z# t% J( g( _. [) ?( ?
  157.   freopen("in.txt", "r", stdin);
    ! G# Z4 g2 ?( M
  158.   freopen("out.txt", "w", stdout);
    & t, K) I2 G" T0 ^7 t

  159.   S$ `8 Q. V% w# R1 {" |2 t5 d
  160.   Hex hex(':');
    1 A5 P8 N& w+ r$ o
  161.   char ch;
    . t9 O2 S& o+ {6 J, \
  162.   while (cin>>ch)
    # n& f( K' X/ F, m- T& z, W
  163.   {4 L/ d* n+ x  @) k
  164.     hex.ParseRecord(ch);' Q, M- y4 E: s6 V
  165.   }
    6 h$ _$ A* d# n6 Y: l
  166.   fclose(stdout);, D, m0 m0 K$ [+ L1 @
  167.   fclose(stdin);' ?% z! N3 _) P
  168.   return 0;
    ! C* ?# z/ D* W+ n; \4 C
  169. }
复制代码

* y% c& G; b+ X! S
是不是这样呢?赶紧打开.hex文件来看一下吧。

2 w5 F% G. P) [& p
收藏 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 手机版