各位老大:
  我在做上位机与下位机用COM2通信的程序 上位机(PC)与下位机(控制单元)采用一问一答式即PC给控制单元发一条命令(程序中命令为SendStr=110300000001869A),当控制单元收到这条命令时 会给PC回发送数据。我在Button2的OnClick事件中建立一个通信监视线程 并给控制单元发送了命令,(控制单元接收数据指示灯指示控制单元收到了PC发的命令,并回发送数据指示灯指示控制单元有向PC发出数据),PC如果收到数据会显示在RichEdit1中,但RichEdit1中什么也不显示。
请哪位高手指点小弟,程序哪里有不妥!
const
  WM_COMMNOTIFY=WM_USER+1; //通讯消息
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    OpenDialog1: TOpenDialog;
    Label1: TLabel;
    BitBtn1: TBitBtn;
    RichEdit1: TRichEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
    procedure WMCOMMNOTIFY(var Message:TMessage);message WM_COMMNOTIFY;//消息处理过程
  public
    { Public declarations }
  end;var
  hNewCommFile,Post_Event:THandle;
  Read_os:TOverlapped;
  Receive:Boolean;
  ReceiveData:Dword;procedure AddToMemo(Str:PChar;Len:DWORD);//接收的数据送入显示区
begin
  Str[Len]:=#0;     //#0为NULL
  Form1.RichEdit1.Text:=Form1.RichEdit1.Text+StrPas(Str);
end;procedure CommWatch(Ptr:Pointer);stdcall; //通讯监视线程
var
  dwEvtMask,dwTranser:DWORD;
  Ok:Boolean;
  Os:TOverlapped;
begin
  Receive:=True;
  FillChar(Os,SizeOf(Os),0);//将OS填充为0
  Os.hEvent:=CreateEvent(nil,True,False,nil);//创建重叠读事件对象
  if Os.hEvent=null then
  begin
    MessageBox(0,'Os.Event Create Error!','Notice',MB_OK);
    Exit;
  end;
  if (not SetCommMask(hNewCommFile,EV_RXCHAR)) then
  begin
    MessageBox(0,'SetCommMask Create Error!','Notice',MB_OK);
    Exit;
  end;
  while(Receive) do
  begin
    dwEvtMask:=0; //等待事件发生
    if not WaitCommEvent(hNewCommFile,dwEvtMask,@Os) then
    begin
      if ERROR_IO_PENDING=GetLastError then      //如果出错状态为ERROR_IO_PENDING
        GetOverlappedResult(hNewCommFile,Os,dwTranser,True)//就用GetOverlappedResult函数来获取状态,第4个参数为True表示一直等到操作完成
    end;
    if ((dwEvtMask and EV_RXCHAR)=EV_RXCHAR)then
    begin
      //等待允许传递WM_COMMNOTIFY通讯消息
      WaitForSingleObject(Post_Event,INFINITE);
      //处理WM_COMMNOTIFY消息时不再发送WM_COMMNOTIFY消息
      ResetEvent(Post_Event);     //置Post_Event对象为无信号状态,类似于DelHighDesignP37底左"不发信号状态"
      //传递WM_COMMNOTIFY通讯消息
      Ok:=PostMessage(Form1.Handle,WM_COMMNOTIFY,hNewCommFile,0);
      if (not Ok)then
      begin
        MessageBox(0,'PostMessage Error!','Notice',MB_OK);
        Exit;
      end;
    end;
  end;
  CloseHandle(Os.hEvent);//关闭重叠事件对象
end;
{ TForm1 }procedure TForm1.WMCOMMNOTIFY(var Message: TMessage); //消息处理函数
var
  CommState:COMSTAT;
  dwNumberOfBytesRead:DWORD;
  ErrorFlag:DWORD;
  InputBuffer:array[0..1024]of Char;
begin
  if not ClearCommError(hNewCommFile,ErrorFlag,@CommState)then
  begin
    MessageBox(0,'ClearCommError!','Notice',MB_OK);
    PurgeComm(hNewCommFile,PURGE_RXABORT or PURGE_RXCLEAR);
    Exit;
  end;
  if (CommState.cbInQue>0)then
  begin
    fillChar(InputBuffer,CommState.cbInQue,#0);
    //接收通讯数据
    if (not ReadFile(hNewCommFile,InputBuffer,CommState.cbInQue,dwNumberOfBytesRead,@read_os))then
    begin
      ErrorFlag:=GetLastError();
      if (ErrorFlag<>0)and(ErrorFlag<>ERROR_IO_PENDING)then
      begin
        MessageBox(0,'ReadFile Error!','Notice',MB_OK);
        Receive:=False;
        CloseHandle(Read_os.hEvent);
        CloseHandle(Post_Event);
        CloseHandle(hNewCommFile);
        Exit;
      end
      else
      begin
        WaitForSingleObject(hNewCommFile,INFINITE);//等待操作完成
        GetOverlappedResult(hNewCommFile,Read_os,dwNumberOfBytesRead,False);
      end;
    end;
    if dwNumberOfBytesRead>0 then              //dwNumberOfBytesRead表示已经读取的字节数,其>0表示已经有读取的数据
    begin
      Read_os.Offset:=Read_os.Offset+dwNumberOfBytesRead;
      ReceiveData:=Read_os.Offset;
      //处理接收的数据
      AddToMemo(InputBuffer,dwNumberOfBytesRead);
    end;
  end;
  //允许发送下一个WM_COMMNOTIFY消息
  SetEvent(Post_Event);
end;procedure TForm1.Button2Click(Sender: TObject); //建立通信监视线程并发送读取数据命令
var
  dcb:TDCB;
  Error:Boolean;
  dwNumberOfBytesWritten,dwNumberOfBytesToWrite,
  ErrorFlag,dwWhereToStartWriting:DWORD;
  
  SendStr:string;
  Write_os:TOverlapped;
  s2:string;
  buf1:array[0..50000] of char;
  i:integer;
  Ok:Boolean;
  com_thread:THandle;
  ThreadID:DWORD;
begin  Form1.Caption:='';
  //打开通讯端口COM2
  hNewCommFile:=CreateFile('COM2',GENERIC_WRITE or GENERIC_READ,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
  if hNewCommFile=INVALID_HANDLE_VALUE then
    MessageBox(0,'Error Opening Com Port!','Notice',MB_OK);
  SetupComm(hNewCommFile,1024,1024);//设置缓冲区大小及主要通讯参数  
  GetCommState(hNewCommFile,dcb);  //用hNewCommFile(COM2)的当前控制设置填充dcb
  dcb.BaudRate:=19200;
  dcb.ByteSize:=8;
  dcb.Parity:=NOPARITY;
  dcb.StopBits:=ONESTOPBIT;
  Error:=SetCommState(hNewCommFile,dcb); //用dcb配置hNewCommFile(COM2)
  if (not Error)then MessageBox(0,'SetCommState Error','Notice',MB_OK);
  SetCommMask(hNewCommFile,EV_TXEMPTY or EV_RXCHAR);//设置监视事件EV_TXEMPTY EV_RXCHAR
  {------------------------------------------------
   ------------建立监视线程-----------------------}
   ReceiveData:=0;
   RichEdit1.Clear;
   FillChar(Read_os,SizeOf(Read_os),0);
  Read_os.Offset:=0;
  Read_os.OffsetHigh:=0;
  //Create Event for Overlapped Read
  Read_os.hEvent:=CreateEvent(nil,True,False,nil); //创建事件对象
  if Read_os.hEvent=null then
  begin
    CloseHandle(hNewCommFile);        //关闭串口COM2
    MessageBox(0,'CreateEvent Error!','Notice',MB_OK);
    Exit;
  end;
  //Create Event for PostMessage
  Post_Event:=CreateEvent(nil,True,True,nil); //创建事件对象
  if Post_Event=null then
  begin
    CloseHandle(hNewCommFile);  //关闭串口COM2
    MessageBox(0,'CreateEvent Error!','Notice',MB_OK);
    Exit;
  end;
  //建立通讯监视线程
  com_thread:=CreateThread(nil,0,@CommWatch,nil,0,ThreadID);
  if (com_thread=0)then
    MessageBox(Handle,'No CreateThread!',nil,MB_OK);
  EscapeCommFunction(hNewCommFile,SETDTR);
  Label1.Font.Color:=clRed;
  Label1.Caption:='正在接收数据...!';  SendStr:='110300000001869A';    //SendStr为发送的命令
  for i:=1 to length(SendStr) do
  begin
    if ((copy(SendStr,i,1)>='0') and (copy(SendStr,i,1)<='9'))or((copy(SendStr,i,1)>='a') and (copy(SendStr,i,1)<='f'))
        or((copy(SendStr,i,1)>='A') and (copy(SendStr,i,1)<='F')) then
    begin
        s2:=s2+copy(SendStr,i,1);
    end;
  end;
  for i:=0 to (length(s2) div 2-1) do
    buf1[i]:=char(strtoint('$'+copy(s2,i*2+1,2)));  dwWhereToStartWriting:=0;
  dwNumberOfBytesWritten:=0;
  dwNumberOfBytesToWrite:=length(s2) div 2; //需要发送的长度
  begin
     try
      Label1.Font.Color:=clRed;
      FillChar(Write_os,SizeOf(Write_os),0);//将Write_os填充为0
      //为重叠写创建事件对象
      Write_os.hEvent:=CreateEvent(nil,True,False,nil);//创建事件对象
      Label1.Caption:='正在发送数据...!';
      repeat
        Label1.Repaint;
        //发送通讯数据
        if not WriteFile(hNewCommFile,buf1,
          dwNumberOfBytesToWrite,dwNumberOfBytesWritten,@write_os)then  
        begin
          ErrorFlag:=GetLastError;   //错误标志
          if ErrorFlag<>0 then
          begin
            if ErrorFlag=Error_IO_PENDING then
            begin
              WaitForSingleObject(Write_os.hEvent,INFINITE);
              GetOverlappedResult(hNewCommFile,Write_os,dwNumberOfBytesWritten,False);
            end
            else
            begin
              MessageBox(0,'WriteFile Error!','Notice',MB_OK);
              Receive:=False;
              CloseHandle(Read_os.hEvent);
              CloseHandle(Post_Event);
              CloseHandle(hNewCommFile);
              Exit;
            end;
          end;
        end;
        Dec(dwNumberOfBytesToWrite,dwNumberOfBytesWritten);
        Inc(dwWhereToStartWriting,dwNumberOfBytesWritten);
        until (dwNumberOfBytesToWrite<=0);//Write the Whole thing!
        Form1.Caption:=IntToStr(dwWhereToStartWriting);
    finally
      
    end;
    CloseHandle(hNewCommFile);//关闭串口
  end;

解决方案 »

  1.   

    看你那么写的那么多.呵呵.做COM口通讯,先做一个小软件,或找个端口软件,你打个命令,然后看一下连接通没有,是否给了返回值.返回值是否正确.
    (验证返回值就用转码,转成你需要的码,一般都是十六进制转ASCII码)噢,要对COM的设置进行确定,如数据位8位,奇偶检验等等.确定通信的参数,再进行通讯的测试.(先写一些基本的函数)然后,再写正试的测试程序或软件.(把函数做成一个文件,直接挂着用.)
      

  2.   

    我的下位机的指示灯显示已经成功收到PC发的命令,并且也给PC回复了数据,而程序就是不能接收到下位机发的数据!请您帮我看看是不是串口的设置哪里有冲突或者是监视事件设置有问题! (hNewCommFile:=CreateFile('COM2',GENERIC_WRITE or GENERIC_READ,0,nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);//打开串口2) 
    (SetCommMask(hNewCommFile,EV_TXEMPTY or EV_RXCHAR);//设置监视事件EV_TXEMPTY EV_RXCHAR ) (通信监视里设置串口事件:if (not SetCommMask(hNewCommFile,EV_RXCHAR)) then )
      

  3.   

    楼主看的懂VB的代码不?看的懂的话这儿有一个API串口通信的例子:
    http://download.csdn.net/source/1339593
      

  4.   

    我用SPCOMM已经实现了,但老板说要用API写的稳定一些 控件不太稳定...所以没办法呀
      

  5.   

    能实现就可以了嘛,串口控件都是开放源码的,跟你自己写API没区别吧,如果那里不爽可以自动修改下!