【转】hex和bin文件格式的区别
Intel HEX文件是记录文本行的ASCII文本文件,在Intel HEX文件中,每一行是一个HEX记录,由十六进制数组成的机器码或者数据常量。Intel HEX文件经常被用于将程序或数据传输存储到ROM、EPROM,大多数编程器和模拟器使用Intel HEX文件。
很多编译器的支持生成HEX格式的烧录文件,尤其是Keil c。但是编程器能够下载的往往是BIN格式,因此HEX转BIN是每个编程器都必须支持的功能。HEX格式文件以行为单位,每行由“:”(0x3a)开始,以回车键结束(0x0d,0x0a)。行内的数据都是由两个字符表示一个16进制字节,比如”01”就表示数0x01;”0a”,就表示0x0a。对于16位的地址,则高位在前低位在后,比如地址0x010a,在HEX格式文件中就表示为字符串”010a”。
下面为HEX文件中的一行:
:10000000FF0462FF051EFF0A93FF0572FF0A93FFBC
“:”表示一行的开始。 “:”后的第1,2个字符“10”表示本行包含的数据的长度,这里就是0x10即16个。 第3,4,5,6个字符“0000”表示数据存储的起始地址,这里表示从0x0000地址开始存储16个数据,其中高位地址在前,低位地址在后。 第7,8个字符“00”表示数据的类型。该类型总共有以下几种: 00 ----数据记录 01 ----文件结束记录 02 ----扩展段地址记录 04 ----扩展线性地址记录
这里就是0x00即为普通数据记录。自后的32个字符就是本行包含的数据,每两个字符表示一个字节数据,总共有16个字节数据跟行首的记录的长度相一致。最后两个字符表示校验码。每个HEX格式的最后一行都是固定为:
:00000001FF
以上的信息其实就足够进行HEX转BIN格式的程序的编写。首先我们只处理数据类型为0x00及0x01的情况。0x02表示对应的存储地址超过了64K,由于我的编程器只针对64K以下的单片机,因此在次不处理,0x04也是如此。
记录格式
一个Intel HEX文件可以包含任意多的十六进制记录,每条记录有五个域,下面是一个记录的格式:
:llaaaatt[dd...]cc
每一组字母是独立的一域,每一个字母是一个十六进制数字,每一域至少由两个十六进制数字组成,下面是字节的描述.
:冒号 是每一条Intel HEX记录的开始
ll 是这条记录的长度域,他表示数据(dd)的字节数目。
aaaa 是地址域,他表示数据的起始地址<如果是数据记录,这表示将要烧录的这条记录中的数据在EPROM中的偏移地址,对于不支持扩展段地址和扩展线性地址的,如89C51,这就是此条记录的起始地址>
tt 这个域表示这条HEX记录的类型,他有可能是下面这几种类型 00 ----数据记录 01 ----文件结束记录 02 ----扩展段地址记录 04 ----扩展线性地址记录
dd 是数据域,表示一个字节的数据,一个记录可能有多个数据字节,字节数目可以查看ll域的说明
cc 是效验和域,表示记录的效验和,计算方法是将本条记录冒号开始的所有字母对<不包括本效验字和冒号> 所表示的十六进制数字<一对字母表示一个十六进制数,这样的一个十六进制数为一个字节>都加起来然后模除256得到的余数,最后求出余数的补码,即是本效验字节cc。
<例如: :0300000002005E9D cc=0x01+NOT((0x03+0x00+0x00+0x00+0x02+0x00+0x5E)%0x100)=0x01+0x9C=0x9D
C语言描述: UCHAR cc; cc=(UCHAR)~(0x03+0x00+0x00+0x00+0x02+0x00+0x5E); cc++; >
数据记录
Intel HEX文件由若干个数据记录组成,一个数据记录以一个回车和一个换行结束<回车为0x0d换行为0x0a> 比如下面的一条数据记录 :10246200464C5549442050524F46494C4500464C33 10 是此行记录数据的字节数目 2462 是数据在内存<将要烧写的eprom地址>中的起始地址 00 是记录类型00(是一个数据记录) 464C 到 464C 是数据 33 是此行记录的效验和
扩展线性地址记录(HEX386) 扩展线性地址记录也可称为32位地址记录/HEX386记录,这个纪录包含高16(16-31位)位数据地址,这种扩展的线性记录总是有两个字节数据,像下面这样: :02000004FFFFFC 02 是记录的数据字节数目 0000 是地址域,这在扩展地址记录中总是0000 04 是记录类型04(扩展地址记录) FFFF 是高16位地址 FC 是记录效验和,计算方法如下: 01h + NOT(02h + 00h + 00h + 04h + FFh + FFh) 当一个扩展线性地址记录被读到后,扩展线性地址记录的数据区域将被保存,并应用到后面从Intel HEX文件中读出的记录,这个扩展线性记录一直有效,直到读到下一个扩展线性记录。 绝对内存地址 = 数据记录中的地址 + 移位后的扩展线性地址 下面举例说明这个过程:从数据记录的地址域得到地址 2462,从扩展线性地址记录的地址域得到地址 FFFF,绝对内存地址 FFFF2462
扩展段地址记录 (HEX86)
扩展段地址记录也被称为HEX86记录,包含 4-19位的数据地址段,这个扩展段地址记录总是有两字节数据,如下: :020000021200EA 02 是 记录中的数据字节数目 0000 是地址域,在扩展段地址记录中,这个域总是0000 02 是记录类型,02(扩展段地址的标示) 1200 是该段的地址 EA 是效验和 计算如下: 01h + NOT(02h + 00h + 00h + 02h + 12h + 00h). 当扩展段地址记录被读后,扩展段地址将被存储并应用到以后从Intel HEX文件读出的记录,这个段地址一直有效直到读到下一个扩展段地址记录 绝对内存地址 = 数据记录中的地址 + 移位后的扩展段地址 数据记录中的地址域,移位后扩展段地址记录中的地址域。 下面举例说明这个过程:从数据记录的地址域得到地址 2 4 6 2,从扩展段地址记录的地址域得到地址 1 2 0 0,绝对内存地址 0 0 0 1 4 4 6 2
文件结束记录(EOF) 一个Intel HEX文件必须有一个文件结束记录,这个记录的类型域必须是01, 一个EOF记录总是这样: :00000001FF 00是记录中数据字节的数目 0000这个地址对于EOF记录来说无任何意义 01记录类型是01(文件结束记录标示) FF是效验和计算如下:01h + NOT(00h + 00h + 00h + 01h).
格式:BBAAAATTHHHH...HHHHCC
BB: Byte AAAA:数据记录的开始地址,高位在前,地位在后。因为这个格式只支持8bits,地址被倍乘。所以,为了得到实际的PIC的地址,需要将地址除以2 TT: Type 00 数据记录 01 记录结束 04 扩展地址记录(表示32位地址的前缀,当然这种只能在 INHX32) HHHH:一个字(Word)的数据记录,高Byte在前,低Byte在后。TT之后,总共有 BB/2 个字 的数据 CC: 一个Byte的CheckSum
因为PIC16F873A只有4K的程序空间,所以,不会有 TT=04的 Linear Address Record
hex和bin文件格式 Hex文件,这里指的是Intel标准的十六进制文件,也就是机器代码的十六进制形式,并且是用一定文件格式的ASCII码来表示。具体格式介绍如下: Intel hex 文件常用来保存单片机或其他处理器的目标程序代码。它保存物理程序存储区中的目标代码映象。一般的编程器都支持这种格式。
Intel hex 文件全部由可打印的ASCII字符组成,如下例所示:
:2000000012014c75a800e4f508f509780a7a78e4f608dafcd283fcfded240af9a7050dbd81 :2000200000010ced2488ec34ff50edc283e4fcfded240af9e76d7013ed33e43c700d0dbd2a :2000400000010ced2488ec34ff50e50509e50970020508e50924a8e50834fd50aee4f50874
Intel hex 由一条或多条记录组成,每条记录都由一个冒号“:”打头,其格式如下:
:CCAAAARR...ZZ
其中: CC 本条记录中的数据字节数
AAAA 本条记录中的数据在存储区中的起始地址
RR 记录类型: 00 数据记录 (data record) 01 结束记录 (end record) 02 段记录 (paragraph record) 03 转移地址记录 (transfer address record)
... 数据域
ZZ 数据域校验和
校验值:每一行的最后一个值为此行数据的校验和。例如:
:1000000018F09FE518F09FE518F09FE518F09FE5C0 这行中的 0xC0
:1000100018F09FE5805F20B9F0FF1FE518F09FE51D 这行中的 0x1D
校验和的算法为:计算从0x3A 以后(不包括0x3A)的所有各字节的和模256的余。即各字节二进制算术和,不计超过256的溢出值,然后用0x100减去这个算数累加和,得出得值就是此行得校验和。
Intel hex文件记录中的数字都是16进制格式,两个16进制数字代表一个字节。CC域是数据域中的实际字节数,地址、记录类型和校验和域没有计算在内。校验和是取记录中从数据字节计数域(CC)到数据域(...)最后一个字节的所有字节总和的2的补码。
而Bin文件是最纯粹的二进制机器代码,没有格式,或者说是"顺序格式"。按assembly code顺序翻译成binary machine code。由于分析出来Hex文件中的数据域ASCII码表示的十六进制与二进制一一对应,而且我公司DSP又是16位的,以一个word为最小单位,所以四个十六进制ASCII码代表一条机器指令单位或者地址,借于上面分析,编写了工具代码。大体原理是用fscanf函数在每行的数据域读入四个ASCII码,以短整形(short int 16bit)形式储存,在把这个短整形变量顺序fwrite到文件流中去即可。
举一例说明: 表1

- ORG 0000H
- LJMP START
- ORG 040H
- START:
- MOV SP, #5FH ;设堆栈
- LOOP:
- NOP
- LJMP LOOP ;循环
- END ;结束

表2
- :03000000020040BB
- :0700400075815F000200431F
表3
- 02 00 40 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF FF FF FF FF 75 81 5F 00 02 00 43
表1为源程序,表2是汇编后得到的HEX文件,表3是由HEX文件转换成的目标文件,也就是最终写入EPROM的文件,它由编程器转换得到,也可以由 HEXBIN一类的程序转换得到。学过手工汇编者应当不难找出表3与表1的一一对应关系,值得注意的是从02 00 40后开始的一长串‘FF’,直到75 81,这是由于伪指令:ORG 040H造成的结果。

- /*
- 使用方法 : bin2hex -b adress filename
- -b : 指示hex文件起始地址
- address : hex文件的起始地址(FIXME:当前版本只支持k字节边界)
- filename: 待转换的文件名
- 示例 : bin2hex -b 32k rom.bin
- */
- #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;
- len = strlen(buf);
- if ((buf[len-1] != 'k') && (buf[len-1] != 'K')) {
- printf ("Invalid argument.\n");
- exit (-1);
- }
- buf[len-1] = 0;
- start_adr = atoi (buf);
- start_adr = start_adr * 1024;
- cur_base = 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 != 4) {
- printf ("Usage : %s -b address filename.xxx\n", argv[0]);
- printf ("-b : indicate the starting address convert to.\n");
- printf ("address : starting address.\n");
- printf ("filename.xxx : file to be converted.\n");
- printf ("output : filename.hex\n");
- printf ("example : %s -b 64k rom.bin\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 ("rom.hex", "w");
- if (fp_write == NULL) {
- printf ("Can't create file rom.hex");
- return -1;
- }
- calc_start_adr (argv[2]);
- start_convert ();
- fclose (fp_read);
- fclose (fp_write);
- printf("Convert Seccessfully!\n");
- return 0;
- }
【转】hex和bin文件格式的区别的更多相关文章
- hex和bin文件格式的区别
Intel HEX文件是记录文本行的ASCII文本文件,在Intel HEX文件中,每一行是一个HEX记录,由十六进制数组成的机器码或者数据常量.Intel HEX文件经常被用于将程序或数据传输存储到 ...
- HEX和BIN文件的区别
以下的内容是从网上转载来的,原文地址:http://blog.csdn.net/zhangliang_571/article/details/8519469 在这里感谢原作者. 1,是在keil中编 ...
- .hex文件和.bin文件的区别
博客转之于: http://mini.eastday.com/a/160627003502858.html HEX文件和BIN文件是我们经常碰到的2种文件格式.下面简单介绍一下这2种文件格式的区别: ...
- Hex、bin、axf、elf格式文件小结
转自Hex.bin.axf.elf格式文件小结 一.HEX Hex文件,一般是指Intel标准的十六进制文件.Intelhex 文件常用来保存单片机或其他处理器的目标程序代码.它保存物理程序存储区中的 ...
- bin/bash 和 /bin/sh 的区别
今天在用ssh Secure shell 连接虚拟机中的Ubuntu编写程序时,想比对一下两个源代码有什么差别,但是在一个ssh 客户端下不断的切换很是费劲.于是想着在主机中再添加一个用户.我原本用s ...
- bin文件格式分析
xip 的 bin 文件分析 一个bin 文件在存储上是按以下的结构存储的 组成:标记(7)+Image開始地址(1)+Image长度(1) 记录0地址+记录0长+记录0校验和+ ...
- /bin/sh 与 /bin/bash 的区别
/bin/sh 与 /bin/bash 的区别,用 : 截取字符串不是POSIX 标准的. 区别 sh 一般设成 bash 的软链 (symlink) ls -l /bin/sh lrwxrwxrwx ...
- linux 下 /bin /sbin 的区别
/bin,/sbin,/usr/bin,/usr/sbin区别 / : this is root directory root 用户根目录 /bin : command ...
- Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区别
这个网址 https://www.cnblogs.com/scofi/p/4867851.html 讲述了Python 头部 #!/usr/bin/python 和 #!/usr/bin/env 的区 ...
随机推荐
- 验证码处理类:UnCodebase.cs + BauDuAi 读取验证码的值(并非好的解决方案)
主要功能:变灰,去噪,等提高清晰度等 代码类博客,无需多说,如下: public class UnCodebase { public Bitmap bmpobj; public UnCodebase( ...
- 《Head First 设计模式》例子的C++实现(1 策略模式)
最近在学习设计模式,用的是 <Head First 设计模式>这本书.感觉这本书写的还是很不错的,深入浅出的介绍了各种常用的设计模式.唯一有点不方便的地方是这本书的例子全都是用的 Java ...
- java 双因素认证(2FA)TOTP demo
TOTP 的全称是"基于时间的一次性密码"(Time-based One-time Password).它是公认的可靠解决方案,已经写入国际标准 RFC6238. 很早就知道有这个 ...
- 【JVM.12】线程安全与锁优化
一.概述 面向过程的编程思想极大地提升了现代软件开发的生产效率和软件可以达到的规模,但是现实世界与计算机世界之间不可避免地存在一些差异,本节就如何保证并发的正确性和如何实现线程安全讲起. 二.线程安全 ...
- Spring+SpringMVC+MyBatis整合(easyUI、AdminLte3)
实战篇(付费教程) 花了几天的时间,做了一个网站小 Demo,最终效果也与此网站类似.以下是这次实战项目的 Demo 演示. 登录页: 富文本编辑页: 图片上传: 退出登录: SSM 搭建精美实用的管 ...
- JS_各种排序方法
排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则应采 ...
- Timer计时不准确的问题及解决方法
在项目中,需要每隔20ms发送一个RTP数据包.一开始使用的是System.Windows.Forms下的Timer类,但是发现明显延迟了.用StopWatch测了一下,发现它的触发间隔居然不是20m ...
- Jmeter(非GUI模式)教程
前言 使用非 GUI 模式,即命令行模式运行 JMeter 测试脚本能够大大缩减所需要的系统资源.优点如下:1.节约系统资源:无需启动界面,节约系统资源 2.便捷快速:仅需启动命令行,输入命令便可执行 ...
- Notes of Daily Scrum Meeting(12.25)
今天在学姐的帮助下,我们终于把网络连接的部分连通了,这对我们是一个很大的鼓舞,也找到了前期 连不通的问题在哪里,这让我们重新有了进行下去的勇气和决心,我们会在最后这几天把前端和后端结合, 做出我们最后 ...
- APP推广(预期方案)
首先,在推广过程中有一些定的弊端:我们这个O2O平台暂时只能适用于学校局域网. 因为我们的APP才刚刚“出炉”不久,在网络上还是属于一篇空白的状态,我们想过可以在百度百科上进行相应的推广,如果有用户搜 ...