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

hex是如何解析的

[复制链接]
gaosmile 发布时间:2020-10-22 23:01
含有单片机的电子产品在量产的时候会用到.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++打开之后会看到如下数据内容。
微信图片_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得来。
' 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该怎么办呢?这就要用到扩展字段了,举例如下:
微信图片_20201022230031.png
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
头文件代码如下所示:
  1. # ]% O5 y# Y& z1 `. ?# L- l
  2. #ifndef _HEXLEXER_H_/ p& G/ q( i, _' g
  3. #define _HEXLEXER_H_+ |, J1 b% n7 u8 Y: s4 s% D! W
  4. #include <cstdio>+ O' @+ ~7 Y5 D5 Q
  5. #include <cstring>
    . ?8 J& b& j& |2 n" v9 B5 P
  6. #include <cstdlib>2 P& T! C5 \  t2 N0 _- n) p3 a/ f
  7. /*) k. p+ r1 i2 o; x, z8 F/ l
  8. Intel Hex文件解析器V1.08 A8 c* F7 P4 ^$ M
  9. Hex文件的格式如下:$ [6 {& r/ n  z) _6 g
  10. RecordMark  RecordLength  LoadOffset  RecordType  Data  Checksum: w$ E. I- X  m$ h
  11. 在Intel Hex文件中,RecordMark规定为“:”
    : d5 ^7 ], h5 o
  12. */
    $ c" l1 k( i' P. P/ C6 S
  13. #pragma warning(disable:4996)3 ~8 g" H5 U6 g5 M, H) }$ B
  14. #define MAX_BUFFER_SIZE 43* [2 q4 D) ]* I* D4 }( Y
  15. class Hex9 a: e# g& }0 y- f9 t
  16. {8 G7 k) E  n0 V9 {+ o. p
  17. public:
    8 [- v- i# l: Y2 c7 @
  18.   Hex(char mark);
    % k* R4 B  ]0 i- m' n& o1 z  l
  19.   ~Hex();4 Q3 H/ `+ G5 l- }( @5 k
  20.   void ParseHex(char *data);//解析Hex文件
    & M* N* x0 @; ?- e
  21.   void ParseRecord(char ch);//解析每一条记录  h/ B6 e) b# f, p0 e, k
  22.   size_t GetRecordLength();//获取记录长度, {9 w  b! x# J$ B
  23.   char GetRecordMark();//获取记录标识  m/ T2 Z0 l; X6 u8 C
  24.   char *GetLoadOffset();//获取内存装载偏移( C  ~( R- f# Z; \( W; X& K4 X
  25.   char *GetRecordType();//获取记录类型
    / V+ K+ t2 S  h/ B1 K0 p" i
  26.   char *GetData();//获取数据
    3 c' @3 ~- K" j0 _1 ~( l
  27.   char *GetChecksum();//获取校验和/ Y/ I+ }7 o% o2 k! h1 j( L) _& M
  28.   
    ) i9 q# @  K* F3 @( n# W
  29. private:  E! T, h  j' Y9 t
  30.   char m_cBuffer[MAX_BUFFER_SIZE];//存储待解析的记录5 X* H! t) Q8 b4 E5 X- W& t7 j  ?
  31.   char m_cRecordMark;//记录标识
    - H. V" v! K/ j7 J; d
  32.   size_t m_nRecordLength;//记录长度
    ( @* z1 |' Y6 d- _/ i
  33.   char *m_pLoadOffset;//装载偏移0 D& z" s/ l: \: Q4 N
  34.   char *m_pRecordType;//记录类型7 n4 D  N4 |1 l0 w! f3 F
  35.   char *m_pData;//数据字段
    7 N3 I% J( B/ j/ k0 }6 t" M
  36.   char *m_pChecksum;//校验和
    % g; f9 {1 M4 {9 A  a3 u, t! `! y
  37.   bool m_bRecvStatus;//接收状态标识
    7 o1 z% {) M7 @% A7 |2 P9 G+ Z
  38.   //size_t m_nIndex;//缓存的字符索引值
    ) \$ W7 p4 P) ^0 l" {) {
  39. };
    : V: @; V' _. g% ~

  40. # @9 n- j( E& L) W
  41. Hex::Hex(char mark)1 A2 O* ~- q- x* a! B! ?
  42. {0 t8 _2 N; Y! k8 A4 p3 @5 ]
  43.   this->m_cRecordMark = mark;) v; t: m6 ]( R: g* O. D& u2 E
  44.   m_cBuffer[0] = '\0';* `' f; Z! G# Q
  45.   //m_pBuffer = NULL;7 }( z/ |5 _% q0 H1 c  W2 {$ ^
  46.   m_nRecordLength = 0;8 V* k! M* l8 {7 X8 Y$ }
  47.   m_pLoadOffset = NULL;
    2 y) d  r) t" e/ O+ h$ R" I& I7 t
  48.   m_pRecordType = NULL;
    , H( z# O( y9 u' f( x
  49.   m_pData = NULL;' d, Q3 p$ J! B( V
  50.   m_pChecksum = NULL;
    9 s3 w: l3 H" E. Q* M
  51.   m_bRecvStatus = false;
    7 S  E6 z4 Z; B/ W+ j
  52.   //m_nIndex = 0;/ `4 W" K& R, F4 A/ Q" C
  53. }. G7 n5 Y1 A2 c' e; Q! W) e4 S

  54. 9 I& ~9 z! x; f
  55. Hex::~Hex()
    6 N% i- Z. n0 j- Q; k
  56. {; s' {' N  T% K6 ]" X$ ]
  57.   delete m_pLoadOffset, m_pRecordType, m_pData, m_pChecksum;
    + z2 n. q1 {: N5 |  T
  58. }- K2 |% v1 |- q" j4 f
  59. #endif
复制代码
: i- P, {* {7 P! R
代码如下所示。
, R. t1 L9 M" Q: \9 n: z# ?

  1. ( F- x2 H& a, l
  2. #include "HexLexer.h"
    9 y4 n) }* L0 |
  3. #include <iostream>, d* s) J  i  Q5 C
  4. using namespace std;  w! i( O! k" e% Y  u
  5. //获取记录标识' X) S/ y, J9 d6 l; J
  6. char Hex::GetRecordMark()
    4 R, ]- F& c8 X0 h7 I. Q* p) N: m
  7. {
    ) y& k" v' n: y4 h& |
  8.   return this->m_cRecordMark;
    1 X. N7 o: L7 W( S
  9. }2 }5 A' A( M7 K. {8 \1 a9 a% i+ v' ], [
  10. //获取每条记录的长度
    & E5 `7 Q4 W5 Y
  11. size_t Hex::GetRecordLength()
    3 j7 y5 M/ }1 y$ J* I* d  P2 y
  12. {, `# n2 E5 K) U
  13.   //char *len = (char*)malloc(sizeof(char)* 3);4 H" F* r! \$ U
  14.   if (strlen(m_cBuffer)>=2)+ J  \9 B1 e8 `, v4 y
  15.   {
    - H" Z* e* ]5 c* z& o
  16.     char len[3];
    & R1 N$ }( `2 |7 K1 N4 {5 K( n
  17.     len[0] = m_cBuffer[0];
    ! Y2 h9 m! [* M
  18.     len[1] = m_cBuffer[1];
    : J6 Q7 ^# F1 Q/ I
  19.     len[2] = '\0';
    8 g- w7 e$ P/ o, x
  20.     char *p = NULL;/ G+ G5 h$ W7 f# k) V% x4 k
  21.     return strtol(len, &p, 16);: ^1 N% B7 V; q* _
  22.   }% P9 E) Z& K; b5 H, y
  23.   else  S* R( q1 q$ B. |% j0 `) z: u0 e
  24.   {
    # `( K4 l6 W1 D/ N/ Y+ R' l
  25.     return 0;. ^1 [+ M! |6 }' s0 r  x
  26.   }
    9 p/ z1 M" B. Y# v( G8 t
  27. }# S- r& @* Q# S3 P
  28. //获取装载偏移
    : e. ~; k. X/ o. _" U' X  H
  29. char* Hex::GetLoadOffset(): \, E7 h1 X& E  i! ]
  30. {! M4 s9 X1 h. y7 j0 j7 [9 ^
  31.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
    8 u4 \+ k9 R1 T. ~
  32.   {
    # y0 o# ?/ i6 x' S: Z& R
  33.     char *offset = (char*)malloc(sizeof(char)* 5);; J( k/ V' c0 x  X( w! p' r
  34.     for (int i = 0; i < 4; ++i)4 \4 W8 H. ]) q
  35.     {
    7 a, E2 a3 v1 I, U! W- ]
  36.       offset[i] = m_cBuffer[i + 2];
    3 h5 E# h* m+ v$ v* c0 a8 E* Y0 G
  37.     }1 W2 D4 u+ q9 Y, w/ o0 }
  38.     offset[4] = '\0';
    * H6 k- m! j+ k" S
  39.     m_pLoadOffset = offset;
    + A4 E* u, ~( K! `) x" F- \/ ^
  40.     offset = NULL;9 V# C' M/ S9 S' E" [; j
  41.   }
    1 O; R$ B8 C" q' t
  42.   return m_pLoadOffset;; p5 W3 W# k8 G4 x% g
  43. }
    ) B1 b2 w+ u7 t) L: r8 y3 p  u
  44. //获取记录类型2 M" W( z- M0 W; q$ |4 D$ Z$ c/ W
  45. char* Hex::GetRecordType()5 G. S& E' z, q- d0 X# y8 c
  46. {. q7 F( V* L/ S
  47.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
    4 L& j; u8 F5 X5 F9 @( ~8 m3 E1 Y8 I
  48.   {! k) O+ _$ r+ m+ b' D6 W  H
  49.     char *type=(char*)malloc(sizeof(char)*3);
    ' y) _/ g5 ~, z9 z2 V# X
  50.     type[0] = m_cBuffer[6];
    # i! D8 i$ x! t- p6 T" j1 U
  51.     type[1] = m_cBuffer[7];
    ! h$ Z# [3 m9 p
  52.     type[2] = '\0';
    " t  P1 ]! R) x5 W
  53.     m_pRecordType = type;
    8 _/ A7 J% j: F+ f) _' C
  54.     type = NULL;
    . i( R+ ?+ u7 R. F
  55.   }" c, l' x) E$ p8 r2 X, C7 g
  56.   return m_pRecordType;
    , H3 A" z; O9 J# w  I& R3 {/ V1 p
  57. }: G1 K& O6 M: B) x% ~% c
  58. //获取数据
    , H, r* N$ |  i/ {1 m1 u' |( E
  59. char* Hex::GetData()) D4 c4 y1 |$ R: b
  60. {
    8 g$ L( _8 _: z. V; `
  61.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
    2 i# C& K9 A* U7 G! M( ]
  62.   {8 @& I7 Z) i1 j# }4 l
  63.     int len = GetRecordLength();% b, N" j9 ~' l# ?1 G
  64.     char *data = (char*)malloc(sizeof(char)*(len * 2 + 1));
    5 G# B" k) G0 R$ D* c- E% F
  65.     for (int i = 0; i < len * 2;++i)
    : p0 Z, V! n- E' ?! u/ e3 w
  66.     {* `$ T7 n0 O( n) w) K# U4 H# R  i
  67.       data[i] = m_cBuffer[i + 8];
    6 C, L7 |& x+ `0 T
  68.     }
    + j4 g+ X) o: u, C3 i- _: D
  69.     data[len * 2] = '\0';
    # a, [" o% h- h2 x# h
  70.     m_pData = data;
    ) N: n1 t+ `1 U$ W: V6 r; i0 k
  71.     data = NULL;
    . o5 t5 @! d1 Y
  72.   }4 W2 u9 o$ `( ?
  73.   return m_pData;* w9 ?: w* y6 `3 V) k) C
  74. }& i$ Q3 Z3 `/ f5 P
  75. //获取校验和
    ! ^& c; O9 A; W+ s
  76. char* Hex::GetChecksum()- v4 G6 F+ q) P2 s' I3 G0 G, T
  77. {0 }, _' ~8 C& E) _+ }# Y
  78.   int len = GetRecordLength();7 S6 G3 l: g. z  @* g
  79.   if (strlen(m_cBuffer) == (len + 5) * 2)
    3 v) R' ^( B$ S
  80.   {( f$ p4 z: E% t. @- U# v& O
  81.     char *checksum=(char*)malloc(sizeof(char)*3);
    . J7 S# l1 W% i
  82.     checksum[0] = m_cBuffer[(len + 5) * 2 - 2];1 ]# Q  y4 v, v7 w
  83.     checksum[1] = m_cBuffer[(len + 5) * 2-1];
    ! L( i7 V& ?& S2 v- A1 h
  84.     checksum[2] = '\0';3 `( m5 P4 s0 X2 f+ o$ [" [
  85.     m_pChecksum = checksum;
    ( t1 e; z' i( {7 b
  86.     checksum=NULL;* t8 E  U6 f. G3 a& w5 a' x
  87.   }* z" c4 n; q1 _8 w/ F( P+ C7 G$ F
  88.   return m_pChecksum;- T7 M& z  ?9 R- }6 Z( g
  89. }: w& x" {1 z  r* A. Q' e. }
  90. //解析Hex文件中的每一条记录4 W3 O! D. ]( Q- d; t. d; ^
  91. void Hex::ParseRecord(char ch)  G& |$ Z- D! R( R: U
  92. {7 K8 l% `3 g% G+ j9 w4 S% r1 o
  93.   size_t buf_len = strlen(m_cBuffer);
    / {) o) u2 N* d( V7 x) j
  94.   if (GetRecordMark()==ch)
    5 o6 \! W" L! |, Q# Z6 f; x
  95.   {4 R( }/ ?7 i: m% Z1 y, n
  96.     m_bRecvStatus = true;3 z4 f! A, t; `- S$ {) p
  97.     m_cBuffer[0] = '\0';
    5 d, b" [4 s$ W
  98.     //m_nIndex = 0;
    7 c+ ~4 N, p' X
  99.     return;
    3 \, C, b; I; V, X2 R5 z
  100.   }. ]# X1 ?: y1 m& @
  101.   if ((buf_len==(GetRecordLength()+5)*2-1))3 i( F$ r+ d! \! ?3 Q
  102.   {
    0 i9 }: O3 w: Y, t$ I. P
  103.     //接收最后一个字符
    ( C* ~# P3 v: U" U  W
  104.     m_cBuffer[buf_len] = ch;
      o* s5 u5 w! Q" y& f$ s1 T# B" a
  105.     m_cBuffer[buf_len + 1] = '\0';
    / m: k+ J1 o: Q( q0 ~- {
  106.     //检验接收的数据
    / ]) ^3 z& E# O
  107.     char temp[3];
      \  }, h0 E2 i* ^! l7 f
  108.     char *p = NULL;
    : D* m+ S( P% c5 s& X
  109.     long int checksum = 0;
    " [1 m# a2 _" e9 m  |( Q  q
  110.     for (int i = 0; i < strlen(m_cBuffer);i+=2)( g# \( D2 T# Y. r1 @# p
  111.     {4 N0 V, R! {1 O$ Q4 B- K3 B0 f
  112.       temp[0] = m_cBuffer[i];
    0 y0 |7 [8 y9 i" [
  113.       temp[1] = m_cBuffer[i + 1];
    0 @( l* w4 ^. H, p" l$ `! h+ k# D
  114.       temp[2] = '\0';
    $ R: l7 b8 @* g) p+ p* O: J  s& y
  115.       checksum += strtol(temp, &p, 16);
    / ]' s' Y- B5 G7 {( P* `
  116.       temp[0] = '\0';2 ^  q0 u+ A& U
  117.     }
    ; `6 m4 g, ]! U2 G8 p
  118.     checksum &= 0x00ff;//取计算结果的低8位
    1 ~' f4 l% v3 o) h+ N+ s8 }% h
  119.     if (checksum==0)//checksum为0说明接收的数据无误: k: s7 N( f9 Y3 [, t3 U! z
  120.     {
    8 L2 q# o+ l; v! h+ {6 p5 D5 g
  121.       cout << "RecordMark " << GetRecordMark() << endl;! B: k' \8 E- X9 m
  122.       cout << "RecordLength " << GetRecordLength() << endl;
    7 ~  [. X  B, w# \8 z" t
  123.       cout << "LoadOffset " << GetLoadOffset() << endl;
    0 h. l0 a9 t4 y; S* o' b
  124.       cout << "RecordType " << GetRecordType() << endl;: L/ C( r1 x% |; V
  125.       cout << "Data " << GetData() << endl;9 q/ F1 ]7 v6 C( g" G6 T
  126.       cout << "Checksum " << GetChecksum() << endl;
      X- d/ p) y; F7 L4 {/ ^, ]6 \  n
  127.     }
    / E& M* g2 h( V
  128.     else//否则接收数据有误4 O' ^4 s2 X* @4 r9 m: g
  129.     {5 K% q1 C+ _+ V  i  Y) V
  130.       cout << "Error!" << endl;
    % H7 n* z8 u& m
  131.     }6 f2 q3 \1 |7 l+ ^4 E( [
  132.     m_cBuffer[0] = '\0';! Q" f5 x# Y/ |# |
  133.     m_bRecvStatus = false;
    5 P8 ~4 {3 w! T1 Q
  134.     m_nRecordLength = 0;
    ; w5 a/ E% [! y' V
  135.     m_pLoadOffset = NULL;8 G8 o/ Z& v! d# {
  136.     m_pRecordType = NULL;( W& g% Y' f4 e7 W8 H' }/ l
  137.     m_pChecksum = NULL;
    0 q( s) x5 C2 T3 B
  138.     m_bRecvStatus = false;7 }0 {9 {8 g( z3 [! @
  139.   }
    ! y' e5 R3 `3 z0 K6 P
  140.   else if (m_bRecvStatus)
    9 ]5 d5 o8 P& H& c
  141.   {' y0 m2 P0 ^+ o: ]
  142.     m_cBuffer[buf_len] = ch;; ^$ `* g  Z# z8 |- [
  143.     m_cBuffer[buf_len + 1] = '\0';6 ?, U7 H- k1 i5 t' @/ L
  144.     //m_nIndex++;
    8 S  A8 }4 ~% j- W% K! _. Y
  145.   }/ F' l  e! {: l2 R* t( M
  146. }6 Q$ W2 }4 ]% |. o
  147. //解析Hex文件
    & H5 [  W4 p4 n5 M5 N
  148. void Hex::ParseHex(char *data)
    1 M- u# N/ L; r/ ]8 K  v2 n3 D
  149. {
    ) _( e! I  N2 J
  150.   for (int i = 0; i < strlen(data);++i)/ _& p1 q& ?  w) z& c& U/ X) J6 \
  151.   {. Q  m  z' B  k/ W1 i8 t: }
  152.     ParseRecord(data[i]);
    ' C. L% a# a* ]" D+ l+ Y- Q: N
  153.   }% J5 |$ N+ R" z* F2 Y1 B
  154. }/ F) O3 P6 E9 \0 c! c" g
  155. int main(int argc, char *argv[])
    " E) @9 R9 g5 O" I! A2 ]* a
  156. {  G' q" [) C* Z1 I
  157.   freopen("in.txt", "r", stdin);) N. F% I; k6 J
  158.   freopen("out.txt", "w", stdout);$ G6 p- \) p# f$ q9 ?; P' s

  159. # I; L& e7 J0 d/ r% H
  160.   Hex hex(':');, _9 d( W0 T9 q" k% C+ _9 R
  161.   char ch;  _+ f2 e- _" C* z
  162.   while (cin>>ch)! v' C: t8 l" @1 x
  163.   {+ s* N) \2 u! G  y, r: V& Z7 e
  164.     hex.ParseRecord(ch);: I2 Y+ Q# o- @, ~, ^: A  T
  165.   }
    7 O$ ]7 w, ~" s+ b+ U
  166.   fclose(stdout);
    & C7 M5 U* ^7 o; P4 L' o8 t
  167.   fclose(stdin);
    5 o: o, |5 i& `2 g# u
  168.   return 0;
    5 k5 w0 l/ ~7 J4 B2 i: S2 K
  169. }
复制代码

  _' K$ T% ?, s5 C$ _' T4 Y2 o- e
是不是这样呢?赶紧打开.hex文件来看一下吧。

+ J7 n/ n& P! ]8 q+ ]  F
赞 收藏 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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版