作者 : 鄭旭崇
§前言
在 8051 盛行的現在,許多的控制器都用他來當作微處理機,例如:溫度控制器,PID壓力控制器
,化學用PH儀...等等不勝枚舉.通常8051內部只有4k BYTE 程式記憶體,而8052內部只有8k BYTE
程式記憶體,如果我們的程式大小超過 4K BYTE 或 8k BYTE 的話,這時就必須外加一顆 EPROM
或是 Flash ROM 了.就一般販售的 ROM 模擬器而言,一套至少要 NT2000 元左右,如果自己製作
的話,成本將不到 NT600 元,這對於貧窮的學生們,個人工作室將是節省支出的方法.
而且使用 ROM 模擬器的優點除了縮短開發時間,更可不限次數的燒錄.
本 ROM 模擬器的特色:
* 支援 32kx8bit 27256 和 64kx8bit 27512.
* 不必插卡,無須外加電源.(電源由目標板 target baord 供應)
* 程式 Download 迅速,約 0.5 秒.
* 接受 Binary 檔案格式.
* 作業環境 Windows 95/98 , DOS.
§並列埠的原理
壹.並列埠I/O位址之取得
一般個人電腦內定的第一個並列介面埠(LPT1),起始位址為0378H,目前
已經被列為標準的ON BOARD基本配備了。您的電腦若有加裝Printer c
ard,那麼它的起始位址應該是0278H.在每一電腦內部最多可以裝設3個並列埠
,作業系統保留了3個I/O空間給並列介面。並列埠的I/O位址範圍如表一所示。
┌───────────────┬──────┐
│ I/O Port 位址 │ 介面名稱 │
├───────────────┼──────┤
│ 0378H - 037AH │ LPT1 │
├───────────────┼──────┤
│ 0278H - 027AH │ LPT2 │
├───────────────┼──────┤
│ 03BCH - 03BEH │ LPT3 │
└───────────────┴──────┘
<表一> 並列埠的I/O位址範圍
另外,並列埠的起始位址亦可由記憶體內的資訊取得,見表二。
┌───────┬──────────┐
│記憶體位址 │ I/O起始位址 │
├───────┼──────────┤
│0000:0408H │ LPT1 │
├───────┼──────────┤
│0000:040AH │ LPT2 │
├───────┼──────────┤
│0000:040DH │ LPT3 │
└───────┴──────────┘
<表二> 由記憶體取得並列埠的I/O位址
我們可以使用Windows所提供的debug.exe來查看,在DOS的提
示字元下輸入:
C:\>DEBUG
-D 0000:0408
0000:0400 78 03 00 00 00 00 00 00 x.......
0000:0410 23 54 00 80 02 80 00 60-00 00 3A 00 3A 00 53 1F #T.....`..:.:.S.
0000:0420 54 14 0D 1C 44 20 30 0B-30 0B 30 0B 30 0B 3A 27 T...D 0.0.0.0.:'
0000:0430 30 0B 34 05 30 0B 38 09-0D 1C 2E 34 4C 26 00 00 0.4.0.8....4L&..
0000:0440 00 00 C0 00 00 00 00 00-00 03 50 00 00 80 00 00 ..........P.....
我們可以清楚地看到在記憶體0000:0408的位址上,記錄著78 03,讀者
一定會問LPT1的起始位址不是0378H嗎?怎麼會是7803呢?其實這是作業
系統將高BYTE的資料放在高位址,低BYTE的資料放在低位址的結果。相信寫過
MASM組合語言的人,對這種資料的排法應該感到不陌生才對。
貳.並列埠之名稱及用途
小弟以LPT1為例,說明並列埠之名稱及用途。
I/O埠位址 功能
0378H 資料埠。當您的並列埠直接由主機板接出來,未經過KeyPro時
,那麼此Port可以做資料雙向傳遞。值得注意的是,如果您的電
腦已經插上了一個KeyPro的話,此Port只能當輸出用。若
強制給它輸入電壓,恐有燒毀之虞,要特別小心。
0379H 狀態埠。為輸入埠,主要用來接收印表機的工作狀態。
037AH 控制埠。為輸出埠,主要用來送出信號給印表機。
D-TYPE 25Pin並列埠接腳之對照,請參考下表。
┌────────┬──────┬─────┬──────────┐
│D-TYPE 25 Pin │ 信號名稱 │ 位址.Bit │IN/OUT │
│接腳編號 │ │ │ │
├────────┼──────┼─────┼──────────┤
│ 1 │ /STROBE │ 037AH.0 │OUT │
├────────┼──────┼─────┼──────────┤
│ 2∼9 │ D0 TO D7 │ 0378H │IN/OUT OR ONLY OUT │
├────────┼──────┼─────┼──────────┤
│ 10 │ /ACK │ 0379H.6 │IN │
├────────┼──────┼─────┼──────────┤
│ 11 │ BUSY │ 0379H.7 │IN │
├────────┼──────┼─────┼──────────┤
│ 12 │ PE │ 0379H.5 │IN │
├────────┼──────┼─────┼──────────┤
│ 13 │ SLCT │ 0379H.4 │IN │
├────────┼──────┼─────┼──────────┤
│ 14 │ /A.F.X │ 037AH.1 │OUT │
├────────┼──────┼─────┼──────────┤
│ 15 │ /ERROR │ 0379H.3 │IN │
├────────┼──────┼─────┼──────────┤
│ 16 │ /INIT │ 037AH.2 │OUT │
├────────┼──────┼─────┼──────────┤
│ 17 │ /SCLT IN │ 037AH.3 │OUT │
├────────┼──────┼─────┼──────────┤
│ 18∼25 │ GND │ │OUT │
└────────┴──────┴─────┴──────────┘
<表三> D-TYPE 25Pin並列埠接腳對照表
I/O位址379H與37AH並未用到所有的Bit。379H只用了5個Bit
,37AH只用了4個Bit。其中有些輸入位元被反向,有些輸出位元被反向,造成了
程式設定值與實際輸出值間的差異。以Port 037AH為例,程式在輸出控制碼前
,應先做轉換。轉換的方法其實很簡單,就是將實際輸出值除了Bit2沒有反向外,其
餘的Bit皆給他反向,再按照Bit0到Bit3的順序,以1,2,4,8的數值加
權,即可得到設定值。 轉換對照值請參考下表。
請注意,Port 037AH的Bit4到Bit7並沒有連接到並列埠上,所以這4
個Bit是Don’t care的。
┌────┬──────────────┬───────┐
│ 設定值 │ Port 037AH 的 Bit 3 - 0 │ 實際輸出值 │
│ │ /B3 B2 /B1 /B0 │ │
├────┼──────────────┼───────┤
│ B │ 1 0 1 1 │ 0 │
├────┼──────────────┼───────┤
│ A │ 1 0 1 0 │ 1 │
├────┼──────────────┼───────┤
│ 9 │ 1 0 0 1 │ 2 │
├────┼──────────────┼───────┤
│ 8 │ 1 0 0 0 │ 3 │
├────┼──────────────┼───────┤
│ F │ 1 1 1 1 │ 4 │
├────┼──────────────┼───────┤
│ E │ 1 1 1 0 │ 5 │
├────┼──────────────┼───────┤
│ D │ 1 1 0 1 │ 6 │
├────┼──────────────┼───────┤
│ C │ 1 1 0 0 │ 7 │
├────┼──────────────┼───────┤
│ 3 │ 0 0 1 1 │ 8 │
├────┼──────────────┼───────┤
│ 2 │ 0 0 1 0 │ 9 │
├────┼──────────────┼───────┤
│ 1 │ 0 0 0 1 │ A │
├────┼──────────────┼───────┤
│ 0 │ 0 0 0 0 │ B │
├────┼──────────────┼───────┤
│ 7 │ 0 1 1 1 │ C │
├────┼──────────────┼───────┤
│ 6 │ 0 1 1 0 │ D │
├────┼──────────────┼───────┤
│ 5 │ 0 1 0 1 │ E │
├────┼──────────────┼───────┤
│ 4 │ 0 1 0 0 │ F │
└────┴──────────────┴───────┘
<表四> 設定值與輸出值轉換對照表
現在我們可以用組合語言來控制它了。
┌────────────┬──────────────────┐
│由0378H輸出38H │ │
├────────────┘ │
│MOV AL,38H ;將欲輸出的值存入AL. │
│MOV DX,0378H ;將I/O位址存入DX. │
│OUT DX,AL ;把資料OUT出去. │
└───────────────────────────────┘
┌────────────┬──────────────────┐
│由037AH輸出08H │ │
├────────────┘ │
│MOV AL,03H ;查表四,當實際輸出值為08H時 │
│MOV DX,037AH ;程式設定值為03H. │
│OUT DX,AL │
└───────────────────────────────┘
看到這裡,讀者是否對並列埠有更深一層的了解呢?小弟曾在第 252 期的專欄裡發表過
"始用並列埠製作 AT89C2051 燒錄器"一文後,至今仍有許多讀者來信問小弟如何使用並列埠讀取資料
的問題,小第在此幫各位解答.
關於 PRINTER PORT 的資料線(D0~D7) 在正常的情況下是不能當作輸入使用的.為了可以讓資料輸
入,我們可以用 Print port 的 0379H.4 ~ 0379H.7(PS4,PS5,PS6,PS7),這四個 bit ,再經由74LS244
當作 Buffer 切換,每次讀 4bit 分成兩次即可.如圖一所示.
< 圖一 > 使用並列埠讀取資料
§線路圖 & 說明
首先看到圖二為 ROM 模擬器的結構圖.CN1為公 25 Pin DSUB 連結器,CN2為 28 Pin 的夾式IC Pin,
J1 與 J2 分別是 20 Pin 和 28 Pin 的 HDC 雙排 Pin.
< 圖二 > ROM 模擬器的結構圖
圖三,圖四顯示著J1到CN1和J2到CN2的接線,其中J2雖然是 28 PIN HDC 雙排 Conector,但是 28 PIN
並非標準規格,所以讀者可以使用標準規格的 34 PIN HDC 雙排 Conector來取代,只用到 1 ~ 28 PIN 即可.
排線的使用長度最好是十五到二十公分,排線太長了信號會衰減,亦較容易受電磁干擾.排線太短了會造成操
作上的不方便.
< 圖三 > J1到CN1的接線
< 圖四 > J2到CN2的接線
再來看到圖五是 ROM 模擬器的主線路,看起來有點複雜,但這可是小弟經過千辛萬苦才想出來的電路,
也曾經是小弟開發單晶片時不可缺乏的工具喔.況且如果 ROM 模擬器那麼簡單的話,那麼那些賣模擬器的
廠商豈不是要喝西北風了?言歸正傳,圖五我們看到兩顆 62256 U8,U9 是用來存放 64K BYTE 資料的地方,
在 U5,U6,U7 左邊的 D0...D7,和 A0...A15 分別是模擬 27512 的 D0...D7,和 A0...A15,U10C Pin8 及
U10C Pin 9 分別模擬 27512 的 /OE 及 /CE.U1,U11 是用來將 Print Port 的 PD0...PD7 解成
RD0...RD7,RA0...RA15以便將資料寫入 62256 中.U10,U12,U13 負責控制 Data Bus 與 Address Bus 的
三態流向.
此電路的工作分成兩個時期,Download 時期和模擬時期.
在 Download 時期 U5,U6,U7 這三顆 IC 的第19腳拉到 High,因此 D0...D7,和 A0...A15 呈三態高阻抗輸出
,這是為了防止資料下載時影響 Target Board 的 Bus.
而此時 U2,U3,U4 的左邊輸出 RD0...RD7,和 RA0...RA15,由 RA15 和 U10C 來選擇 U8 或 U9這兩顆 RAM 的
/CE 致能,再經由 /RWE 信號線產生寫入時序,即可將資料寫入 62256 RAM 內,完成 Downlaod動作.
在 Download 時期結束後,
U5,U6,U7 三顆 IC 第19腳拉到 Low,使得
D0...D7,和 RD0...RD7 相通,A0...A15,和 RA0...RA15 相通.
U2,U3,U4 三顆 IC 第1腳拉到 High 以關閉輸出,進入ROM模擬時期,
這時已可以由 D0...D7,和 A0...A15 來讀取資料了.
< 圖五 > ROM 模擬器的主線路
§程式 & 說明
還是一句老話,組合語言是全宇宙公認最複雜最難懂的程式語言,其實組合語言的每一個指令都很簡
單,但是一旦把它們組合成一個程序或模組時,想要由這些指令碼去了解一個程序或模組的行為,則是相當
堅難。這就是組合語言奧妙與藝術的地方。學習組合語言的人口並不多,精通組合語言的人更是希有動物
,有鑑於此,小弟對於此程式不做太詳細的說明。看不懂的人也沒關係,你只要知道大概的原理,會用就好。
;********************************************
;* ROM 模擬器 Download 程式 作者:鄭旭崇 *
;********************************************
PRINT MACRO STR ;DOS 中斷呼叫,顯示字串之巨集定義
MOV DX,OFFSET STR ;
MOV AH,09H ;
INT 21H ;
ENDM ;
INPUT MACRO BUFF ;DOS 中斷呼叫,輸入字串之巨集定義
MOV DX,OFFSET BUFF ;
MOV AH,0AH ;
INT 21H ;
ENDM ;
H_OPEN MACRO FILE_NAME,MODE ;DOS 中斷呼叫,開啟檔案之巨集定義
MOV DX,OFFSET FILE_NAME ;
MOV AL,MODE ;
MOV AH,3DH ;
INT 21H ;
ENDM ;
H_READ MACRO BUFF,BYTE,HAND ;DOS 中斷呼叫,讀取檔案之巨集定義
MOV DX,OFFSET BUFF ;
MOV CX,BYTE ;
MOV BX,HAND ;
MOV AH,3FH ;
INT 21H ;
ENDM
;DOS 中斷呼叫,關閉檔案之巨集定義
H_CLOSE MACRO HAND ;
MOV BX,HAND ;
MOV AH,3EH ;
INT 21H ;
ENDM ;
H_OUT MACRO ABC,DEF ;資料輸出之巨集定義
MOV DX,ABC ;
MOV AL,DEF ;
OUT DX,AL ;
CALL DLY ;
ENDM ;
;=======================================================
_378H EQU 378H ;並列埠 LPT1
_37AH EQU 37AH ;
.MODEL SMALL
.DATA
BUFFER DB 4096 DUP(?) ;存放被Download檔資料 4096 Byte.
PROMPT DB 'COPY RIGHT BY Fraptt Cheng.',10,13,'INPUT FILE NAME:','$'
PROMPT1 DB 10,13,'SUCCESS !$'
PROMPT2 DB 10,13,7,'FILE NOT FOUND!','$'
IN_BUFF DB 32,33 DUP(?) ;存放被燒錄的檔案名稱
HANDLE DW ? ;檔案碼
ADDRESS DB 2 DUP(?) ;Download 位址計數
DAT DB ? ;資料暫存區
.CODE ;程式碼開始
BEGIN: MOV AX,DS
MOV ES,AX
MOV AX,@DATA ;
MOV DS,AX ;
MOV BX,80H ;
MOV AL,ES:[BX] ;
CMP AL,0 ;檢查PSP內有無參數?
JE L1_COM ;
MOV DI,OFFSET IN_BUFF ;PSP內,有參數
;
MOV CX,20 ;將參數值複製一份到 IN_BUFF
L0: MOV AL,ES:[BX] ;
CMP AL,0DH ;
JE L2_COM ;
MOV DS:[DI],AL ;
INC DI ;
INC BX ;
LOOP L0 ;
L1_COM: PRINT PROMPT ;PSP內,沒有參數
INPUT IN_BUFF ;顯示 PROMPT1 提示使用者輸入檔案名稱
L2_COM: ;
MOV BL,IN_BUFF[1] ;
XOR BH,BH ;
MOV BYTE PTR IN_BUFF[BX+2],0;
H_OPEN IN_BUFF+2,0 ;開啟檔案
JC CLOSE1 ;無法開啟跳到 CLOSE1
MOV HANDLE,AX ;
MOV ADDRESS[0],0 ;ROM 模擬器位址記數 = 0
MOV ADDRESS[1],0 ;
LEA SI,BUFFER ;
;--------------------------------------
RD_FL: H_READ BUFFER,4096,HANDLE
CMP AX,0
JE CLOSE
CALL DOWN_LOAD
JMP RD_FL
CLOSE: ;關閉檔案
H_OUT _378H,0FH ;DISABLE 74574
H_OUT _37AH,0C3H
H_OUT _37AH,0CBH
H_OUT _37AH,0C3H
PRINT PROMPT1 ;顯示成功訊息
JMP CLOSE2
CLOSE1: PRINT PROMPT2 ;顯示檔案開啟失敗訊息
CLOSE2: H_CLOSE HANDLE ;關閉檔案
MOV AH,4CH
INT 21H ;離開程式
;=========================================
DOWN_LOAD:
MOV CX,4096 ;DOWN LOAD 4096 BYTES.
D1: LODSB ;AL = SI -> BUFFER DATA.
MOV DAT,AL
CALL WRITE_BYTE
MOV BL,ADDRESS[0] ;ADDRESS = ADDRESS + 1
MOV BH,ADDRESS[1]
INC BX
MOV ADDRESS[0],BL
MOV ADDRESS[1],BH
LOOP D1
LEA SI,BUFFER
EXIT: RET
;============================================
WRITE_BYTE:
H_OUT _378H,00H ;ENABLE 74574
H_OUT _37AH,0C3H
H_OUT _37AH,0CBH
H_OUT _37AH,0C3H
H_OUT _378H,DAT ;TRAN. DATA
H_OUT _37AH,0C2H
H_OUT _37AH,0CAH
H_OUT _37AH,0C2H
H_OUT _378H,ADDRESS[0] ;TRAN. LOW ADDRESS
H_OUT _37AH,0C1H
H_OUT _37AH,0C9H
H_OUT _37AH,0C1H
H_OUT _378H,ADDRESS[1] ;TRAN. HI ADDRESS
H_OUT _37AH,0C0H
H_OUT _37AH,0C8H
H_OUT _37AH,0C0H
H_OUT _37AH,0C6H
H_OUT _37AH,0CEH ;WRITE TO RAM
H_OUT _37AH,0C6H
H_OUT _378H,0FH ;DISABLE 74574
H_OUT _37AH,0C3H
H_OUT _37AH,0CBH
H_OUT _37AH,0C3H
RET
;================================================
DLY: ;延時副程式
PUSH CX
MOV CX,0F2H
DLY1: DEC CX
CMP CX,0
JNE DLY1
POP CX
RET
.STACK ;定義堆疊段
END BEGIN
原始程式以文書編輯軟體寫好後,以檔案名稱為 EROM.ASM 存檔。存檔後便可對
EROM.ASM 進行組譯及連結。組譯軟體必須是 MASM 5.0 以上的版本,使用 MASM 5.0
以下版本的朋友,本原始程式在區段宣告的地方須作小幅度的修改,怎麼修改,請參考相
關書籍。原始程式經過組譯及連結後,產生 EROM.EXE 之可執行檔,可在 DOS 命令列
下直接執行。
組譯程式,在 DOS 提示字元下輸入:
C:\>MASM EROM;;;;
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.
51252 + 258220 Bytes symbol space free
0 Warning Errors
0 Severe Errors
連結程式,在 DOS 提示字元下輸入:
C:\>MASM EROM;;;;
Microsoft (R) 8086 Object Linker Version 3.05
Copyright (C) Microsoft Corp 1983, 1984, 1985. All rights reserved.
-- EROM.EXE 可執行檔已產生 --
執行例:
C:\>EROM TEST.TSK
.....約0.5秒
SUCCESS !
或
C:\>EROM
COPY RIGHT BY Fraptt Cheng.
INPUT FILE NAME:TEST.TSK
.....約0.5秒
SUCCESS !
§結語
這個 ROM 模擬器已經跟隨著小弟做過許多 CASE ,說實在還挺好用的.而今發表出來無非是想要
讓更多有緣的人一起分享小弟的成果,讓大家有一個更好的學習開發環境.其實說到 Print Port 還有
很多東西可以做的,像是,模擬PLC 等等,有興趣的讀者不妨研究看看,也許還會發掘
更多用途呢!讀者朋友對於本文章有任何問題或建議,歡迎您 E-mail 給我,小弟的 E-mail是 :
FineTech@ms69.hinet.net 當然,讀者朋友們想要程式的 Source Code 的話,也可以來信索取.