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

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个回答
Cinderella6 回答时间:2020-10-23 09:26:10
mark~~~~~
heart蓝色CD 回答时间:2020-10-23 20:04:40
不错

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

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