.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的代码。上述列出的代码里面我就直接拷贝了部分代码使用。大家也可以从里提取出出来自用。
2040

被折叠的 条评论
为什么被折叠?



