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

hex是如何解析的

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


一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得来。


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


三程序如何实现hex解析
经常会用到上位机软件来实现单片机的烧录,那上位机就要解析hex文件,程序如何实现hex文件的解析呢?

头文件代码如下所示:

  1. #ifndef _HEXLEXER_H_
  2. #define _HEXLEXER_H_
  3. #include <cstdio>
  4. #include <cstring>
  5. #include <cstdlib>
  6. /*
  7. Intel Hex文件解析器V1.0
  8. Hex文件的格式如下:
  9. RecordMark  RecordLength  LoadOffset  RecordType  Data  Checksum
  10. 在Intel Hex文件中,RecordMark规定为“:”
  11. */
  12. #pragma warning(disable:4996)
  13. #define MAX_BUFFER_SIZE 43
  14. class Hex
  15. {
  16. public:
  17.   Hex(char mark);
  18.   ~Hex();
  19.   void ParseHex(char *data);//解析Hex文件
  20.   void ParseRecord(char ch);//解析每一条记录
  21.   size_t GetRecordLength();//获取记录长度
  22.   char GetRecordMark();//获取记录标识
  23.   char *GetLoadOffset();//获取内存装载偏移
  24.   char *GetRecordType();//获取记录类型
  25.   char *GetData();//获取数据
  26.   char *GetChecksum();//获取校验和
  27.   
  28. private:
  29.   char m_cBuffer[MAX_BUFFER_SIZE];//存储待解析的记录
  30.   char m_cRecordMark;//记录标识
  31.   size_t m_nRecordLength;//记录长度
  32.   char *m_pLoadOffset;//装载偏移
  33.   char *m_pRecordType;//记录类型
  34.   char *m_pData;//数据字段
  35.   char *m_pChecksum;//校验和
  36.   bool m_bRecvStatus;//接收状态标识
  37.   //size_t m_nIndex;//缓存的字符索引值
  38. };

  39. Hex::Hex(char mark)
  40. {
  41.   this->m_cRecordMark = mark;
  42.   m_cBuffer[0] = '\0';
  43.   //m_pBuffer = NULL;
  44.   m_nRecordLength = 0;
  45.   m_pLoadOffset = NULL;
  46.   m_pRecordType = NULL;
  47.   m_pData = NULL;
  48.   m_pChecksum = NULL;
  49.   m_bRecvStatus = false;
  50.   //m_nIndex = 0;
  51. }

  52. Hex::~Hex()
  53. {
  54.   delete m_pLoadOffset, m_pRecordType, m_pData, m_pChecksum;
  55. }
  56. #endif
复制代码

代码如下所示。

  1. #include "HexLexer.h"
  2. #include <iostream>
  3. using namespace std;
  4. //获取记录标识
  5. char Hex::GetRecordMark()
  6. {
  7.   return this->m_cRecordMark;
  8. }
  9. //获取每条记录的长度
  10. size_t Hex::GetRecordLength()
  11. {
  12.   //char *len = (char*)malloc(sizeof(char)* 3);
  13.   if (strlen(m_cBuffer)>=2)
  14.   {
  15.     char len[3];
  16.     len[0] = m_cBuffer[0];
  17.     len[1] = m_cBuffer[1];
  18.     len[2] = '\0';
  19.     char *p = NULL;
  20.     return strtol(len, &p, 16);
  21.   }
  22.   else
  23.   {
  24.     return 0;
  25.   }
  26. }
  27. //获取装载偏移
  28. char* Hex::GetLoadOffset()
  29. {
  30.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
  31.   {
  32.     char *offset = (char*)malloc(sizeof(char)* 5);
  33.     for (int i = 0; i < 4; ++i)
  34.     {
  35.       offset[i] = m_cBuffer[i + 2];
  36.     }
  37.     offset[4] = '\0';
  38.     m_pLoadOffset = offset;
  39.     offset = NULL;
  40.   }
  41.   return m_pLoadOffset;
  42. }
  43. //获取记录类型
  44. char* Hex::GetRecordType()
  45. {
  46.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
  47.   {
  48.     char *type=(char*)malloc(sizeof(char)*3);
  49.     type[0] = m_cBuffer[6];
  50.     type[1] = m_cBuffer[7];
  51.     type[2] = '\0';
  52.     m_pRecordType = type;
  53.     type = NULL;
  54.   }
  55.   return m_pRecordType;
  56. }
  57. //获取数据
  58. char* Hex::GetData()
  59. {
  60.   if (strlen(m_cBuffer) == (GetRecordLength() + 5) * 2)
  61.   {
  62.     int len = GetRecordLength();
  63.     char *data = (char*)malloc(sizeof(char)*(len * 2 + 1));
  64.     for (int i = 0; i < len * 2;++i)
  65.     {
  66.       data[i] = m_cBuffer[i + 8];
  67.     }
  68.     data[len * 2] = '\0';
  69.     m_pData = data;
  70.     data = NULL;
  71.   }
  72.   return m_pData;
  73. }
  74. //获取校验和
  75. char* Hex::GetChecksum()
  76. {
  77.   int len = GetRecordLength();
  78.   if (strlen(m_cBuffer) == (len + 5) * 2)
  79.   {
  80.     char *checksum=(char*)malloc(sizeof(char)*3);
  81.     checksum[0] = m_cBuffer[(len + 5) * 2 - 2];
  82.     checksum[1] = m_cBuffer[(len + 5) * 2-1];
  83.     checksum[2] = '\0';
  84.     m_pChecksum = checksum;
  85.     checksum=NULL;
  86.   }
  87.   return m_pChecksum;
  88. }
  89. //解析Hex文件中的每一条记录
  90. void Hex::ParseRecord(char ch)
  91. {
  92.   size_t buf_len = strlen(m_cBuffer);
  93.   if (GetRecordMark()==ch)
  94.   {
  95.     m_bRecvStatus = true;
  96.     m_cBuffer[0] = '\0';
  97.     //m_nIndex = 0;
  98.     return;
  99.   }
  100.   if ((buf_len==(GetRecordLength()+5)*2-1))
  101.   {
  102.     //接收最后一个字符
  103.     m_cBuffer[buf_len] = ch;
  104.     m_cBuffer[buf_len + 1] = '\0';
  105.     //检验接收的数据
  106.     char temp[3];
  107.     char *p = NULL;
  108.     long int checksum = 0;
  109.     for (int i = 0; i < strlen(m_cBuffer);i+=2)
  110.     {
  111.       temp[0] = m_cBuffer[i];
  112.       temp[1] = m_cBuffer[i + 1];
  113.       temp[2] = '\0';
  114.       checksum += strtol(temp, &p, 16);
  115.       temp[0] = '\0';
  116.     }
  117.     checksum &= 0x00ff;//取计算结果的低8位
  118.     if (checksum==0)//checksum为0说明接收的数据无误
  119.     {
  120.       cout << "RecordMark " << GetRecordMark() << endl;
  121.       cout << "RecordLength " << GetRecordLength() << endl;
  122.       cout << "LoadOffset " << GetLoadOffset() << endl;
  123.       cout << "RecordType " << GetRecordType() << endl;
  124.       cout << "Data " << GetData() << endl;
  125.       cout << "Checksum " << GetChecksum() << endl;
  126.     }
  127.     else//否则接收数据有误
  128.     {
  129.       cout << "Error!" << endl;
  130.     }
  131.     m_cBuffer[0] = '\0';
  132.     m_bRecvStatus = false;
  133.     m_nRecordLength = 0;
  134.     m_pLoadOffset = NULL;
  135.     m_pRecordType = NULL;
  136.     m_pChecksum = NULL;
  137.     m_bRecvStatus = false;
  138.   }
  139.   else if (m_bRecvStatus)
  140.   {
  141.     m_cBuffer[buf_len] = ch;
  142.     m_cBuffer[buf_len + 1] = '\0';
  143.     //m_nIndex++;
  144.   }
  145. }
  146. //解析Hex文件
  147. void Hex::ParseHex(char *data)
  148. {
  149.   for (int i = 0; i < strlen(data);++i)
  150.   {
  151.     ParseRecord(data[i]);
  152.   }
  153. }
  154. int main(int argc, char *argv[])
  155. {
  156.   freopen("in.txt", "r", stdin);
  157.   freopen("out.txt", "w", stdout);

  158.   Hex hex(':');
  159.   char ch;
  160.   while (cin>>ch)
  161.   {
  162.     hex.ParseRecord(ch);
  163.   }
  164.   fclose(stdout);
  165.   fclose(stdin);
  166.   return 0;
  167. }
复制代码

是不是这样呢?赶紧打开.hex文件来看一下吧。

收藏 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 手机版