请教大哥们,在串口通信中的整个详细过程。请尽量详细点。什么缓冲区啊之类的

解决方案 »

  1.   

    unit U_APISerialPort;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExtCtrls;
    const
      Wm_CommNotify = WM_User +12;
    type
      Tfrm_SerialPort = class(TForm)
        pnl1: TPanel;
        lbl_SerialPort: TLabel;
        cbb_SerialPort: TComboBox;
        btn_OpenSerialPort: TButton;
        btn_CloseSerialPort: TButton;
        pnl2: TPanel;
        lbl_RevData: TLabel;
        mem_RevData: TMemo;
        pnl3: TPanel;
        lbl_SendData: TLabel;
        mem_SendData: TMemo;
        pnl4: TPanel;
        btn_Send: TButton;
        btn_Close: TButton;
        btn_SaveToFile: TButton;
        procedure FormShow(Sender: TObject);
        procedure btn_OpenSerialPortClick(Sender: TObject);
        procedure btn_CloseSerialPortClick(Sender: TObject);
        procedure btn_CloseClick(Sender: TObject);
        procedure btn_SendClick(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure btn_SaveToFileClick(Sender: TObject);
      private
        procedure CommInitialize;
        procedure MsgComm(var Msg:TMessage);Message Wm_CommNotify;
        function WriteStr(const Str:string):Boolean;
        { Private declarations }
      public
        { Public declarations }
      end;
      TComm=class(TThread)
      protected
        procedure Execute;override;
      end;var
      frm_SerialPort: Tfrm_SerialPort;
      g_Hcom,g_Post_Event:THandle;
      g_LpolW,g_LpolR:POverlapped;
      g_RXComm:TComm;
      g_bFlag :Boolean;implementation{$R *.dfm}
    procedure TComm.Execute;
    var
      l_dwEvtmask,l_dwOvres,l_dwbb:DWORD;
      l_bRXFinish:BOOL;
    begin
      while True do
      begin
        l_dwEvtmask := 0;
        l_bRXFinish := WaitCommEvent(g_Hcom,l_dwEvtmask,g_LpolR);//等待串口事件EV_RXCHAR
        if not l_bRXFinish then
          if GetLastError()= ERROR_IO_PENDING then//正在接受数据;
          begin
            l_dwbb:=WaitForSingleObject(g_LpolR^.hEvent,500);//等待500MS
            case l_dwbb of
              WAIT_OBJECT_0: l_bRXFinish:=GetOverlappedResult(g_Hcom,g_LpolR^,l_dwOvres,False);
              WAIT_TIMEOUT: l_bRXFinish:= False//定是益出
            else
              l_bRXFinish := False;
            end;
          end
        else
          l_bRXFinish:=False;
         if l_bRXFinish then
         begin
           ResetEvent(g_Post_Event); //同步事件复位
           PostMessage(frm_SerialPort.Handle,Wm_CommNotify,0,0);
         end;
      end;
    end;procedure Tfrm_SerialPort.FormShow(Sender: TObject);
    begin
      try
        btn_CloseSerialPort.Enabled := False;
        cbb_SerialPort.Clear;
        mem_RevData.Clear;
        mem_SendData.Clear;
        cbb_SerialPort.AddItem('',nil);
        cbb_SerialPort.AddItem('COM1',nil);
        cbb_SerialPort.AddItem('COM2',nil);
        cbb_SerialPort.AddItem('COM3',nil);
        cbb_SerialPort.AddItem('COM4',nil);
      except on e:Exception do
        ShowMessage(e.Message);
      end;
    end;procedure Tfrm_SerialPort.btn_OpenSerialPortClick(Sender: TObject);
    begin
      if cbb_SerialPort.Text ='' then
      begin
        MessageDlg('请选择COM口',mtWarning,[mbOK],0);
      end
      else
      begin
        btn_CloseSerialPort.Enabled := True;
        try
          CommInitialize;
        except on e:Exception do
            ShowMessage(e.Message);
        end;
      end;
    end;procedure Tfrm_SerialPort.btn_CloseSerialPortClick(Sender: TObject);
    begin
      btn_CloseSerialPort.Enabled := False;
    end;procedure Tfrm_SerialPort.btn_CloseClick(Sender: TObject);
    begin
      Self.Close;
    end;procedure Tfrm_SerialPort.CommInitialize;
    var
      l_Lpdcb:TDCB;
    begin
      g_Hcom:= CreateFile(PAnsiChar(cbb_SerialPort.Text),GENERIC_READ or GENERIC_WRITE,0,nil,
             OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
      g_bFlag := True;
      if g_Hcom <> invalid_handle_value then
      begin
        SetupComm(g_Hcom,4096,4096);
        GetCommState(g_Hcom,l_Lpdcb);
        l_Lpdcb.BaudRate := 9600;
        l_Lpdcb.StopBits :=0;
        l_Lpdcb.ByteSize :=8;
        l_Lpdcb.Parity :=0;
        SetCommState(g_Hcom,l_Lpdcb);
        SetCommMask(g_Hcom,EV_RXCHAR);
      end
      else
        ShowMessage('无法打开串口');
    end;
    function Tfrm_SerialPort.WriteStr(const Str: string): Boolean;
    var
      l_DwCharsWritten,l_DwRes:DWORD;
      l_S_DATA:string;
      l_BRes:Boolean;
    begin
      l_BRes :=False;
      l_S_DATA:=Str;
      if g_Hcom<>invalid_handle_value then
      begin
        l_DwCharsWritten :=0;
        l_BRes :=WriteFile(g_Hcom,PChar(l_S_DATA)^,Length(l_S_DATA),l_DwCharsWritten,g_LpolW);
        if not l_BRes then
        begin
          if GetLastError()=ERROR_IO_PENDING then
          begin
            l_DwRes :=WaitForSingleObject(g_LpolW^.hEvent,INFINITE);
            if l_DwRes=WAIT_OBJECT_0 then
              l_BRes :=GetOverlappedResult(g_Hcom,g_LpolW^,l_DwCharsWritten,False)
            else
              l_BRes:=True;
          end;
        end;
      end
      else
      Result := l_BRes;
    end;procedure Tfrm_SerialPort.MsgComm(var Msg: TMessage);
    var
      l_bclear:Boolean;
      l_coms :TComStat;
      l_dwcbNum,l_dwCbread,l_dwlpErrors:DWORD;
      l_s:string;
    begin
      l_bclear :=ClearCommError(g_Hcom,l_dwlpErrors,@l_coms);
      if l_bclear then
      begin
        l_dwcbNum :=l_coms.cbInQue;//获取接受缓冲区待接收字节数
        SetLength(l_s,l_dwcbNum+1);//分配内存
        ReadFile(g_Hcom,PChar(l_s)^,l_dwcbNum,l_dwCbread,g_LpolR);//读串口
        SetLength(l_s,l_dwCbread);//分配
        SetEvent(g_Post_Event);//同步事件置位
        mem_RevData.Lines.Add(l_s);
      end;  
    end;procedure Tfrm_SerialPort.btn_SendClick(Sender: TObject);
    var
      l_S_DATA:string;
    begin
      l_S_DATA :=mem_SendData.Text;
      if  WriteStr(l_S_DATA) then
         ShowMessage('无法发送数据')
      else
         ShowMessage('发送成功');
    end;procedure Tfrm_SerialPort.FormDestroy(Sender: TObject);
    begin
      CloseHandle(g_LpolW^.hEvent);
      CloseHandle(g_LpolR^.hEvent);
      Dispose(g_LpolR);
      Dispose(g_LpolW);
      g_LpolW :=nil;
      g_LpolR :=nil;
      g_RXComm.Terminate;
      SetEvent(g_Post_Event);
      CloseHandle(g_Post_Event);
      CloseHandle(g_Hcom);
    end;procedure Tfrm_SerialPort.FormCreate(Sender: TObject);
    begin
    //  CommInitialize;
      New(g_LpolW);
      New(g_LpolR);
      g_LpolW^.Internal :=0;
      g_LpolW^.InternalHigh :=0;
      g_LpolW^.Offset :=0;
      g_LpolW^.OffsetHigh :=0;
      g_LpolW^.hEvent :=CreateEvent(nil,True,False,nil);
      g_LpolR^.Internal :=0;
      g_LpolR^.InternalHigh :=0;
      g_LpolR^.Offset :=0;
      g_LpolR^.OffsetHigh :=0;
      g_LpolR^.hEvent :=CreateEvent(nil,True,False,nil);
      PurgeComm(g_Hcom,PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR);
      g_Post_Event:=CreateEvent(nil,True,True,nil);
      g_RXComm :=TComm.Create(False);
    end;procedure Tfrm_SerialPort.btn_SaveToFileClick(Sender: TObject);
    begin
      try
        if mem_RevData.Text =''then
          ShowMessage('接收数据不能为空!')
        else
          mem_RevData.Lines.SaveToFile('d:\receive.tex');
      except  end;  
    end;end.
      

  2.   

    下载spcomm组件,自己看源代码
      

  3.   

    1楼的,是网上流行的一个经典写法。串口实际上也有很多写法,不过,实际上也就是几个API,弄懂机制就会变得简单。
    http://www.moon-soft.com/program/bbs/readelite515510.htm