所謂的數字輸出就是在程序要求某一個設備的某一開關點開或關,產生高電位或低電位。從計算機的觀點來說,低電位就是0.7V以下(邏輯0),而高電位是2.1V以上(邏輯1),若電位處在0.7~2.1V時,電位的邏輯狀態是不確定的。想要通過計算機去控制外部設備,最簡單的方法就是控制數字輸出。
所謂的數字輸入,也就是外界的狀況被計算機用0或1的數值予以記錄下來而儲存,此0與1就代表了外界某一個設備的某一開關點開或關的兩種情形。
PC并行口即可以作數字輸出口,也可以作數字輸入口。其中的數據端口、控制端口都可以作為數字輸出端口,數據端口共8位,控制端口共4位,兩個端口可以組成1~12位的任意數字輸出端口;其中的狀態端口、控制端口都可以作為數字輸入端口,狀態端口共5位,控制端口共4位,兩個端口可以組成1~9位的任意數字輸入端口。本文給出了并行端口3種寄存器的讀寫方法,如下圖所示:
?
四、PC并行口數字輸入/輸出的VC實現
由于Windows對系統底層操作采取了屏蔽的策略,因而對用戶而言,系統變得更為安全,但這卻給眾多的硬件或者系統軟件開發人員帶來了不小的困難,因為只要應用中涉及到底層的操作,開發人員就不得不深入到Windows的內核去編寫屬于系統級的設備驅動程序。對并行口的讀寫操作就是如此,由于Windows對系統的保護,絕對不允許任何的直接I/O動作發生,所以必須帶上*.dll、*.sys或*.vxd文件,這些文件用來讓操作系統知道有一個特定的I/O可能會被調用。系統開機后,這些文件中的內容就會加載到內存中,一旦有對應的動作發生,就會引發I/O的實際動作。
本文只是介紹并行口作為數字I/O口的使用,不在于介紹并行I/O口驅動的編寫。故本文中直接使用由 Yariv Kaplan 編寫的 WinIo 庫,它有如下特點:WinIo 庫通過使用內核模式下設備驅動程序和 其它一些底層編程技巧繞過 Windows 安全保護機制,允許32位 Windows 程序直接對 I/O 口進行操作。
支持Windows 9x、Windows NT、Windows2000、WindowsXP環境;在Windows NT/2000/XP下,允許非 Administrator 用戶應用 WinIo 應用程序;不支持中斷。
注意事項:使用這個類代碼時請確保不要與其它使用常規 Win32 調用操作并行端口的程序發生沖突。
WinIo庫在VC應用程序中的使用(WinIo庫下載)
為了在VC中能正常使用WinIo庫,必須按以下步驟進行配置:
(1):將WinIo.dll、WinIo.sys、WINIO.VXD三個文件放在程序可執行文件所在目錄下;
(2):將WinIo.lib添加到工程中,WinIo.lib及winio.h文件必須放在工程目錄下;
(3):在StdAfx.h頭文件中加入#include "winio.h"語句;
(4):調用InitializeWinIo函數初始化WinIo驅動庫;
(5):調用讀寫IO口的GetPortVal或SetPortVal函數;
(6):調用ShutdownWinIo函數;
在非管理員權限下運行,必須首先完成以下步驟:
(1):將WinIo.dll、WinIo.sys、WINIO.VXD三個文件放在任一WinIo應用程序可執行文件所在目錄下;
(2):以管理員或其它具有管理員權限的用戶身份登陸;
(3):調用InstallWinIoDriver函數,第一個參數設置為WinIo.sys文件所在目錄路徑,第二個參數設置為false;
(4):重新啟動系統;
(5):以普通用戶身份登錄,現在可以調用WinIo庫函數;
(6):當不再需要WinIo庫時,可以再次以管理員身份或其它具有管理員權限的用戶身份登陸系統,調用RemoveWinIoDriver卸載該庫;
WinIo庫中幾個函數說明:
(1):初始化與終止
bool _stdcall InitializeWinIo();
void _stdcall ShutdownWinIo();
(2):安裝與卸載
bool _stdcall InstallWinIoDriver(PSTR pszWinIoDriverPath, bool IsDemandLoaded = false);
bool _stdcall RemoveWinIoDriver();
(3):讀寫I/O口
bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize);
bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize);
GetPortVal函數從指定端口讀取一個BYTE/WORD/DWORD類型的值;
wPortAddr是指定一個端口地址值;
pdwPortVal為指向一雙字節型變量的指針,該變量存儲從wPortAddr端口讀取的值;
bSize指定讀取字節數,值可以為1,2或4。
SetPortVal函數向指定端口寫入一個BYTE/WORD/DWORD類型的值;
除dwPortVal為輸入參數,表示待寫入外,其余個變量含義與GetPortVal相似。
PC并行口數字輸出的VC實現(示例工程下載)
為了測試并行口的數字輸出,可以準備12支LED發光二極管,將LED的陽極分別與數據端口引腳Pin2~Pin9和控制端口引腳Pin1、Pin14、Pin16、Pin17相連接;將LED的陰極連接在一起與并行口的歸地引腳GND相連即可。在實際控制應用中不能這樣連接,因為數據端口引腳、控制端口引腳輸出的電流非常小,只有10mA左右,必須添加 其它硬件電路。
(1):數據端口數字輸出的VC實現
//獲得數據端口地址
WORD m_nport=(WORD)0x378;
//獲得要寫入數據端口的值WriteValue(數據范圍為0~255)
DWORD m_nValue=(DWORD)WriteValue;
//調用WinIo庫函數SetPortVal寫端口值
SetPortVal(m_nport, m_nValue, 1);//write a BYTE value to an I/O port
(2):控制端口數字輸出的VC實現
//獲得控制端口地址
WORD m_nport=(WORD)0x37A;
//獲得控制端口的值,保持高位值不變,將要輸出的值從低4位輸出,且使連接器上的電位狀態與想輸出的值一致
DWORD temp_dwPortVal;
unsigned int temp_aa;
GetPortVal(m_nport, &temp_dwPortVal, 1); //reads a BYTE value from an I/O port
temp_aa=(unsigned int)temp_dwPortVal;
temp_aa=temp_aa&0x0F0; //取低8位值,將低4位置為0;高4位不變;
temp_aa=temp_aa^0x0B; //將低4位中C0、C1、C3置為1,C2置為0;高4位不變;
//獲得要寫入控制端口的值WriteValue(數據范圍為0~15)
unsigned int WriValue;
WriValue=WriteValue&0x0F; //取低4位;
temp_aa=temp_aa^WriValue; //將寫入值的低4位中的C0、C1、C3取反,C2位不變,高4位保持端口值不變
SetPortVal(m_nport, (DWORD)temp_aa, 1); //寫出的值中,高4位保持端口原來的值不變,
//低4位是寫入什么電平,連接器上既是什么電平
(3):數據端口及控制端口組合成12位數字輸出的VC實現
//獲得端口地址
WORD m_nportData=(WORD)0x378;
WORD m_nportControl=(WORD)0x37A;
//獲得要寫入端口的值WriteValue(數據范圍為0~4095)
DWORD m_nValue=(DWORD)(WriteValue&0x0FF);//取低8位值
SetPortVal(m_nportData, m_nValue, 1);//write a BYTE value to Data port
DWORD temp_dwPortVal;
unsigned int temp_aa;
GetPortVal(m_nportControl, &temp_dwPortVal, 1); //reads a BYTE value from an I/O port
temp_aa=(unsigned int)temp_dwPortVal;
temp_aa=temp_aa&0x0F0; //取低8位值,將低4位置為0;高4位不變;
temp_aa=temp_aa^0x0B; //將低4位中C0、C1、C3置為1,C2置為0;高4位不變;
unsigned int WriValue;
WriValue=WriValue>>8;//取高4位值
temp_aa=temp_aa^WriValue; //將寫入值的低4位中的C0、C1、C3取反,C2位不變,高4位保持端口值不變
SetPortVal(m_nportControl, (DWORD)temp_aa, 1); //寫出的值中,高4位保持端口原來的值不變,
//低4位是寫入什么電平,連接器上既是什么電平
評論
查看更多