.MCS文件和.HEX的区别以及生成.MCS的代码

.HEX是早起的INTEL提出的烧写文件的格式,由于历史原因只支持到64K的长度。

.MCS文件我们说的是XILINX的烧写文件,他是在.HEX的基础上发展而来的。为了突破64K长度限制,每隔64K字节他给出一个起始地址。

我们看到每行16个字节(两个ASCII码表达一个字节),每隔4096行,也就是整整65536字节就会出现一次起始地址信息。

我们简单HEX格式定义:

/*

记录格式
一个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++;
*/

看到02确实是地址扩展字段。

有了上述的分析我们在生成mcs文件时候每隔64K防止一个地址,实现代码如下:

static void show_a_seg(){
static int  i = 0 ;
if (i==0) fprintf(fout,":020000040000FA\n");
if (i==1) fprintf(fout,":020000040001F9\n");
if (i==2) fprintf(fout,":020000040002F8\n");
if (i==3) fprintf(fout,":020000040003F7\n");
if (i==4) fprintf(fout,":020000040004F6\n");
if (i==5) fprintf(fout,":020000040005F5\n");
if (i==6) fprintf(fout,":020000040006F4\n");
if (i==7) fprintf(fout,":020000040007F3\n");
if (i==8) fprintf(fout,":020000040008F2\n");
if (i==10) fprintf(fout,":020000040009F1\n");
if (i==11) fprintf(fout,":02000004000AF0\n");
if (i==12) fprintf(fout,":02000004000BEF\n");
if (i==13) fprintf(fout,":02000004000CEE\n");
if (i==14) fprintf(fout,":02000004000DED\n");
if (i==15) fprintf(fout,":02000004000EEC\n");
if (i==16) fprintf(fout,":02000004000FEB\n");
i++;
}
    

这里注意i是一个静态局部变量,再每次调用后保存修改。当然这代码使用“穷举”的方法,如果MCS文件可以再添加或者根据HEX的02开头协议改成更智能的。

所有代码如下:

 

#include <windows.h>
#include <stdio.h>
#include <conio.h>

 unsigned char  s[] = { 
 
 
 #include "aaa.c"
 
  
};
 
		 
		 
		 


 
static unsigned long addr;
static FILE *fout=NULL;
static long int offset;
static int newaddr;
static int pos=-666;
static unsigned char bytes[160];

#define mesg_f printf
/*-----------------------------------------------------------------------
 * "hex" format.  Intel HEX format expected by many EPROM programmers
 */


void hexdump(void)     /* dumps one line into file */
{
	int i, sum;

	if (fout == NULL) return;
	fprintf(fout,":%02X%04lX00", pos, addr & 0xFFFF);
	sum = pos + ((addr>>8)&0xff) + (addr&0xff) ;
	for (i=0; i < pos; i++) {
		fprintf(fout,"%02X", bytes[i] & 0xFF );
		sum += bytes[i]&0xff;
	}
	fprintf(fout, "%02X\n", 1+(~sum)&0xff);
	addr += pos;///4; /// 2009-11-14 by liwei
	pos = 0;
}
static void show_a_seg(){
static int  i = 0 ;
if (i==0) fprintf(fout,":020000040000FA\n");
if (i==1) fprintf(fout,":020000040001F9\n");
if (i==2) fprintf(fout,":020000040002F8\n");
if (i==3) fprintf(fout,":020000040003F7\n");
if (i==4) fprintf(fout,":020000040004F6\n");
if (i==5) fprintf(fout,":020000040005F5\n");
if (i==6) fprintf(fout,":020000040006F4\n");
if (i==7) fprintf(fout,":020000040007F3\n");
if (i==8) fprintf(fout,":020000040008F2\n");
if (i==10) fprintf(fout,":020000040009F1\n");
if (i==11) fprintf(fout,":02000004000AF0\n");
if (i==12) fprintf(fout,":02000004000BEF\n");
if (i==13) fprintf(fout,":02000004000CEE\n");
if (i==14) fprintf(fout,":02000004000DED\n");
if (i==15) fprintf(fout,":02000004000EEC\n");
if (i==16) fprintf(fout,":02000004000FEB\n");
i++;
}
    
static int open_hex(const char *file)
{
	fout = fopen(file, "a");
	if( fout == NULL ) {
		mesg_f("Cannot open %s for writing.\n", file);
		return 0;
	}
	show_a_seg(); 
	printf("show a seg\n");
//	getchar();
	
	//	fprintf(fout, ":020000020000FC\n");  /* end of file marker */
	pos = 0;
	return 1;
}


static void pause_hex(void)
{
	if (fout == NULL) return;
	if ( pos > 0 ) hexdump();
	printf("pause hex \n");
//	getchar();
	fclose(fout);
}

static void close_hex(void)
{
	if (fout == NULL) return;
	if ( pos > 0 ) hexdump();
	printf("close hex \n");
//	getchar();
	fprintf(fout, ":00000001FF\n");  /* end of file marker */
	fclose(fout);
}

static void addr_hex(unsigned long a)
{
	if ( pos > 0 ) hexdump();
	addr = a;
}


static void byte_hex(unsigned char b)
{
	bytes[pos] = b;
	pos += 1;
	if ( pos == 16) hexdump();
}


unsigned char  gen_hex_file_64k(  char *filename,unsigned char *buff , int len)
{
int i;
open_hex(filename);
for(i=0;i<len;i++)byte_hex(buff[i]);
}


unsigned char  gen_hex_file(  char *filename,unsigned char *buff , int len)
{
int i ;
int offset = 0  ; 

	fout = fopen(filename, "w");
	fclose(fout) ; 
while(len > 65536 ){
          gen_hex_file_64k(filename,buff+offset,65536);
          offset += 65536;
          len -= 65536;
          if (len==0)close_hex();else  pause_hex();
}
if (len)   { gen_hex_file_64k(filename,buff+offset,len); close_hex(); }
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*

记录格式
一个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++;
*/

////////////////////////////////////////////////////////////////////////////////////////


unsigned char byte_swap(unsigned char hi ){
     unsigned char r = 0 ;
     if ( hi & 128 ) r += 1   ; 
     if ( hi & 64 )  r += 2 ; 
     if ( hi & 32 ) r += 4 ; 
     if ( hi & 16 ) r += 8  ; 
     if ( hi & 8 )  r += 16 ; 
     if ( hi & 4 )  r += 32; 
     if ( hi & 2 ) r += 64; 
     if ( hi & 1 ) r += 128 ; 
     return r ;
}
void main()
{
 
unsigned 	int i,len;

// for(i=0;i<sizeof(s);i+=1) s[i] =    (i&0xff)  ;//     byte_swap (s[i]); 
//	fout = fopen("rrr.mcs", "w");
//	fclose(fout) ; 
 //        gen_hex_file("rrr.mcs",s,sizeof(s));
         
       for(i=0;i<sizeof(s);i+=1) s[i] =  byte_swap (s[i]); //     byte_swap (s[i]); 
	fout = fopen("aaa.mcs", "w");
	fclose(fout) ; 
         gen_hex_file("aaa.mcs",s,sizeof(s));
         
            
         
 ///   buff2file();

}


这里注意包含了一个很简洁的生成hex的代码。有一个开源的51单片机的C编译器叫做SDCC,里面有一段生成.HEX的代码。上述列出的代码里面我就直接拷贝了部分代码使用。大家也可以从里提取出出来自用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值