Intel HEX 文件是由一行行符合Intel HEX 文件格式的文本所 構 成的ASCII 文本文件。在Intel HEX 文件中,每一行包含一 個 HEX 記錄 。 這 些 記錄 由 對應 機器 語 言 碼 和/ 或常量 數 據的十六 進 制 編碼數 字 組 成。Intel HEX 文件通常用於 傳輸將 被存於ROM 或者EPROM 中的程序和 數 據。大多 數 EPROM 編 程器或模 擬器使用Intel HEX 文件。
Hex文件是可以燒寫到單片機中,被單片機執行的一種文件格式,生成Hex文件的方式由很多種,可以通過不同的編譯器將C程序或者匯編程序編譯生成hex。
一般Hex文件通過記事本就可以打開。可以發現一般Hex文件的記錄格式如下:

Intel HEX 由任意數量的十六 進 制 記錄組 成。每 個記錄 包含5 個 域, 它們按以下格式排列:
每一組字母 對應 一 個 不同的域,每一 個 字母 對應 一 個 十六 進 制 編碼 的 數 字。每一 個 域由至少 兩個 十六 進制 編碼數 字 組 成, 它們構 成一 個 字 節 ,就像以下描述的那 樣:
:(冒號)每個Intel HEX 記錄 都由冒 號開頭 ;
LL 是 數 據 長 度域, 它 代表 記錄當 中 數 據字 節 (dd) 的 數量 ;
aaaa 是地址域, 它代表 記錄當 中 數據的起始地址;
TT是代表HEX 記錄類 型的域 , 它 可能是以下 數 據 當 中的一 個:
00 – 數 據 記錄(Data Record)
01 – 文件結 束 記錄(End of FileRecord)
02 – 擴展段地址 記錄(ExtendedSegment Address Record)
03 – 開始段地址 記錄(Start Segment Address Record)
04 – 擴展 線 性地址 記錄(Extended Linear Address Record)
05 – 開始線性地址 記錄(Extended Segment Address Record)
dd 是數 據域 , 它 代表一 個 字 節 的 數 據. 一 個記錄 可以有 許 多 數 據字 節 . 記錄當 中 數 據字 節 的 數 量必 須 和數 據 長 度域(ll) 中指定的 數字相符.
cc 是校驗 和域 , 它 表示 這個記錄 的校 驗 和. 校 驗 和的 計 算是通 過將記錄當 中所有十六 進 制 編碼數 字 對 的 值相加, 以256 為 模 進 行以下 補 足.
表示為:“:[1字節長度][2字節地址][1字節記錄類型][n字節數據段][1字節校驗和] ”
具體根據記錄類型分析如下:
(1)數據記錄”00”
Intel HEX文件由任意數 量以回車換行符結束的數據記錄組成數據記錄外觀如下:
:10246200464C5549442050524F46494C4500464C33
其中:10 是這個記錄當中 數 據字 節 的 數量.即0x10 ;
2462 是數據 將 被下 載 到存 儲 器 當中的地址.即0x2462 ;
00 是記錄類型( 數 據 記錄).即0x00 ;
464C…464C是 數據.分別代表0x46,0x4C... ;
33 是這個記錄的校 驗和即0x33;計算方法如下:256D-(10H+24H+62H+00H+46H+4CH+55H+49H+44H+20H+50H+52H+4FH+46H+49H+4CH+45H+00H+46H+4CH)/100H=33H;
(2)文件結束(EOF)”01”
Intel HEX文件必須以文件結束(EOF) 記錄結束這個記錄的記錄類的值必須是01.EOF 記錄 外 觀總是如下:
:00000001FF
其中:00 是記錄當中 數 據字 節 的 數量.
0000 是數據被下載到存儲器當中的地址. 在文件結束記錄當中地址是沒有意義,被忽略的.0000h 是典型的地址;
01 是記錄類型 01( 文件 結 束 記錄)
FF 是 這個記錄 的校 驗 和, 計算方法如下: 256D-(00H+00H+00H+01H)=FFH;
(3)擴展線性地址記錄(HEX386) ”04”
由於每行標識數據地址的只有2Byte,所以最大只能到64K,為了可以保存高地址的數據,就有了Extended Linear AddressRecord。如果這行的數據類型是0x04,那么,這行的數據就是隨后數據的基地址。
擴展線性地址記錄也叫作32位地址記錄或HEX386記錄.這些記錄含數據的高16位擴展線性地址記錄總是有兩個數據字節,外觀如下:
:02000004FFFFFC
其中:02 是這個記錄當中 數 據字 節 的 數量.
0000 是地址域, 對於 擴 展 線 性地址 記錄 , 這個 域 總是0000.
04 是記錄類型 04( 擴 展 線 性地址 記錄)
FFFF 是地址的高16 位.
FC 是這個記錄的校 驗 和, 計算如下: 256D-(02H+00H+00H+04H+FFH+FFH)/100H=FFH;
當一 個擴展 線 性地址記錄被讀 取, 存 儲於數據域的擴展線性地址被保存,它被應於
從 Intel HEX 文件 讀取 來 的 隨 后的 記錄 . 線 性地址保持有效, 到 它 被另外一 個擴址記錄 所改 變。
通 過 把 記錄當 中的地址域 與 被移位的 來 自 擴 展 線 性地址 記錄 的地址 數 據相加
獲 得 數 據 記錄 的 絕對 存 儲器地址。
以下的例子演示了這個過 程:
:0200000480007A //數據記錄的絕對存儲器地址高16位為0x8000
:100000001D000A00000000000000000000000000C9
:100010000000000085F170706F0104005D00BD00FC
第一行,是Extended Linear Address Record,里面的數據,也就是基地址是0x8000,第二行是DataRecord,里面的地址值是0x0000。那么數據1D000A00000000000000000000000000(共16個字節)要寫入FLASH中的地址為 (0x8000<< 16)| 0x0000,也就是寫入FLASH的0x80000000這個地址;第三行的數據寫入地址為0x80000010.當一個HEX文件的數據超過64k的時候,文件中就會出現多個Extended Linear Address Record。
(4)擴展段地址記錄(HEX86)“02“
擴展段地址記錄也叫HEX86 記錄 , 它包括4-19 位數據地址段. 擴展段地址記總是有兩
個數 據字節 , 外觀如下:
:020000021200EA
其中:02 是記錄當中 數 據字 節 的 數量;
0000 是地址域. 對於 擴 展段地址 記錄 , 這個 域 總是0000;
02 是記錄類型 02( 擴 展段地址 記錄);
1200 是地址段;
EA 是這個記錄的校 驗 和;
當一 個擴 展段地址 記錄 被 讀 取, 存 儲 於 數 據域的 擴 展段地址被保存, 它 被 應 用於 從 Intel HEX 文件 讀 取 來的 隨 后的 記錄 . 段地址保持有效, 直到 它 被另外一 個擴 展地址 記錄 所改 變。
通 過 把 記錄當 中的地址域 與 被移位的 來 自 擴 展段地址 記錄 的地址 數 據相加 獲 得 數 據 記錄 的 絕對 存 儲器地址。
以下的例子演示了這個過 程..
來自 數 據 記錄地址域的地址 2462
擴展段地址 記錄數據域 + 1200
---------
絕對存 儲 器地址 00014462
Intel HEX 文件例子:
下面是一個 完整的Intel HEX 文件的例子:
:10001300AC12AD13AE10AF1112002F8E0E8F0F2244
:10000300E50B250DF509E50A350CF5081200132259
:03000000020023D8
:0C002300787FE4F6D8FD7581130200031D
:10002F00EFF88DF0A4FFEDC5F0CEA42EFEEC88F016
:04003F00A42EFE22CB
:00000001FF
//追加一段
int ParseIHexPerLine(const char *buf,const char *path,int line)
{
unsigned int nbytes=0,addr=0,type=0,i,val,line_chksum;
unsigned char data[1024];
unsigned char cksum;
const char *s=buf;
if(*s!=':') //第一個為冒號
{
fprintf(stderr,"%s:%s: format violation (1)/n",path,line);
return(1);
}
++s;
//接下來的8個字節為數據大小、地址等
if(sscanf(s,"%02x%04x%02x",&nbytes,&addr,&type)!=3)
{
fprintf(stderr,"%s:%s: format violation (2)/n",path,line);
return(1);
}
s+=8;
//讀到的類型
if(type==0) //為數據段
{
if(!(nbytes>=0 && nbytes<1024))
{
perror("nbyte per line unsupport/n");
return(-1);
}
cksum=nbytes+addr+(addr>>8)+type;
//
for(i=0; i<nbytes; i++)
{
val=0;
if(sscanf(s,"%02x",&val)!=1)
{
fprintf(stderr,"%s:%s: format violation (3)/n",path,line);
return(1);
}
s+=2;
data[i]=val;
cksum+=val;
}
//
line_chksum=0;
if(sscanf(s,"%02x",&line_chksum)!=1)
{
fprintf(stderr,"%s:%s: format violation (4)/n",path,line);
return(1);
}
if((cksum+line_chksum)&0xff)
{
fprintf(stderr,"%s:%s: checksum mismatch (%u/%u)/n",
cksum,line_chksum);
return(1);
}
if(WriteRAM(addr,data,nbytes))
return(1);
}
else if(type==1)
{
// EOF marker. Oh well, trust it.
return(-1);
}
else
{
fprintf(stderr,"%s:%s: Unknown entry type %d/n",type);
return(1);
}
return(0);
}
