hex和bin文件格式

 

Hex文件,這裏指的是Intel標準的十六進制文件,也就是機器代碼的十六進制形式,並且是用一定文件格式的ASCII碼來表示.具體格式介紹如下:
Intel hex 文件格式

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
數據域校驗和

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造成的結果。

copy from:http://tieba.baidu.com/f?kz=271526661

/*
      使用方法 : 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;
}

簡單介紹一下這2種文件格式的區別:


1 - HEX文件是包括地址信息的,而BIN文件格式只包括了數據本身
          在燒寫或下載HEX文件的時候,一般都不需要用戶指定地址,因爲HEX文件內部的信息已經包括了地址。而燒寫BIN
          文件的時候,用戶是一定需要指定地址信息的。
         
         
3 - BIN文件格式
          對二進制文件而言,其實沒有”格式”。文件只是包括了純粹的二進制數據。
         
         
4 - HEX文件格式
          HEX文件都是由記錄(RECORD)組成的。在HEX文件裏面,每一行代表一個記錄。記錄的基本格式爲:
          +---------------------------------------------------------------+
          |    RECORD   | RECLEN |   LOAD   | RECTYPE | INFO or DATA | CHKSUM |
          |   MARK ':' |         | OFFSET |          |               |         |
          +---------------------------------------------------------------+
          |   1-byte    | 1-byte | 2-byte | 1-byte   |     n-byte     | 1-byte |
          +---------------------------------------------------------------+
         
          記錄類型包括:
          '00' Data Rrecord:用來記錄數據,HEX文件的大部分記錄都是數據記錄
          '01' End of File Record: 用來標識文件結束,放在文件的最後,標識HEX文件的結尾
          '04' Extended Linear Address Record: 用來標識擴展線性地址的記錄
          '02' Extended Segment Address Record: 用來標識擴展段地址的記錄
         
          在上面的後2種記錄,都是用來提供地址信息的。每次碰到這2個記錄的時候,都可以根據記錄計算出一個“基”地址。
          對於後面的數據記錄,計算地址的時候,都是以這些“基”地址爲基礎的。
         
          數據記錄的具體格式:
          +---------------------------------------------------------------+
          |    RECORD   | RECLEN |   LOAD   | RECTYPE | INFO or DATA | CHKSUM |
          |   MARK ':' |         | OFFSET |   '00'    |               |         |
          +---------------------------------------------------------------+
          |   1-byte    | 1-byte | 2-byte | 1-byte   |     n-byte     | 1-byte |
          +---------------------------------------------------------------+         
         
          看個例子:
         :020000040000FA
         :10000400FF00A0E314209FE5001092E5011092E5A3
         :00000001FF         
       
         對上面的HEX文件進行分析:
         第1條記錄的長度爲02,LOAD OFFSET爲0000,RECTYPE爲04,說明該記錄爲擴展段地址記錄。數據爲0000,校驗和爲
         FA。從這個記錄的長度和數據,我們可以計算出一個基地址,這個地址爲0X0000。後面的數據記錄都以這個地址爲基
         地址。
         第2條記錄的長度爲10(16),LOAD OFFSET爲0004,RECTYPE爲00,說明該記錄爲數據記錄。
         數據爲FF00A0E314209FE5001092E5011092E5,共16個BYTE。這個記錄的校驗和爲A3。此時的基地址爲0X0000,加上OFFSET,
         這個記錄裏的16BYTE的數據的起始地址就是0x0000 + 0x0004 = 0x0004.
         第3條記錄的長度爲00,LOAD OFFSET爲0000,TYPE = 01,校驗和爲FF。說明這個是一個END OF FILE RECORD,標識
         文件的結尾。
       
         在上面這個例子裏,實際的數據只有16個BYTE:FF00A0E314209FE5001092E5011092E5,其起始地址爲0x4
           

4 - HEX文件和BIN文件大小有區別
      HEX文件是用ASCII來表示二進制的數值。例如一般8-BIT的二進制數值0x3F,用ASCII來表示就需要分別表示字符'3'
      和字符'F',每個字符需要一個BYTE,所以HEX文件需要 > 2倍的空間。
      對一個BIN文件而言,你查看文件的大小就可以知道文件包括的數據的實際大小。而對HEX文件而言,你看到的文件
      大小並不是實際的數據的大小。一是因爲HEX文件是用ASCII來表示數據,二是因爲HEX文件本身還包括別的附加信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章