unit Unit1;<br><br>interface<br><br>uses<br> Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br> Dialogs, StdCtrls, ComCtrls;<br><br>const<br> WM_COMMNOTIFY = WM_USER + 100; // 通讯消息<br><br>type<br> TForm1 = class(TForm)<br> StatusBar1: TStatusBar;<br> Memo1: TMemo;<br> Memo2: TMemo;<br> Label1: TLabel;<br> Label2: TLabel;<br> GroupBox1: TGroupBox;<br> Label3: TLabel;<br> Label4: TLabel;<br> Label5: TLabel;<br> Label6: TLabel;<br> ComboBox4: TComboBox;<br> ComboBox3: TComboBox;<br> ComboBox2: TComboBox;<br> ComboBox1: TComboBox;<br> Label7: TLabel;<br> ComboBox5: TComboBox;<br> btnOpenCom: TButton;<br> btnSendData: TButton;<br> btnReceiveData: TButton;<br> btnCloseCom: TButton;<br> procedure btnOpenComClick(Sender: TObject);<br> procedure FormCreate(Sender: TObject);<br> procedure btnCloseComClick(Sender: TObject);<br> procedure btnSendDataClick(Sender: TObject);<br> procedure btnReceiveDataClick(Sender: TObject);<br> private<br> { Private declarations }<br> procedure WMCOMMNOTIFY(var Message :TMessage);message WM_COMMNOTIFY;<br> public<br> { Public declarations }<br> end;<br><br>var<br> Form1: TForm1;<br><br>implementation<br><br>{$R *.dfm}<br><br>var<br> CommHandle:THandle;<br> PostEvent:THandle;<br> ReadOs : Toverlapped;<br> Connected:Boolean;<br> Receive :Boolean;<br> ReceiveData : Dword;<br><br>procedure AddToMemo(Str
Char;Len
word); // 接收的数据送入显示区Memo2<br>begin<br> //接收厚的字符串为NULL终止<br> str[Len]:=#0;<br> Form1.Memo2.Text:=Form1.Memo2.Text+StrPas(str);<br>end;<br><br><br>procedure CommWatch(Ptr
ointer);stdcall; // 通讯监视线程<br>var<br> dwEvtMask,dwTranser : Dword;<br> PostMsgFlag: Boolean;<br> overlapped : Toverlapped;<br><br>begin<br> Receive :=True;<br> FillChar(overlapped,SizeOf(overlapped),0);<br> overlapped.hEvent :=CreateEvent(nil,True,False,nil); // 创建重叠读事件对象<br> if overlapped.hEvent=null then<br> begin<br> MessageBox(0,'overlapped.Event Create Error !','Notice',MB_OK);<br> Exit;<br> end;<br><br> //进入串口监视状态,直到全局变量Receive置为False停止<br> while(Receive) do<br> begin<br> dwEvtMask:=0;<br> // 等待串口事件发生<br> if not WaitCommEvent(CommHandle,dwEvtMask,@overlapped) then<br> begin<br> if ERROR_IO_PENDING=GetLastError then<br> GetOverLappedResult(CommHandle,overlapped,dwTranser,True)<br> end;<br><br> //串口读事件发布消息 <br> if ((dwEvtMask and EV_RXCHAR)=EV_RXCHAR) then<br> begin<br> // 等待允许传递WM_COMMNOTIFY通讯消息<br> WaitForSingleObject(Postevent,INFINITE);<br> // 处理WM_COMMNOTIFY消息时不再发送WM_COMMNOTIFY消息<br> ResetEvent(PostEvent);<br> // 传递WM_COMMNOTIFY通讯消息,告知主线程调用读串口的过程<br> PostMsgFlag:=PostMessage(Form1.Handle,WM_COMMNOTIFY,CommHandle,0);<br> if (not PostMsgFlag) then<br> begin<br> MessageBox(0,'PostMessage Error !','Notice',MB_OK);<br> Exit;<br> end;<br> end;<br> end;<br> CloseHandle(overlapped.hEvent); // 关闭重叠读事件对象<br>end;<br><br><br>procedure TForm1.WMCOMMNOTIFY(var Message :TMessage); // 消息处理函数<br>var<br> CommState : ComStat;<br> dwNumberOfBytesRead : Dword;<br> ErrorFlag : Dword;<br> InputBuffer : Array [0..1024] of Char;<br><br>begin<br> if not ClearCommError(CommHandle,ErrorFlag,@CommState) then<br> begin<br> MessageBox(0,'ClearCommError !','Notice',MB_OK);<br> PurgeComm(CommHandle,Purge_Rxabort or Purge_Rxclear);<br> Exit;<br> end;<br><br> if CommState.cbInQue>0 then<br> begin<br> fillchar(InputBuffer,CommState.cbInQue,#0);<br> // 接收通讯数据<br> if (not ReadFile( CommHandle,InputBuffer,CommState.cbInQue,<br> dwNumberOfBytesRead,@ReadOs )) then<br> begin<br> ErrorFlag := GetLastError();<br> if (ErrorFlag <> 0) and (ErrorFlag <> ERROR_IO_PENDING) then<br> begin<br> MessageBox(0,'ReadFile Error!','Notice',MB_OK);<br> Receive :=False;<br> CloseHandle(ReadOs.hEvent);<br> CloseHandle(PostEvent);<br> CloseHandle(CommHandle);<br> Exit;<br> end<br> else begin<br> WaitForSingleObject(CommHandle,INFINITE); // 等待操作完成<br> GetOverlappedResult(CommHandle,ReadOs,dwNumberOfBytesRead,False);<br> end;<br> end;<br> if dwNumberOfBytesRead>0 then<br> begin<br> ReadOs.Offset :=ReadOs.Offset+dwNumberOfBytesRead;<br> ReceiveData := ReadOs.Offset;<br> // 处理接收的数据<br> AddToMemo(InputBuffer,dwNumberOfBytesRead);<br> end;<br> end;<br> // 允许发送下一个WM_COMMNOTIFY消息<br> SetEvent(PostEvent);<br>end;<br><br><br>procedure TForm1.btnOpenComClick(Sender: TObject);<br>var<br> CommTimeOut : TCOMMTIMEOUTS;<br> DCB : TDCB;<br><br>begin<br> StatusBar1.SimpleText := '连接中...';<br><br> //发送消息的句柄<br> PostEvent:=CreateEvent(nil,True,True,nil);<br> if PostEvent=null then<br> begin<br> MessageBox(0,'CreateEvent Error!','Notice',MB_OK);<br> StatusBar1.SimpleText := '串口打开失败';<br> Exit;<br> end;<br><br> //Overlapped Read建立句柄<br> ReadOs.hEvent :=CreateEvent(nil,true,False,nil);<br> if ReadOs.hEvent=null then<br> begin<br> MessageBox(0,'CreateEvent Error!','Notice',MB_OK);<br> CloseHandle(PostEvent);<br> StatusBar1.SimpleText := '串口打开失败';<br> Exit;<br> end;<br><br> //建立串口句柄<br> CommHandle := CreateFile(PChar(ComboBox1.Text),GENERIC_WRITE or GENERIC_READ,<br> 0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL,0);<br><br> if CommHandle = INVALID_HANDLE_VALUE then<br> begin<br> CloseHandle(PostEvent);<br> CloseHandle(ReadOs.hEvent);<br> MessageBox(0,'串口打开失败!','Notice',MB_OK);<br> StatusBar1.SimpleText := '串口打开失败';<br> Exit;<br> end;<br> StatusBar1.SimpleText := '已同端口 '+ ComboBox1.Text + ' 连接!';<br><br> //设置超时<br> CommTimeOut.ReadIntervalTimeout := MAXDWORD;<br> CommTimeOut.ReadTotalTimeoutMultiplier := 0;<br> CommTimeOut.ReadTotalTimeoutConstant := 0;<br> SetCommTimeouts(CommHandle, CommTimeOut);<br><br> //设置读写缓存<br> SetupComm(CommHandle,4096,1024);<br><br> //对串口进行指定配置<br> GetCommState(CommHandle,DCB);<br> DCB.BaudRate := StrToInt(ComboBox2.Text);<br> DCB.ByteSize := StrToInt(ComboBox3.Text);<br> DCB.Parity := ComboBox4.ItemIndex;;<br> DCB.StopBits := ComboBox5.ItemIndex;<br> Connected := SetCommState(CommHandle, DCB);<br><br> //关系串口的读事件<br> if (not SetCommMask(CommHandle,EV_RXCHAR)) then<br> begin<br> MessageBox(0,'SetCommMask Error !','Notice',MB_OK);<br> Exit;<br> end;<br><br> if (Connected) then<br> begin<br> btnOpenCom.Enabled :=False;<br> end<br> else begin<br> CloseHandle(CommHandle);<br> StatusBar1.SimpleText := '设置串口失败';<br> end;<br>end;<br><br>procedure TForm1.FormCreate(Sender: TObject);<br>begin<br> Connected:=False;<br> ComboBox1.ItemIndex:=0;<br> ComboBox2.ItemIndex:=0;<br> ComboBox3.ItemIndex:=4;<br> ComboBox4.ItemIndex:=0;<br> ComboBox5.ItemIndex:=0; <br>end;<br><br>procedure TForm1.btnCloseComClick(Sender: TObject);<br>begin<br> if not Connected then<br> begin<br> StatusBar1.SimpleText := '未打开串口';<br> Exit;<br> end;<br> Receive :=False;<br> //取消事件监视,此时监视线程中的WaitCommEvent将返回<br> SetCommMask(CommHandle,0);<br> //等待监视线程结束<br> WaitForSingleObject(PostEvent,INFINITE);<br> //关闭事件句柄<br> CloseHandle(PostEvent);<br> //停止发送和接收数据,并清除发送和接收缓冲区<br> PurgeComm(CommHandle,PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR);<br> //关闭其他的句柄<br> CloseHandle(ReadOs.hEvent);<br> CloseHandle(CommHandle); <br> btnOpenCom.Enabled :=True;<br> Connected:=False;<br> StatusBar1.SimpleText := '串口已经关闭';<br>end;<br><br>procedure TForm1.btnSendDataClick(Sender: TObject);<br>var<br> Str:String;<br> i:Integer;<br> writeoverlapped:TOverlapped;<br> ByteToWrite,BytesWritten,AllBytesWritten
WORD;<br> ErrorCode,ErrorFlag
WORD;<br> CommStat:COMSTAT;<br><br>begin<br> if not Connected then<br> begin<br> StatusBar1.SimpleText := '未打开串口';<br> Exit;<br> end;<br><br> if (Memo1.GetTextLen=0) then<br> begin<br> StatusBar1.SimpleText := '缓冲区为空';<br> Exit;<br> end;<br><br> AllBytesWritten:=0;<br> for i:=0 to memo1.Lines.Count-1 do<br> begin<br> Str:=memo1.Lines
;<br> ByteToWrite:=length(Str);<br> if ByteToWrite=0 then continue;<br> try<br> StatusBar1.SimpleText := '正在发送数据';<br> //初始化一步读写结构<br> FillChar(writeoverlapped,Sizeof(writeoverlapped),0);<br> //避免贡献资源冲突<br> writeoverlapped.hEvent:=CreateEvent(nil,True,False,nil);<br> //发送数据<br> if not WriteFile(Commhandle,Str[1],ByteToWrite,BytesWritten,@writeoverlapped) then<br> begin<br> ErrorCode:=GetLastError;<br> if ErrorCode<>0 then<br> begin<br> if ErrorCode=ERROR_IO_PENDING then<br> begin<br> StatusBar1.SimpleText := '端口忙,正在等待...';<br> while not GetOverlappedResult(Commhandle,writeoverlapped,BytesWritten,True) do<br> begin<br> ErrorCode:=GetLastError;<br> if ErrorCode=ERROR_IO_PENDING then<br> continue<br> else begin<br> ClearCommError(Commhandle,ErrorFlag,@CommStat);<br> showmessage('发送数据出错');<br> CloseHandle(WriteOverlapped.hEvent);<br> CloseHandle(Commhandle);<br> btnOpenCom.Enabled :=True;<br> Exit;<br> end;<br> end;<br> AllBytesWritten:=AllBytesWritten+BytesWritten;<br> end<br> else begin<br> ClearCommError(Commhandle,ErrorFlag,@CommStat);<br> showmessage('发送数据出错');<br> CloseHandle(WriteOverlapped.hEvent);<br> Receive :=False;<br> CloseHandle(Commhandle);<br> CloseHandle(PostEvent);<br> btnOpenCom.Enabled :=True;<br> Exit;<br> end;<br> end;<br> end;<br> finally<br> CloseHandle(writeoverlapped.hEvent);<br> end;<br> end;<br> StatusBar1.SimpleText:='已经发送了Byte个数:'+IntToStr(ALLBytesWritten);<br> btnReceiveData.OnClick(btnReceiveData);<br>end;<br><br>procedure TForm1.btnReceiveDataClick(Sender: TObject);<br>var<br> com_thread: Thandle;<br> ThreadIDWORD;<br><br>begin<br> if not connected then<br> begin<br> StatusBar1.SimpleText := '未打开串口';<br> Exit;<br> end;<br><br> ReceiveData :=0;<br> Memo2.Clear;<br> FillChar(ReadOs,SizeOf(ReadOs),0);<br> ReadOs.Offset := 0;<br> ReadOs.OffsetHigh := 0;<br><br> // 建立通信监视线程<br> Com_Thread:=CreateThread(nil,0,@CommWatch,nil,0,ThreadID);<br> if (Com_Thread=0) then<br> MessageBox(Handle,'No CreateThread!',nil,mb_OK);<br> <br> //设置DTR信号线<br> EscapeCommFunction(Commhandle,SETDTR);<br> StatusBar1.SimpleText := '正在接收数据...';<br>end;<br><br>end.