早些時候寫的一個Delphi中的串列埠通讀類.
這個是早期的版本,後期我做了很大的修動...僅做為學習參考用.
在做資料採集,及控制系統中,我建議大家自己用API寫通訊類..不要使用SPCOMM,以及MSCOMM...在實際的應用中,自己寫的通訊類在應用上會更加的靈活方便(^^當然寫這個通訊類是比較費時的...)
在做資料採集時,可以自己很方便的加入CRC或者checksum校驗方式..51以CRC8 /16為主......採用CRC可以使用資料傳輸更加的可靠..
{
This unit create by 李金浩
2004-3-12號23:26修正
QQ:67260745
E-Mail:[email protected]
}
interface
uses
Forms, SysUtils, Windows, Messages, Dialogs, Controls, Classes, ToolWin, ComCtrls,
ExtCtrls, StdCtrls, Math;
//----------------
(*串列埠號*)
const
Com1=1;
Com2=2;
Com3=3;
Com4=4;
Com5=5;
Com6=6;
Com7=7;
Com8=8;
Com9=9;
Com10=10;
(*StopBit*)
sbit1=0;
sbit1_5=1;
sbit2=2;
(*modem 事件常量*)
MY_CTS=1; //The CTS (clear-to-send) signal is on.
MY_DSRL=2; //The DSR (data-set-ready) signal is on.
MY_RING=4; //The ring indicator signal is on.
MY_RLSD=8; //The RLSD (receive-line-signal-detect) signal is on.
(*處理訊息*)
MY_ReadComm=WM_User+507;
Type
TMyComm=Class
public
(*關閉指定串列埠*)
//********************
Function CloseComm(Const Com:integer;const CloseAll:boolean=False):boolean;
(*開啟指定串列埠*)
function OpenComm(Const COM:integer;
Const My_BandRate:DWORD=4800;
Const My_ByteSize:byte=8;
Const My_Parity:byte=NoParity;
Const My_StopBits:byte=0):Boolean;
//讀串列埠函式集
Function ReadComm_string(Const Com:integer;var revcStr:string;const len:DWORD=0):boolean;//讀取串列埠string
Function ReadComm_ByteArray(const Com:integer;var revcArray:array of byte;const len:DWORD=0):boolean;
Function ReadComm_Byte(Const Com:integer;var OneByte:byte):boolean;
//寫串列埠口函式集
Function WriteComm_String(Const Com:integer;Const SendString:string):boolean;
Function WriteComm_ByteArray(Const Com:integer;const SendByte:array of byte;Buflong:DWORD):boolean;
Function WriteComm_Byte(Const Com:integer;const SendByte:byte):boolean;
//--------------
Function GetRXDsize(com:integer):integer; //得到RXD緩衝區資料長度
Function GetModemState(com:integer):DWord;//得到狀態口的狀態
procedure SetReadOFFByte(offByte:byte=$13);//設定接收停止結束符
Function IsReadOFFByte(RByte:byte):boolean;//判斷接收的是不是停止結束符
procedure ClearRXD(com:integer);//清空RXD緩衝區內容
procedure ClearTXD(com:integer);//清空TXD緩衝區內容
procedure ClearComBuf(com:integer);//清空所有緩衝區
end;
//---------------------
var
MComm:TMycomm;//建立TMycomm例項
// myThread:TThread;
// Timer1:TTimer;
bOFFByte:byte;//接收結束byte
lpDCB:TDCB;
COMHandle:array[1..10] of Thandle; //檔案控制代碼
ComOpenFlag:array[1..10] of boolean;//檔案開啟標識
rCommTimeouts:COMMTIMEOUTS;
bSuccessFlag:boolean;
ipError:Dword;
lpstat:PcomStat;
abSendBuf,abRecvBuf:array[1..1024] of byte;
nBytesWrite,nBytesRead:DWORD;//設定已寫/讀的數量
i:integer;
//---------
implementation
{***************************************************}
(*開啟檔案控制代碼 *)
(*預設格式如:MComm.OpenComm(com1,4800,8,NoParity,0)*)
{***************************************************}
function TMyComm.OpenComm(const COM:integer; //埠號
const My_BandRate:DWORD;//波特率
Const My_ByteSize:byte; //資料位
Const My_Parity:byte; //是否有奇偶校驗
Const My_StopBits:byte):Boolean;//開啟指定串列埠//開啟指定串列埠
var //預設設定格式為:4800,8,N,1
comNum:string;
begin
//如果ComOpenFlag[COM]=false 表示未開啟。。。則進行操作
if not ComOpenFlag[COM] then//if ComOpenFlag[COM]=false
begin
comNum:=format('Com%d',[com]);
(*第一。創鍵檔案控制代碼*)
ComHandle[com]:=Createfile(pAnsiChar(comNum),
GENERIC_Read or GENERIC_Write,(*訪問讀寫方式*)
0,(*不共享*)
nil,(*無安全屬性指標*)
open_existing,(*建立方式*)
file_attribute_normal,0);
if ComHandle[com]=invalid_handle_value then
begin
// showmessage('com1開啟錯誤!');
CloseComm(com); //呼叫關閉串列埠
result:=false;
exit;
end
else begin
result:=True;
ComOpenFlag[COM]:=true //表示開啟過
end; // if ComHandle[com]=invalid_handle_value then
(*第二:裝置com輸入輸出緩衝區*)
bSuccessFlag:=SetupComm(ComHandle[com],4096,4096);
if not bSuccessFlag then
begin
showmessage('裝置com輸入輸出緩衝區錯誤!');
CloseComm(com);
result:=false;
exit;
end;
(*第三:取得預設DCB*)
bSuccessFlag:=GetCommstate(ComHandle[com],lpDcb);
if not bSuccessFlag then
begin
// showmessage('取得預設DCB錯誤!');
CloseCOMM(ComHandle[com]);
result:=false;
exit;
end;
(*第四,設定DCB*)
//4800,8,N,1
lpDCB.BaudRate:=My_BandRate;
lpDCB.ByteSize:=My_ByteSize;
lpDCB.Parity:=My_Parity;//N無奇偶校驗
lpDCB.StopBits:=My_StopBits;//0,1,2===>1,1.5,2
bSuccessFlag:=SetCommstate(ComHandle[com],lpDCB);
if not bSuccessFlag then
begin
// showmessage('設定DCB錯誤!');
CloseCOMM(ComHandle[com]);
exit;
end;
ClearComBuf(Com);//清空所有緩衝區
ClearCommError(ComHandle[com],iperror,lpstat);
(*第六 設定TimeOut*)
rCommTimeouts.ReadIntervalTimeout:=0;
rCommTimeouts.ReadTotalTimeoutConstant:=250;
rCommTimeouts.ReadTotalTimeoutMultiplier:=0;
rCommTimeouts.WriteTotalTimeoutMultiplier:=0;
rCommTimeouts.WriteTotalTimeoutConstant:=250;
bSuccessFlag:=SetCommTimeOuts(ComHandle[com],rCommTimeouts);
//EV_RXCHAR A character was received and placed in the input buffer.
SetCommMask(comHandle[com],EV_RXCHAR
or EV_CTS
or EV_DSR
or EV_RING
or EV_RLSD); //設定接收訊息
//------------------------------------------
if not bSuccessFlag then
begin
// showmessage('設定TimeOut出錯!');
result:=false;
CloseCOMM(ComHandle[com]);
exit;
end;
end else begin
result:=false;
end;
end;
{**************************************************}
(*關閉檔案控制代碼 *)
(*CloseAll:boolean預設為false;為True時關閉所有埠*)
{**************************************************}
Function TMyComm.CloseComm(Const Com:integer;const CloseAll:boolean):boolean;
var
cSucc:boolean;
i:integer;
begin
//關閉檔案控制代碼
if not CloseAll then
begin
cSucc:=true;
if ComOpenFlag[COM] then //如果處於開啟,就進行關閉處理
begin
cSucc:=CloseHandle(ComHandle[com]);
ComOpenFlag[COM]:=false;//設為false。表示已關閉
end;
result:=cSucc;
end else
begin
//關閉所有埠
for i:=1 to 10 do
begin
CloseHandle(ComHandle[i]);
end;
result:=True;;
end;
//----------------
end;
{******************************}
(* 讀串列埠 ReadComm_string *)
(* 讀取string *)
{******************************}
Function TMyComm.ReadComm_string(Const Com:integer;var revcStr:string;const len:DWORD=0):boolean;
var
SL:DWORD;
begin
//在讀取前消空緩衝區
result:=True;
SL:=len;
//如果為len=0 則系統自動獲取緩衝區長度
if len=0 then SL:=GetRxDSize(Com);
revcStr:='';
bSuccessFlag:=ReadFile(ComHandle[com],Pointer(revcStr)^,SL,nBytesRead,nil);
if (not bSuccessFlag) or (nBytesRead=0) then result:=false;
end;
{******************************}
(* 讀取byte陣列 *)
{******************************}
Function TMyComm.ReadComm_ByteArray(const Com:integer;
var revcArray:array of byte;
const len:DWORD=0):boolean;
var
i:integer;
SL:DWORD;
begin
result:=True;
SL:=len;
//如果為len=0 則系統自動獲取緩衝區長度
if len=0 then SL:=GetRXDsize(ComHandle[com]);
if GetRXDsize(ComHandle[com])>high(revcArray) then//如果接緩衝區的資料大於陣列就出錯
begin
ClearRXD(ComHandle[com]);//出錯時清空讀取緩衝區
result:=false;
exit;
end;
//在讀取前消空緩衝陣列
for i:=low(revcArray) to high(revcArray) do
begin //清空讀寫陣列,防止讀取亂碼
revcArray[i]:=byte(0);
end;
bSuccessFlag:=ReadFile(ComHandle[com],revcArray,SL,nBytesRead,nil);
if (not bSuccessFlag) or (nBytesRead=0) then result:=false;
end;
{******************************}
(* 讀串列埠 ReadComm_Byte *)
(* 讀取一個Byte *)
{******************************}
Function TMyComm.ReadComm_Byte(Const Com:integer;var OneByte:byte):boolean;
begin
result:=true;
if GetRXDSize(com)<=0 then
begin
result:=false;
exit;
end;
bSuccessFlag:=ReadFile(ComHandle[com],OneByte,1,nBytesRead,nil);
if (not bSuccessFlag) or (nBytesRead=0) then result:=false;
end;
{******************************}
(* 寫串列埠WriteComm_String *)
{******************************}
Function TMyComm.WriteComm_String(Const Com:integer;Const SendString:string):boolean;
begin
result:=true;
PurgeComm(ComHandle[com],4);//清空TXD緩衝區內空
bSuccessFlag:=writeFile(ComHandle[com],pointer(SendString)^,length(sendString),nBytesWrite,nil);
if (not bSuccessFlag) or (nBytesWrite=0) then result:=false;
end;
{***************************}
(*寫串列埠WriteComm_ByteArray*)
(*傳送一個byte 陣列 *)
{***************************}
Function TmyComm.WriteComm_ByteArray(Const Com:integer;const SendByte:array of byte;Buflong:DWORD):boolean;
begin
result:=true;
//----------------
ClearTXD(ComHandle[com]);//清空TXD緩衝區內空
bSuccessFlag:=writeFile(ComHandle[com],SendByte,Buflong,nBytesWrite,nil);
if (not bSuccessFlag) or (nBytesWrite=0) then result:=false;
end;
{***************************}
(* WriteComm_Byte *)
(* 寫入一個byte *)
{***************************}
function TMyComm.WriteComm_Byte(const Com: integer;const SendByte:byte): boolean;
begin
result:=true;
//----------------
ClearTXD(ComHandle[com]);//清空TXD緩衝區內空
bSuccessFlag:=writeFile(ComHandle[com],SendByte,1,nBytesWrite,nil);
if (not bSuccessFlag) or (nBytesWrite=0) then result:=false;
end;
{**************************************}
(* 得到RXD緩衝區的資料長度 *)
{**************************************}
function TMyComm.GetRXDsize(com:integer): integer;
var
cs:TComstat;
begin
ClearCommError(ComHandle[com],iperror,@cs);
result:=cs.cbInQue
end;
{******************}
(* 清空RXD *)
{******************}
procedure TMyComm.ClearRXD(com: integer);
begin
PurgeComm(ComHandle[com],8);//清空RXD緩衝區內空
end;
{*************************************}
(* 清空所有緩衝區 *)
{*************************************}
procedure TMyComm.ClearComBuf(com:integer);
begin
//第五:通過PurgeComm清空指定通訊口的輸入輸出緩衝區的所有字元
// PURGE_TXABORT = 1; { Kill the pending/current writes to the comm port. }
// PURGE_RXABORT = 2; { Kill the pending/current reads to the comm port. }
// PURGE_TXCLEAR = 4; { Kill the transmit queue if there. }
// PURGE_RXCLEAR = 8; { Kill the typeahead buffer if there. }
PurgeComm(ComHandle[com],1 or 2 or 4 or 8);
end;
{******************}
(* 清空TXD *)
{******************}
procedure TMyComm.ClearTXD(com: integer);
begin
PurgeComm(ComHandle[com],4);//清空TXD緩衝區內空
end;
{*******************************}
// 埠狀態訊息說明
// MS_CTS_ON //The CTS (clear-to-send) signal is on.
// MS_DSR_ON //The DSR (data-set-ready) signal is on.
// MS_RING_ON //The ring indicator signal is on.
// MS_RLSD_ON //The RLSD (receive-line-signal-detect) signal is on.
{*******************************}
function TMyComm.GetModemState(com: integer): DWord;
var
dwModemState:DWord;
begin
if GetCommModemStatus(ComHandle[com],dwModemState) then
result:=dwModemState
else
result:=0;//操作失敗返回為0
end;
{************************************************}
{設定接收結束byte--->設定全域性變數offByte }
{注:這裡的接收結束byte不是DCB裡XoffChar是自定義的}
{************************************************}
procedure TMyComm.SetReadOFFByte(offByte: byte);
begin
bOFFByte:=offByte
end;
{*****************************************}
{判斷設定的結束byte--->讀取全域性變數offByte}
{*****************************************}
function TMyComm.IsReadOFFByte(RByte: byte): boolean;
begin
result:=RByte=bOFFByte
end;
initialization
MComm:= TMycomm.Create;
finalization
MComm.CloseComm(0,True);//關閉所有埠
MComm.Free;
end.