大家好,我是学电子的小白白。

熟悉单片机开发的朋友,应该经常见到*.hex后缀的文件,它是单片机和嵌入式工程编译输出的一种常见的目标文件格式(比如keil就能编译输出hex文件),通过烧写工具把它下载到单片机中,程序就能在芯片中运行。

有些时候,比如我们在自己实现IAP时,又需要把编译后的目标文件转成*.bin文件的格式,才能往单片机中传输,之后bootloader程序会将接收到的bin文件固化到芯片中。

那么,hex文件和bin文件有什么区别呢,为什么有时用hex格式有时用bin格式?本篇文章就带大家来了解一下。

1)hex文件格式

这里,我在keil中编写了一个极简的LED闪烁程序,在keil中需要勾选输出hex设置:

如果不勾选,只会输出默认的axf格式目标文件。

编译之后,就可以输出hex格式的目标文件了,我们用普通的文本编辑器就可以打开hex目标文件,可以看到如下内容:

我们解释一下文件的内容:

a)hex文件内部是以文本格式来存储内容的,每行以冒号(:)起始,后面每两个字母是一个8bit的16进制数;

b)每行的格式:BBAAAATTD……DCC;

BB表示本行数据的长度;AAAA表示本行数据存储的地址;TT表示数据类型;DD的长度可长可短,是实际的数据;CC是校验和;

我们以第一行为例:020000040800F2

02是数据长度,也就是后面的实际数据“0800”的长度,2字节;

0000表示地址0;

04是数据类型,后面在详细解释;

0800是实际的数据;

F2是校验和,计算方法是,本行所有字节累加和(累加和只用低8位)取反再加1,即计算过程为0xF2=0x01 + not(0x02+0x04+0x08);

c)这里需要补充说明的是TT表示的数据类型

数据类型一共有6种形式:

'00'数据记录:用来记录数据,HEX文件的大部分记录都是数据记录;

'01'文件结束记录:用来标识文件结束,放在文件的最后,标识HEX文件的结尾;

'02'扩展段地址记录:用来标识扩展段地址的记录;

'03'开始段地址记录:开始段地址记录;

'04'扩展线性地址记录:用来标识扩展线性地址的记录;

'05'开始线性地址记录:开始线性地址记录;

这里仍然举几个例子说明,第一行:020000040800F2的数据类型是04,即扩展线性地址记录,表示的是这样一行的内容是地址的高位,也即DD区域表示地址高位为0x0800;当地址长度超过16bit时,就需要扩展线性地址记录来声明高位地址;

第二行:10000000000400200900000800F009F800F01CF8C6,数据类型是00,也就是数据记录,那么它的DD区域就是数据;同时,它的地址区域是0000,那么就表示,这一行的数据应该存在0000地址中;再结合上一行的扩展线性地址记录,它实际存储的地址应该是0x08000000。熟悉stm32单片机的朋友可能清楚,flash起始地址就是0x08000000:

第三行:1000100000F026F800F01EF800F022F8F6E703B52D,格式与第二行一样,但是地址不同,表示这一行的数据存在0x08000010地址中;我们发现这两地址相隔0x10,刚好是第一行的数据内容实际长度。

倒数第三行,格式与第二、三行也是一样的,只是长度不足0x10,只有0x08,这是已经到了实际内容的末尾。

Hex文件内大部分都是这种数据记录。

d)最后两行

:0400000508000009E6

:00000001FF

我们先解释末尾一行,:00000001FF,这行是表示文件结尾,所有的hex文件最后一行都可以是这个。

倒数第二行,数据类型是05,开始线性地址记录,其实它表示的是一个函数入口地址,但是这个函数地址并不会影响实际烧写到flash中的内容,我们可以不管它,MDK官方的解释是大多数情况下可以忽略它:

The Start Linear Address specifies the address of the __main (pre-main) function but not the address of the startup code which usually calls __main after calling SystemInit(). An odd linear start address specifies that __main is compiled for the Thumb instruction set.

The Start Linear Address Record can appear anywhere in hex file. In most cases this record can be ignored because it does not contain information which is needed to program flash memory.

到这里,hex文件中常见的一些格式就介绍完了,如果需要研究更深入,可以通过http://www.keil.com/support/docs/1584/

找到keil官方的解析(这个链接好像已经404了,可以在文末关注公*众*号找到保存的原文档)。

我们在做有IAP功能的项目时,有时需要把boot和app两段代码合并以后烧写,这样可以大大简化操作步骤,此时,可以把两个hex文件手动合并。

操作方法是,把其中一个hex文件最后的两行(开始线性地址记录、文件结束记录)删除:

再把另一个hex文件的所有内容都复制粘贴到其后,就可以了。

但是要注意,两个文件的地址区不能有重叠!

2)bin文件格式

相比hex文件,bin文件格式就简单得多了,它直接就是保存的需要烧写的目标文件内容,是没有任何附加格式的原始二进制文件。

我们把上一个工程设置为输出bin文件:

再编译输出,可以同时输出bin格式的目标文件。

使用十六进制文件编辑器打开,可以看到如下内容:

对比之前的hex文件格式,发现这些内容正好对应了hex文件中所有“数据记录”行中的实际数据内容。没有地址、校验、文件结尾等等一些附加内容。

3)hex文件和bin文件的对比和转换

通过前述的解释,我们了解了,bin文件只有最原始的程序数据,它与保存在单片机flash中的原始值是一样的;hex文件中,则除了程序数据外,还包含了地址、校验等等一些信息。

所以,一般在自己设计IAP程序时,直接传输bin文件可以简化bootloader软件的设计,减少一些处理过程,缩小boot程序的体积,但是要注意需要事先规定写入的地址;而通过上位机软件和下载器烧写时,使用hex文件,可以简化操作、增加可靠性。

一般软件IDE都可以生成hex文件,有的也能生成bin文件,如上文中提到的keil;st公司出品的STM32CubeProgrammer也可以将hex转bin。

如果软件没有这个功能,我们也不用重复造轮子,有很多前辈大佬已经做了转换工具,我们可以使用现成的。

我试用了多种,选了比较好用的一种hex转bin文件工具推荐给大家:

这个软件由“不咸不要钱”大佬编写,该大佬的软件开源地址:GitHub - mian2018/CSharp_Hex2Bin: 嵌入式 hex转bin

如果打不开,我在网盘里保存了一份,可以在我的公众号里找到网盘下载地址。

想要把bin文件转换为hex文件,就需要增加一些内容了,因为hex文件中比bin文件多的内容主要就是地址信息。

这里我也找了一个软件来转换,需要敲命令行,输入地址和文件名:

源码如下,也可在我的公众号里找到网盘下载地址。

/*使用方法 : bin2hex -b adress filename output-b : 指示hex文件起始地址address : hex文件的起始地址(输入4字节十六进制地址)filename : 待转换的文件名output : 输出文件名示例 : bin2hex -b 0x08000000 rom.bin out.hex
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *fp_read;               /* 待读取文件句柄 */
FILE *fp_write;              /* 待写入文件句柄 */unsigned long start_adr;     /* 转换成Hex格式的起始地址 */
unsigned short cur_base;     /* 转换成Hex格式的当前地址高16位 */
unsigned short cur_offset;   /* 转换成Hex格式的当前地址低16位 */
unsigned char read_buf[16];
unsigned char write_buf[48];void calc_start_adr (char *buf)
{unsigned int len,i;char *str;char c;len = strlen(buf);if ((buf[0] == '0') && ((buf[1] == 'x')||(buf[1] == 'X'))){buf[1] = '0';}for(i=0; i<len; i++){c = buf[i];if ((c >= '0') && (c <= '9')){}else if((c >= 'A') && (c <= 'F')){}else if((c >= 'a') && (c <= 'f')){}else{printf ("Invalid argument.\n");exit (-1);}}/*十六进制字符串转换为地址*/start_adr = strtol(buf, &str, 16);cur_base =   (unsigned short)(start_adr >> 16);cur_offset = (unsigned short)start_adr;
}void start_convert (void)
{unsigned char cnt;unsigned char read_num;unsigned char cksum, highc, lowc;/* 设置当前地址高16位 */highc = cur_base >> 8;lowc = (unsigned char)cur_base;cksum = 2 + 4 + highc + lowc;cksum = 0xFF - cksum;cksum = cksum + 1;sprintf (write_buf, ":02000004%04X%02X", cur_base, cksum);write_buf[15] = 0x0D;write_buf[16] = 0x0A;fwrite (write_buf, 1, 17, fp_write);read_num = fread (read_buf, 1, 16, fp_read);while (read_num == 16){/* 写入读取的16字节 */highc = cur_offset >> 8;lowc = (unsigned char)cur_offset;cksum = 0x10 + highc + lowc;for (cnt=0; cnt<16; cnt++){cksum += read_buf[cnt];}cksum = 0xFF - cksum;cksum = cksum + 1;sprintf (write_buf, ":10%02X%02X00%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",highc, lowc,read_buf[0], read_buf[1], read_buf[2], read_buf[3],read_buf[4], read_buf[5], read_buf[6], read_buf[7],read_buf[8], read_buf[9], read_buf[10], read_buf[11],read_buf[12], read_buf[13], read_buf[14], read_buf[15],cksum);write_buf[43] = 0x0D;write_buf[44] = 0x0A;fwrite (write_buf, 1, 45, fp_write);/* 计算当前地址低16位,当越限时写入当前地址高16位 */if (cur_offset == 65520){cur_offset = 0;cur_base ++;highc = cur_base >> 8;lowc = (unsigned char)cur_base;cksum = 2 + 4 + highc + lowc;cksum = 0xFF - cksum;cksum = cksum + 1;sprintf (write_buf, ":02000004%04X%02X", cur_base, cksum);write_buf[15] = 0x0D;write_buf[16] = 0x0A;fwrite (write_buf, 1, 17, fp_write);}else{cur_offset += 16;}read_num = fread (read_buf,1,16,fp_read);}/* 写入剩余的字节 */if (read_num){highc = cur_offset >> 8;lowc = (unsigned char)cur_offset;cksum = read_num + highc + lowc;for (cnt=0; cnt<read_num; cnt++){cksum += read_buf[cnt];}cksum = 0xFF - cksum;cksum = cksum + 1;sprintf (write_buf, ":%02X%02X%02X00", read_num, highc, lowc);for (cnt=0; cnt<read_num; cnt++){sprintf (&write_buf[9 + cnt * 2], "%02X", read_buf[cnt]);}sprintf (&write_buf[9 + cnt * 2], "%02X", cksum);write_buf[11 + read_num * 2] = 0x0D;write_buf[12 + read_num * 2] = 0x0A;fwrite (write_buf, 1, 13 + read_num * 2, fp_write);}/* 写入终止序列 */sprintf (write_buf, ":00000001FF");write_buf[11] = 0x0D;write_buf[12] = 0x0A;fwrite (write_buf, 1, 13, fp_write);
}int main (int argc, char *argv[])
{if (argc != 5){printf ("Usage : %s -b address filename output\n", argv[0]);printf ("-b : indicate the starting address convert to.\n");printf ("address : starting address.\n");printf ("filename : file to be converted.\n");printf ("output :   file to output\n");printf ("example : %s -b 0x08003000 input.bin output.hex\n", argv[0]);return -1;}if (strcmp (argv[1], "-b")){printf ("Invalid argument.\n");return -1;};fp_read = fopen (argv[3], "rb");if (fp_read == NULL){printf ("Can't open file %s", argv[3]);return -1;}fp_write = fopen (argv[4], "wb");if (fp_write == NULL){printf ("Can't create file %s",argv[4]);return -1;}calc_start_adr (argv[2]);start_convert ();fclose (fp_read);fclose (fp_write);printf("Convert Seccessfully!\n");return 0;
}

好了,本节内容就分享到这里了。

如果觉得有用,欢迎大家关注我,下载相关的学习资源和软件代码:

hex文件格式剖析,以及hex与bin文件互相转换相关推荐

  1. hex文件格式解析,hex转bin(C语言)

    前言 hex转bin文件网上有很多现成的工具,但还是想了解下其中的数据结构跟原理 区别 hex跟bin都是程序烧写的文件,那他们有什么不同呢? 首先看大小,hex文件都会大于bin文件,hex文件打开 ...

  2. bin文件怎么转换成文本文档_怎么把视频文件转换成MP3?这款工具六步帮你实现...

    在我们的生活当中,如果我们在看视频的时候,碰到了一则带有背景音乐的视频,此时我们不需要视频上的画面内容,只想要保留视频里的音乐的话,那么我们就需要通过将视频转换成MP3音频格式文件,才能够获得视频当中 ...

  3. bin文件怎么转换成文本文档_Python脚本4:根据txt文本,批量创建文件夹

    背景:深度学习图像分类的时候,有许多的标签类.1000个标签就需要创建1000个文件夹,文件夹里面放入对应的图像.不可能一个一个右击创建文件夹,所以有了今天的脚本.根据txt文本每一行的类别,创建文件 ...

  4. bin文件怎么转换成文本文档_怎么把pdf文件转换成word文档?这样转很简单

    在日常的学习.工作生活中,小伙伴们总少不了要对文件格式进行转换操作,例如把pdf文件转换成word文档.对于职场老手来说,这当然不算一个难度操作,甚至还很简单.但对于职场新人而言,找不对方法,可能操作 ...

  5. keil编译器如何生成二进制bin文件

    keil编译器默认生成的是16进制的hex文件,但是有时候需要生成二进制的bin文件,可以使用kei自带的二进制转换工具来实现. 首先在keil安装目录中找到 ARMCC文件夹,然后打开里面bin文件 ...

  6. c语言文本文件转换程序,C语言数组转换为BIN文件工具下载

    C2B转换助手是ALIENTEK开发的一个C语言数组(仅支持十六进制数组)到BIN文件的转换工具,非常适合将一些大的数组转换为BIN文件,存放在SD卡或者片外FLASH中,从而大大降低对MCU的FLA ...

  7. hex文件和bin文件区别

    HEX文件和BIN文件是我们经常碰到的2种文件格式.因为自己也是新手,所以一直对这两个文件懵懵懂懂,不甚了解,最近在做STM32单片机的IAP更新,其中要考虑HEX文件和BIN文件,所以需要学习下这两 ...

  8. C# 学习笔记(12)hex文件转bin文件小工具

    C# 学习笔记(12)hex文件转bin文件小工具 hex文件格式 hex文件格式网上有很多 我这里参考HEX文件格式详解https://blog.csdn.net/weixin_39752827/a ...

  9. 各种烧写文件格式简介-ELF Hex Bin axf

    转载地址:http://blog.chinaunix.net/uid-20321537-id-1966794.html 一,ELF Executable and linking format(ELF) ...

最新文章

  1. 死前真的会有「跑马灯」,人类首次同步测量大脑濒死状态
  2. 目标跟踪_POI算法
  3. Linux获取执行文件路径,如何 获取linux进程的执行文件路径
  4. 罗永浩回应做主播赚钱还债;360 否认裁员;Kubernetes 1.18 版本发布| 极客头条
  5. 门户网站CDN实战优化教学案例分享
  6. apktool java_apktool 是GOOGLE提供的APK编译工具,需要JAVA运行环境,推荐使用JDK1.6或者JDK1.7...
  7. 卡塔尔能源每年将向中石化供应400万吨液化天然气;哪吒汽车发布技术品牌浩智 | 美通企业日报...
  8. PAT甲级 1031
  9. 《动手学深度学习》(PyTorch版)代码注释 - 48 【Multi-scale_target_detection】
  10. 计算机第一次月考试题,计算机基础第一次月考试题.doc
  11. Mybatis 官网地址
  12. HDFS启动报错Expected to be able to read up until at least txid but unable to find any edit logs
  13. 如何成为某一领域的高手
  14. 背光的工作原理及结构
  15. html中js正则表达式手机,js验证电话号码与手机支持+86的正则表达式
  16. C++ sizeof(struct)计算结构体大小
  17. linux mii 调试总结
  18. Java+SpringBoot+vue+elementui在线答疑网站系统mysql maven毕业设计
  19. 语音问答机器人小程序
  20. 南邮考研计算机组成原理真题,南京邮电大学408计算机学科专业基础综合(含数据结构、计算机组成原理、操作系统和计算机网络)考研资料...

热门文章

  1. 分类效果评价(机器学习)
  2. CMAP是否可以使用RemoveAll()释放内存?CMAP如何释放内存?
  3. 域服务器用户一直被锁,Windows Server 2019 域用户账户锁定策略
  4. 肺肠轴——看不见的Crosstalk
  5. 验证银行卡卡号是否符合规则
  6. python中怎么画一个机器猫_如何用Python画一只机器猫?
  7. Java中阻塞队列类型介绍
  8. 192、如何查询局域网内在线的监控设备IP
  9. 文字前带小点点的样式代码
  10. 社保入税+国家支持,企业一大法宝:灵活用工