hex和bin文件格式区别

1.hex介绍

Hex 全称 (Intel HEX)文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制编码数字组成。Intel HEX文件通常用于传输将被存于ROM或者EPROM中的程序和数据。大多数EPROM编程器或模拟器使用Intel HEX文件。

2.hex与bin文件的区别

  • HEX文件是包括地址信息的,而BIN文件格式只包括了数据本身,在烧写或下载HEX文件的时候,一般都不需要用户指定地址,因为HEX文件内部的信息已经包括了地址。而烧写BIN文件的时候,用户是一定需要指定地址信息的。

  • BIN文件格式,对二进制文件而言,其实没有”格式”。文件只是包括了纯粹的二进制数据。

3.hex文件格式

记录格式

一个Intel HEX文件可以包含任意多的十六进制记录,每条记录有五个域,下面是一个记录的格式:

:llaaaatt[dd...]cc

每一组字母是独立的一域,每一个字母是一个十六进制数字,每一域至少由两个十六进制数字组成,下面是字节的描述.

:冒号 是每一条Intel HEX记录的开始

ll 是这条记录的长度域,他表示数据(dd)的字节数目。

aaaa 是地址域,他表示数据的起始地址<如果是数据记录,这表示将要烧录的这条记录中的数据在EPROM中的偏移地址,对于不支持扩展段地址和扩展线性地址的,如89C51,这就是此条记录的起始地址>

tt 这个域表示这条HEX记录的类型,他有可能是下面这几种类型 00 ----数据记录 01 ----文件结束记录 02 ----扩展段地址记录 04 ----扩展线性地址记录

dd 是数据域,表示一个字节的数据,一个记录可能有多个数据字节,字节数目可以查看ll域的说明

cc 是效验和域,表示记录的效验和,计算方法是将本条记录冒号开始的所有字母对<不包括本效验字和冒号> 所表示的十六进制数字<一对字母表示一个十六进制数,这样的一个十六进制数为一个字节>都加起来然后模除256得到的余数,最后求出余数的补码,即是本效验字节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).

4.程序如下

hex2bin.h

#ifndef HEX2BIN_H
#define HEX2BIN_H

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;

#define HEX_MAX_LENGTH		521
#define HEX_MIN_LEN		11

typedef enum {
	RES_OK = 0,		//正确
	RES_DATA_TOO_LONG,	//数据太长
	RES_DATA_TOO_SHORT,	//数据太短
	RES_NO_COLON,		//无标号
	RES_TYPE_ERROR,		//类型出错,或许不存在
	RES_LENGTH_ERROR,	//数据长度字段和内容的总长度不对应
	RES_CHECK_ERROR,	//校验错误
	RES_HEX_FILE_NOT_EXIST,	//HEX文件不存在
	RES_BIN_FILE_PATH_ERROR,//BIN文件路径可能不正确
	RES_WRITE_ERROR,	//写数据出错
	RES_HEX_FILE_NO_END	//hex文件没有结束符
} RESULT_STATUS;

typedef struct {
	uint8_t len;
	uint8_t	type;
	uint16_t addr;
	uint8_t *data;
} BinFarmat;

RESULT_STATUS HexFile2BinFile(char *src, char *dest);
#endif

hex2bin.c

#include "hex2bin.h"
#include 
#include 
/********************************************************************************
input:
c:单个字符('0'~'9' 'a'~'f', 'A'~'F')
output:
单个字符转化为单个字符
********************************************************************************/
static uint8_t HexCharToBinBinChar(char c)
{
	if (c >= '0' && c <= '9')
		return c - '0';
	else if (c >= 'a' && c <= 'z')
		return c - 'a' + 10;
	else if (c >= 'A' && c <= 'Z')
		return c - 'A' + 10;
	return 0xff;
}

/********************************************************************************
input:
p: 两个文本字符
output:
转化为1个字节
********************************************************************************/
static uint8_t Hex2Bin(const char *p)
{
	uint8_t tmp = 0;
	tmp = HexCharToBinBinChar(p[0]);
	tmp <<= 4;
	tmp |= HexCharToBinBinChar(p[1]);
	return tmp;
}

/********************************************************************************
input:
src: hex单行字符串
p->type: 如果函数返回结果正确,这里就存着转化后的类型
p->len: 如果函数运行正确,这里就存着转化后的bin数据长度
p->data: 如果函数运行正确,长度并且不为0,该指针就只想转化后的数据
p->addr[0]: 如果函数返回结果正确,这里就存着地址的低字节
p->addr[1]: 如果函数返回结果正确,这里就存着地址的低字节
output:
返回hex格式流分析的结果
********************************************************************************/
static RESULT_STATUS HexFormatUncode(const char *src, BinFarmat *p)
{
	uint8_t check = 0, tmp[4], binLen;
	uint16_t hexLen = strlen(src);
	uint16_t num = 0, offset = 0;
	if (hexLen > HEX_MAX_LENGTH)		//数据内容过长
		return RES_DATA_TOO_LONG;
	if (hexLen < HEX_MIN_LEN)
		return RES_DATA_TOO_SHORT;	//数据内容过短
	if (src[0] != ':')
		return RES_NO_COLON;		//没有冒号
	if ((hexLen - 1) % 2 != 0)
		return RES_LENGTH_ERROR;	//hexLen的长度应该为奇数
	binLen = (hexLen - 1) / 2;		//bin总数据的长度,包括长度,地址,类型校验等内容
	while (num < 4)
	{
		offset = (num << 1) + 1;
		tmp[num] = Hex2Bin(src + offset);
		check += tmp[num];
		num++;
	}
	p->len = tmp[0];			//把解析的这些数据保存到结构体中
	p->addr = tmp[1];
	p->addr <<= 8;
	p->addr += tmp[2];
	p->type = tmp[3];
	while (num < binLen)
	{
		offset = (num << 1) + 1;        //保存真正的bin格式数据流
		p->data[num - 4] = Hex2Bin(src + offset);
		check += p->data[num - 4];
		num++;
	}
	if (p->len != binLen - 5)		//检查hex格式流的长度和数据的长度是否一致
		return RES_LENGTH_ERROR;
	if (check != 0)				//检查校验是否通过
		return RES_CHECK_ERROR;
	return RES_OK;
}

RESULT_STATUS HexFile2BinFile(char *src, char *dest)
{
	FILE *src_file, *dest_file;
	uint16_t addr_low = 0;
	uint32_t addr_hign = 0;
	char buffer_hex[600];
	uint8_t buffer_bin[255];
	BinFarmat gBinFor;
	RESULT_STATUS res;
	gBinFor.data = buffer_bin;
	src_file = fopen(src, "r");		//以文本的形式打开一个hex文件
	if (!src_file)
		return RES_HEX_FILE_NOT_EXIST;
	dest_file = fopen(dest, "wb");		//以二进制写的方式打开文件,文件不存在也没影响
	if (!dest_file)
		return RES_BIN_FILE_PATH_ERROR;
	fseek(src_file, 0, SEEK_SET);           //定位到开头,准备开始读取数据  
	while (!feof(src_file))
	{
		fscanf(src_file, "%s\r\n", buffer_hex);
		res = HexFormatUncode(buffer_hex, &gBinFor);
		if (res != RES_OK)
		{
			fclose(src_file);
			fclose(dest_file);
			return res;
		}
		switch (gBinFor.type)
		{
		case 0:			//数据记录
			addr_low = gBinFor.addr;
			//数据指针偏移
			fseek(dest_file, addr_low + addr_hign, SEEK_SET);
			if (fwrite((const uint8_t*)gBinFor.data, gBinFor.len, 1, dest_file) != 1)
			{
				fclose(src_file);
				fclose(dest_file);
				return RES_WRITE_ERROR;
			}
			break;
		case 1:		        //数据结束
			fclose(src_file);
			fclose(dest_file);
			return RES_OK;
		case 2:
			addr_hign = ((uint32_t)gBinFor.addr) << 4;
			break;
                case 3:
                        break;
		case 4:			//线性段地址
			addr_hign = ((uint32_t)gBinFor.addr) << 16;
			break;
                case 5:
                        break;
		default:
			fclose(src_file);
			fclose(dest_file);
			return RES_TYPE_ERROR;
		}
	}
	fclose(src_file);
	fclose(dest_file);
	return RES_HEX_FILE_NO_END;
}

main.c

#include 
#include "hex2bin.h"
const char *TipString[] =
{
	"bin file to hex file success!",
	"line data of hex file is too large",
	"line data of hex file is too short",
	"line data of hex file is no colon",
	"line data of hex file type is error",
	"line data of hex file length is error",
	"line data of hex file check error",
	"hex file is not exist",
	"bin file path is error",
	"hex file is no end"
};
int main(int argc, char *argv[])
{
	RESULT_STATUS res;
	if (argc != 3)
	{
		printf("para doesn't match!\r\n");
	}
	res = HexFile2BinFile(argv[1], argv[2]);
	printf("%s\r\n", TipString[res]);
	if (res != RES_OK)
	{
		return -1;
	}
	return 0;
}

程序调用:hex2bin.exe   test.hex test.bin

为了方便输入,我写了个bat文件为hex2bin.exe文件传入参数。

@echo off
echo hex2bin文件,bat文件及hex文件应在同一文件夹
echo 输入格式:XXX.hex
echo 输入格式:XXX.bin
set /p a=输入hex文件名称:
set /p b=输入bin文件名称:
hex2bin %a%  %b%
pause

参考网址:

https://www.cnblogs.com/skullboyer/p/7978189.html

https://blog.csdn.net/hwb_1988/article/details/45132417

你可能感兴趣的:(单片机)