[ บทความ : แปลงไฟล์ .HEX ให้เป็นไฟล์ฐานสอง ]

รูปแบบของไฟล์ฐานสิบหก Intel HEX (แบบ 8 บิต)

	:NNAAARRHHHHHH…HHHCC
สัญลักษณ์
ความหมาย
:
เป็นตัวบอกให้เรารู้ว่าเป็นจุดเริ่มของข้อมูลในแต่ละบรรทัด
NN
เป็นตัวเลขฐานสิบหกจำนวน 2 หลัก ที่บอกว่า ในบรรทัดนั้นมีข้อมูลอยู่กี่ตัว
AAAA
เป็นเลขฐานสิบหกที่บอกว่า ข้อมูลไบต์แรกของบรรทัดนั้น อยู่ ณ ตำแหน่งใดในหน่วยความจำ
RR
เป็นตัวบอกประเภทของข้อมูล, 00 - บรรทัดข้อมูล, 01 - บรรทัดสุดท้าย
CC
เป็น Check Sum หาได้จาก
Sum = จำนวนไบต์+ ไบต์สูงของค่าแอดเดรส + ไบต์ต่ำของค่าแอดเดรส + ค่าชนิดของข้อมูล + ผลรวมของข้อมูล
CC = ค่า 2's complement ของ sum = complement(sum)+1

ตัวอย่างโปรแกรม Z80

		ORG   8000h
	main       LD    A,5
		XOR   A
		HALT
		END

เมื่อเราทำการคอมไพล์แล้วก็จะได้ไฟล์ LST ออกมาดังนี้


	8000                         ORG   8000h
   	8000                 main
   	8000   3e 05                 LD    A,5
   	8002   af                    XOR   A
   	8003   76                    HALT
   	8004                         END

และได้ไฟล์ฐานสิบหก (.HEX) เป็นหน้าตาดังนี้ครับ


	:048000003E05AF7614
	:008004017B

บรรทัดแรก : 04 บอกว่า บรรทัดนั้นมี 4 ไบต์ , เริ่มต้นที่หน่วยความจำตำแหน่งที่ 8000h เป็นบรรทัดข้อมูล (00) ข้อมูลคือ 3E05AF76 ส่วน CC คือ 14 วิธีการคำนวณ เป็นดังนี้ครับ

	sum = 4h+80h+00h+00h+3Eh+05h+AFh+76h =  ECh (ผลบวกคิดเฉพาะ 8 บิต ส่วนที่เกินตัดทิ้ง)
	ECh = 11101100b, Complement ของ ECh = 00010011b
	บวกอีก 1 = 00010100b = 14h <--เป็นค่า check sum

บรรทัดที่สอง : 00 บอกว่า บรรทัดนี้ไม่มีข้อมูล เริ่มตำแหน่งข้อมูลที่ 8004h มีรูปแบบข้อมูลเป็น 01 หรือ เป็นบรรทัดจบ ส่วน 7B เป็น CC ซึ่งหลักการคำนวณ คือ

	sum = 00h+80h+04h+01h+00h =  85h (10000101b)
	2's complement ของ 85h = (01111010b)+1 = (01111011b) = 7Bh <-- เป็นค่าของ  check sum

คราวนี้เรามาดูซอร์สโปรแกรมที่ทำหน้าที่แปลงไฟล์ฐานสิบหก ให้เป็นไฟล์ไบนารี กันเลยครับ ... โปรแกรม เขียนด้วย Visual C++ version 6.0 ทำงานแบบ Console (Text) Mode ซึ่งเท่ที่ลองกับคอมไพล์เลอร์บน DOS ก็ทำงานได้ปกติดี ... ซอร์สโปรแกรมเป็นดังนี้ครับ


	/*
	 * Filename : H2O.C
	 *
	 * Author   : Supachai Budsartij (e-mail : raek@se-ed.net)
	 * Date     : Dec 10,2000
	 * Compiler : Visual C++ Version 6 professional edition
	 *
	 * Note     : Convert Intel-HEX file(.HEX) to object file(.OBJ).
	 */
	#include <stdio.h>
	#include <string.h>
	
	#define BTRUE  1
	#define BFALSE 0
	
	char ToUpper(char x);
	char ToLower(char x);
	int  IsUpper(char x);
	int  IsLower(char x);
	int  IsAlpha(char x);
	int  IsDigit(char x);
	int  IsHexDigit(char x);
	int  Nibble2Bin(char byte);
	int  GetHex(FILE * fp);
	int  GetXByte(FILE *fp);
	int  iHex2Obj(void);
	unsigned char TwoCPL(unsigned char x);
	
	// --- source function
	
	char ToUpper(char x)
	// Change x to upper case.
	{
	    if (IsLower(x)) {
	        x = 'A'+(x-'a');
	    }
	    return(x);
	}
	
	char ToLower(char x)
	// Change x to lower case
	{
	    if (IsUpper(x)) {
	        x = 'a'+(x-'A');
	    }
	    return(x);
	}
	
	int IsUpper(char x)
	// Recognize an upper case.
	{
	    if ((x>='A')&&(x<='Z')) {
	        return(BTRUE);
	    }
	    return(BFALSE);
	}
	
	int  IsLower(char x)
	// Recognize a lower case.
	{
	    if ((x>='a')&&(x<='z')) {
	        return(BTRUE);
	    }
	    return(BFALSE);
	}
	
	int IsAlpha(char c)
	// Recognize an alpha character
	{
	    char c2;
	    c2 = ToUpper(c);
	    if ((c2>='A')&&(c2<='Z')) {
	        return(BTRUE);
	    }
	    return(BFALSE);
	}

	int IsDigit(char c)
	// Recognize a decimal digit
	{
	    if ((c >= '0')&&(c<='9')) {
	        return(BTRUE);
	    }
	    return(BFALSE);
	}


	int IsHexDigit(char x)
	// Recognize a hexdecimal digit
	{
	    x = ToUpper(x);
	    if ((x >= '0')&&(x<='9')||((x >= 'A')&&(x <= 'F'))) {
	        return(BTRUE);
	    }
	    return(BFALSE);
	}


	int Nibble2Bin(char byte)
	// Convert Hex digit to binary
	{
	    byte = ToUpper(byte);
	
	    if ((byte >= '0')&&(byte <= '9')) {
	        byte -= '0';
	    }
	    else if ((byte >= 'A')&&(byte <= 'F')) {
	        byte = (byte-'A')+10;
	    }
	    else {
	        return(-1);
	    }
	    return(byte);
	}


	int GetHex(FILE *fp)
	{
	     unsigned char buffer;

	     buffer = fgetc(fp);
	     if (!IsHexDigit(buffer)) {
	         return(-1);
	     }
	     return(buffer);
	}

	int GetXByte(FILE *fp)
	{
	    unsigned char byte, xbyte;

	    if ((byte = GetHex(fp)) == -1) {
	        return(-1);
	    }
	    xbyte = ((unsigned char)Nibble2Bin(byte))<<4;

	    if ((byte = GetHex(fp)) == -1) {
	        return(-1);
	    }
	    xbyte |= (unsigned char)Nibble2Bin(byte);

	    return(xbyte);
	}


	unsigned char TwoCPL(unsigned char x)
	// Find 2's complement of x.
	{
	     return((~x)+1);
	}


	int iHex2Obj(void)
	{
	    char done;
	    int  num, max_data;
	    unsigned char cc;
	    unsigned int addr;
	    char src[128], tar[128];
	    FILE * p_src,
	         * p_tar;

	    done = 0;

	    fprintf(stdout,"HEX-Filename ?"); gets(src);
	    fprintf(stdout,"OBJ-Filename ?"); gets(tar);

	    p_src = fopen(src,"rt");
	    if (p_src == NULL) {
	         fprintf(stdout,"ERROR : Can not open hex-filename /"%s/"/n",src);
	         return(BFALSE);
	    }

	    p_tar = fopen(tar,"wb");
	    if (p_tar == NULL) {
	         fprintf(stdout,"ERROR : Can not create obj-filename /"%s/"/n",tar);
	         return(BFALSE);
	    }

	    fprintf(stdout,"/n Convert IntelHEX file to object file");
	    fprintf(stdout," [press ESC for terminated]/n");

	    while (!done) {

	/* Step 1 : Read until found ':' */

	        do {
	            num = (unsigned char)fgetc(p_src);
	        } while ((num != (int)':')&&(num != 27)&&(!feof(p_src)));

	        if (feof(p_src)) {
	            fprintf(stdout,"ERROR : %s is not intel-HEX file/n",src);
	            fcloseall();
	            return(BFALSE);
	        }

	        if (num == 27) {
	            fprintf(stdout,"/n --- User terminate ---/n");
	            fcloseall();
	            return(BFALSE);
	        }

	        cc = 0;

	/* Step 2 : Get number of data */

	        num = GetXByte(p_src);

	        if (num < 0) { /* Last record or error (num is a HEX-digit) */
	            fprintf(stdout,"/nERROR : [num of data] is not a HEX-digit/n");
	            fcloseall();
	            return(BFALSE);
	        }
	        if (num == 0) {
	            done = 1;
	        }

	        cc += (unsigned char)num; /* cc = num */
	        max_data = num;

	/* Step 3 : Read address */

	        num = GetXByte(p_src); /* Read HI Byte */
	        if (num < 0) {
	            fprintf(stdout,"/nERROR : [Hi address] is not a HEX-digit/n");
	            fcloseall();
	            return(BFALSE);
	        }

	        cc += (unsigned char)num; /* cc = cc+Addr_HI */
	        addr = (unsigned int)(num << 8); /* Convert to Hi_Byte */

	        num = GetXByte(p_src); /* Read LO Byte */
	        if (num < 0) {
	            fprintf(stdout,"/nERROR : [Lo address] is not a HEX-digit/n");
	            fcloseall();
	            return(BFALSE);
	        }
	
	        cc += (unsigned char)num; /* cc = cc+Addr_Lo */
	        addr |= (unsigned int)num;

	/* Step 4 : Read Record-Type */

	        num = GetXByte(p_src);
	        if (num < 0) {
	            fprintf(stdout,"/nERROR : [Record type] is not a HEX-digit/n");
	            fcloseall();
	            return(BFALSE);
	        }

	        cc += (unsigned char)num; /* cc = cc+record_type */

	        if (num == 1) {
	            done = 1;
	        }
	        else { /* num == 0 */

	/* Step 5 : Read data / write and verified. */

	            while (max_data > 0) {
	                num = GetXByte(p_src); /* Read data */
	                if (num < 0) {
	                    fprintf(stdout,"/nERROR : [Read data] is not a HEX-digit/n");
	                    fcloseall();
	         	    return(BFALSE);
	                }
                	cc += (unsigned)num; /* cc = cc+data */
	
	                /* write */
	                fwrite(&(unsigned char)num, sizeof(unsigned char), 1, p_tar);

	                max_data--;
	                addr++;
	            }  /* Finis reading */
	        } /* else { ... num == 0 */

	/* Step 6 : CheckSum */

	        num = GetXByte(p_src); /* Read check sum data*/
	        if (num < 0) {
	            fprintf(stdout,"/nERROR : [check sum] is not a HEX-digit/n");
	            fcloseall();
	            return(BFALSE);
	        }

	        cc = TwoCPL(cc);
	        if (cc != (unsigned char)num) {
	            fprintf(stdout,"/nERROR : [check sum]/n");
	            fcloseall();
	            return(BFALSE);
	        }
	    } /* while(!done) ... */

	    fcloseall();
	    fprintf(stdout,"...Convert successfull.../n/n");

	    return(BTRUE);
	}

	void main(void)
	{
	    iHex2Obj();
	}


เขียนโดย : ศุภชัย บุศราทิจ
Author : Supachai Budsaratij
e-mail : raek@se-ed.net
วันที่ทำการปรับปรุง : ๒๓ ธ.ค. ๒๕๔๓