雖然 USB 已取代並行埠成為主流,但在工業控制、舊式印表機、嵌入式開發板等領域,並行埠(LPT1/LPT2)仍不可或缺。本文介紹一個封裝良好的 MFC 類別 CParallelPort,提供低層 I/O 存取、跨 Windows 9x/ME/NT/2000/XP 相容、Unicode 專案相容,並附贈 PC-to-PC 檔案傳輸範例程式。
| 項目 | 說明 |
|---|---|
| 支援平台 | Windows 9x, ME, NT 4.0, 2000, XP, Server 2003 (32/64-bit) |
| 字元集 | ANSI / Unicode 皆可編譯,自動適配 |
| 專案類型 | 主控台 / GUI / DLL / 靜態/動態連結 MFC 均可 |
| 核心功能 | 資料/狀態/控制暫存器讀寫、中斷處理、EPP/ECP 模式切換 |
| 範例應用 | 雙機並行傳纜 (LapLink 型) 檔案傳輸 (Client/Server) |
class CParallelPort {
public:
// 建構/解構
CParallelPort();
~CParallelPort();
// 開啟/關閉埠 (預設 LPT1, 0x378)
BOOL Open(LPCTSTR pszPortName = _T("LPT1"));
void Close();
// 低層暫存器存取
BYTE ReadData(); // 讀取資料暫存器 (基址 + 0)
void WriteData(BYTE b); // 寫入資料暫存器
BYTE ReadStatus(); // 讀取狀態暫存器 (基址 + 1)
BYTE ReadControl(); // 讀取控制暫存器 (基址 + 2)
void WriteControl(BYTE b); // 寫入控制暫存器
// 高層資料傳輸 (手搖協定)
BOOL WriteByte(BYTE b, DWORD dwTimeout = 1000);
BOOL ReadByte(BYTE& b, DWORD dwTimeout = 1000);
DWORD WriteBlock(const BYTE* pData, DWORD dwLen, DWORD dwTimeout = 5000);
DWORD ReadBlock(BYTE* pData, DWORD dwLen, DWORD dwTimeout = 5000);
// 狀態查詢
BOOL IsOpen() const;
BOOL IsPaperOut() const;
BOOL IsSelected() const;
BOOL IsError() const;
// NT/2000/XP 需安裝 DriverLINX PortIO 驅動
static BOOL IsDriverInstalled();
};
ParallelPort.cpp 加入專案,#include "ParallelPort.h" 於需使用模組。#include 加入預編譯標頭 (stdafx.h) 提升編譯速度。InpOut32.dll 低層 I/O 會失敗。使用標準 LapLink 並行傳輸線 (DB25 公對公),內部交叉連接:
Pin 2 (D0) ↔ Pin 15 (Error)
Pin 3 (D1) ↔ Pin 13 (Select)
Pin 4 (D2) ↔ Pin 12 (PaperEnd)
Pin 5 (D3) ↔ Pin 10 (Ack)
Pin 6 (D4) ↔ Pin 11 (Busy)
Pin 18-25 (GND) 共地
sequenceDiagram
participant Sender
participant Receiver
Sender->>Receiver: WriteData (高 4 位) + Strobe=1
Receiver->>Sender: Ack=0 (Busy=1)
Sender->>Receiver: Strobe=0
Receiver->>Sender: Ack=1 (Busy=0) -> Ready for next nibble
... 重複傳送低 4 位 ...
... 重複直到檔案結束 ...
void CServerDlg::OnStartServer()
{
m_port.Open(_T("LPT1"));
m_port.WriteControl(0x0C); // 初始化控制暫存器: IRQ啟用, 方向=輸出
CFile file(_T("send.dat"), CFile::modeRead);
BYTE buf[1024];
UINT nRead;
while ((nRead = file.Read(buf, 1024)) > 0) {
m_port.WriteBlock(buf, nRead);
UpdateProgress(file.GetPosition(), file.GetLength());
}
file.Close();
m_port.Close();
}
void CClientDlg::OnStartClient()
{
m_port.Open(_T("LPT1"));
m_port.WriteControl(0x04); // 方向=輸入, 啟用中斷
CFile file(_T("recv.dat"), CFile::modeCreate | CFile::modeWrite);
BYTE buf[1024];
DWORD nRead;
while ((nRead = m_port.ReadBlock(buf, 1024)) > 0) {
file.Write(buf, nRead);
UpdateProgress(file.GetPosition());
if (nRead < 1024) break; // 最後一包
}
file.Close();
m_port.Close();
}
| 現象 | 原因 | 對策 |
|---|---|---|
| Open() 失敗 | 埠被佔用/不存在/驅動未裝 | 裝置管理員確認 LPT1、安裝 DriverLINX、關閉佔用程式 |
| 傳輸資料錯誤/中斷 | 接線錯誤/接地不良/手搖超時 | 檢查 LapLink 線序、縮短線長、增加 Timeout |
| Unicode 專案編譯錯誤 | 字串字面值未加 _T() | 所有字串常數包裹 _T()、使用 LPCTSTR/LPTSTR |
| 64 位元 OS 無法存取 | DriverLINX 無 64 位元版 | 改用 USB-並行轉接器 (支援 WinUSB/虛擬 COM) |