Function TForm1.SendCommData(s:string):boolean;
var
  i:integer;
  buffChar:array[0..64] of char;
  len:integer;
begin
  result := false;  StrPCopy(buffChar,s);
  len := length(s);  if not (Comm1.WriteCommData(@buffChar[0],1)) then
  begin
    result := false;
    exit;
  end;  for i:=1 to len-1 do
  begin
    Comm1.WriteCommData(@buffChar[i],1);    //bool
  end;
  result := true;end;
procedure TForm1.GetMeTheData(s:string);
begin
   SendCommData('GetMeTheData');//请求串口外部设备传数据给我
end;
procedure TForm1.Comm1ReceiveData(Sender: TObject;
  Buffer: Pointer; BufferLength: Word);
var
  buffChar : array[0..32] of byte;
  sRev,sRes: string;
  i:smallint;
begin
  try
    ZeroMemory(@buffChar[0],33);
  except
  end;
  //SetLength(buffChar,BufferLength);
  CopyMemory(@buffChar[0],Buffer,BufferLength);
  sRev := '';
  sRes := '';
  sRev := Format('%x',[buffChar[0]]);
  if (sRev='7B') then //是需要的数据了
  begin
    //取出需要的数据
    sRes:=需要的数据;
  end;
  if sRes='' then
  begin
    //接收失败
  end
  else
  begin
    //接收成功,显示数据
  end;
end;
流程就是每当我发SendCommData('GetMeTheData')到串口,串口设备就传数据给我,
刚开始的20次左右,是好的,一切正常,之后就接不到数据了,也不知道是没发成功还是没接成功,开始我想是缓冲区满了,于是我就在发送之前,或者是接收之后,清
空缓冲区,如下
PurgeComm( Comm1.handle, PURGE_TXABORT or PURGE_RXABORT or
                           PURGE_TXCLEAR or PURGE_RXCLEAR ) ;
(如果用安全清除:
FlushFileBuffers(Comm1.handle),结果是成功8次左右就死机。)
结果是根本要发的数据SendCommData('GetMeTheData')都没发出去,虽然我是在发送之前清的缓冲区。
Comm1为spcomm控件实例,属性控制是默认的。比如缓冲区大小为:
SetupComm( hNewCommFile, 4096, 4096 );
属性选项如下:
BaudRate 9600
ByteSize _8
CommName COM2
DsrSensitivity False
DtrControl DtrEnable
IgnoreNullChar False
Inx_XonXoffFlow True
Name Comm1
Outx_XtsFlow False
Outx_DsrFlow False
Outx_XonXoffFlow True
Parity None
ParityCheck False
ReadIntervalTimeout 100
ReadTotalTimeoutConstant 0
ReadTotalTimeoutMultiplier 0
ReplaceChar #0
ReplaceWhenParityError False
RtsControl RtsEnable
StopBit _1
Tag 0
TxContinueOnXoff True
WriteTotalTimeoutConstant 0
WriteTotalTimeoutMultiplier 0
XoffChar #19
XoffLimit 500
XonChar #17
XonLimit 500

解决方案 »

  1.   

    >>串口设备就传数据给我,
    >>刚开始的20次左右,是好的,一切正常,之后就接不到数据了,也不知道是没发成功还是
    >>没接成功,开始我想是缓冲区满了,于是我就在发送
    應該不是 "缓冲区满了"的原因, 是什麼數據導致線程挂起了
      

  2.   

    很有可能,我看了下spcomm的原代码,请高手指点改改,要怎么改原代码,还是改我的程序就可以了?spcomm的写线程:
    procedure TWriteThread.Execute;
    var
       msg:   TMsg;
       dwHandleSignaled:      DWORD;
       overlappedWrite:       TOverLapped;
       CompleteOneWriteRequire : Boolean;
    label
         EndWriteThread;
    begin
         // Needed for overlapped I/O.
         FillChar( overlappedWrite, SizeOf(overlappedWrite), 0 );  {0, 0, 0, 0, NULL}     overlappedWrite.hEvent := CreateEvent( nil, True, True, nil );
         if overlappedWrite.hEvent = 0 then
         begin
              PostHangupCall;
              goto EndWriteThread
         end;     CompleteOneWriteRequire := True;     // This is the main loop.  Loop until we break out.
         while True do
         begin
              if not PeekMessage( msg, 0, 0, 0, PM_REMOVE ) then
              begin
                   // If there are no messages pending, wait for a message or
                   // the CloseEvent.               pFSendDataEmpty^ := True;               if CompleteOneWriteRequire then
                   begin
                        if not PostMessage( hComm32Window, PWM_SENDDATAEMPTY, 0, 0 ) then
                        begin
                             PostHangupCall;
                             goto EndWriteThread
                        end
                   end;               CompleteOneWriteRequire := False;               dwHandleSignaled := MsgWaitForMultipleObjects(1, hCloseEvent, False,
                                       INFINITE, QS_ALLINPUT);               case dwHandleSignaled of
                   WAIT_OBJECT_0:     // CloseEvent signaled!
                   begin
                        // Time to exit.
                        goto EndWriteThread
                   end;               WAIT_OBJECT_0 + 1: // New message was received.
                   begin
                        // Get the message that woke us up by looping again.
                        Continue
                   end;               WAIT_FAILED:       // Wait failed.  Shouldn't happen.
                   begin
                        PostHangupCall;
                        goto EndWriteThread
                   end
                   
                   else                // This case should never occur.
                   begin
                        PostHangupCall;
                        goto EndWriteThread
                   end
                   end
              end;          // Make sure the CloseEvent isn't signaled while retrieving messages.
              if WAIT_TIMEOUT <> WaitForSingleObject(hCloseEvent,0) then
                 goto EndWriteThread;          // Process the message.
              // This could happen if a dialog is created on this thread.
              // This doesn't occur in this sample, but might if modified.
              if msg.hwnd <> 0{NULL} then
              begin
                   TranslateMessage(msg);
                   DispatchMessage(msg);
                   Continue
              end;          // Handle the message.
              case msg.message of
              PWM_COMMWRITE:  // New string to write to Comm port.
              begin
                   // Write the string to the comm port.  HandleWriteData
                   // does not return until the whole string has been written,
                   // an error occurs or until the CloseEvent is signaled.
                   if not HandleWriteData( @overlappedWrite,
                                           PChar(msg.lParam), DWORD(msg.wParam) ) then
                   begin
                        // If it failed, either we got a signal to end or there
                        // really was a failure.                    LocalFree( HLOCAL(msg.lParam) );
                        goto EndWriteThread
                   end;               CompleteOneWriteRequire := True;
                   // Data was sent in a LocalAlloc()d buffer.  Must free it.
                   LocalFree( HLOCAL(msg.lParam) )
              end
              end
         end; {main loop}     // Thats the end.  Now clean up.
    EndWriteThread:     PurgeComm(hCommFile, PURGE_TXABORT + PURGE_TXCLEAR);
         pFSendDataEmpty^ := True;
         CloseHandle(overlappedWrite.hEvent)
    end; {TWriteThread.Execute}
      

  3.   

    spcom的读线程:
    procedure TReadThread.Execute;
    var
       szInputBuffer: array[0..INPUTBUFFERSIZE-1] of Char;
       nNumberOfBytesRead:    DWORD;   HandlesToWaitFor:      array[0..2] of THandle;
       dwHandleSignaled:      DWORD;   fdwEvtMask:                    DWORD;   // Needed for overlapped I/O (ReadFile)
       overlappedRead:                TOverlapped;   // Needed for overlapped Comm Event handling.
       overlappedCommEvent:   TOverlapped;
    label
         EndReadThread;
    begin
         FillChar( overlappedRead, Sizeof(overlappedRead), 0 );
         FillChar( overlappedCommEvent, Sizeof(overlappedCommEvent), 0 );     // Lets put an event in the Read overlapped structure.
         overlappedRead.hEvent := CreateEvent( nil, True, True, nil);
         if overlappedRead.hEvent = 0 then
         begin
              PostHangupCall;
              goto EndReadThread
         end;     // And an event for the CommEvent overlapped structure.
         overlappedCommEvent.hEvent := CreateEvent( nil, True, True, nil);
         if overlappedCommEvent.hEvent = 0 then
         begin
              PostHangupCall();
              goto EndReadThread
         end;     // We will be waiting on these objects.
         HandlesToWaitFor[0] := hCloseEvent;
         HandlesToWaitFor[1] := overlappedCommEvent.hEvent;
         HandlesToWaitFor[2] := overlappedRead.hEvent;     // Setup CommEvent handling.     // Set the comm mask so we receive error signals.
         if not SetCommMask(hCommFile, EV_ERR or EV_RLSD or EV_RING ) then
         begin
              PostHangupCall;
              goto EndReadThread
         end;     // Start waiting for CommEvents (Errors)
         if not SetupCommEvent( @overlappedCommEvent,  fdwEvtMask ) then
            goto EndReadThread;     // Start waiting for Read events.
         if not SetupReadEvent( @overlappedRead,
                                szInputBuffer, INPUTBUFFERSIZE,
                                nNumberOfBytesRead ) then
            goto EndReadThread;     // Keep looping until we break out.
         while True do
         begin
              // Wait until some event occurs (data to read; error; stopping).
              dwHandleSignaled := WaitForMultipleObjects(3, @HandlesToWaitFor,
                                  False, INFINITE);          // Which event occured?
              case dwHandleSignaled of
                   WAIT_OBJECT_0:     // Signal to end the thread.
                   begin
                        // Time to exit.
                        goto EndReadThread
                   end;               WAIT_OBJECT_0 + 1: // CommEvent signaled.
                   begin
                        // Handle the CommEvent.
                        if not HandleCommEvent( @overlappedCommEvent, fdwEvtMask, TRUE ) then
                           goto EndReadThread;                    // Start waiting for the next CommEvent.
                        if not SetupCommEvent( @overlappedCommEvent, fdwEvtMask ) then
                           goto EndReadThread
                        {break;??}
                   end;               WAIT_OBJECT_0 + 2: // Read Event signaled.
                   begin
                        // Get the new data!
                        if not HandleReadEvent( @overlappedRead,
                                                szInputBuffer,
                                                INPUTBUFFERSIZE,
                                                nNumberOfBytesRead ) then
                           goto EndReadThread;                    // Wait for more new data.
                        if not SetupReadEvent( @overlappedRead,
                                               szInputBuffer, INPUTBUFFERSIZE,
                                               nNumberOfBytesRead ) then
                           goto EndReadThread
                        {break;}
                   end;               WAIT_FAILED:       // Wait failed.  Shouldn't happen.
                   begin
                        PostHangupCall;
                        goto EndReadThread
                   end
                   else    // This case should never occur.
                   begin
                        PostHangupCall;
                        goto EndReadThread
                   end
              end {case dwHandleSignaled}
         end; {while True}        // Time to clean up Read Thread.
     EndReadThread:     PurgeComm( hCommFile, PURGE_RXABORT + PURGE_RXCLEAR );
         CloseHandle( overlappedRead.hEvent );
         CloseHandle( overlappedCommEvent.hEvent )
    end; {TReadThread.Execute}
      

  4.   

    如果我把goto改为break的话,我怕我改得不正确,导致不可恢复的错误呢。
      

  5.   

    在线程最外面层加:
    while not Terminated do
    begin
    end;
    可以吗??
      

  6.   

    spcomm太难用了,哪个串口控件最好呀???推荐推荐。
      

  7.   

    用标准的MSCOMM就可以 ,还有CPort也可以
      

  8.   

    spcomm最好用。
    也许是下位机工作不正常了吧。你既然用Spcomm,为何还要显式地去用那些API呢?
    你还要注意发送的间隔,要考虑两方(下位机、上位机)都能处理过来。
    还有你这是什么代码呀?  for i:=1 to len-1 do
      begin
        Comm1.WriteCommData(@buffChar[i],1);    //bool
      end;
    不能用一个语句发送出去吗?自找麻烦。
      

  9.   

    大概看了一下,要注意CopyMemory的数据长度,一旦数据长度变大,就会越界出错
    可以用串口调试助手之类的作测试,还有你发送语句为什么不一起发?
      

  10.   

    SetLength(buffChar,BufferLength);
    move(Buffer^,buffChar,BufferLength);
    可以么??
    其实收到的数据是21 Byte,33个长度因该够了吗?
    还有,我看spcomm的收发线程都有goto语句,我看它如果出错,goto之后,线程就完了,要怎么样防止它完蛋呢?
      

  11.   

    SetLength(buffChar,BufferLength);//像是会出错也。
    move(Buffer^,buffChar,BufferLength);
      

  12.   

    建议先用专业的串口调试软件查看接收的数据,并使用它来模拟,看看错误在哪里http://www.skycn.com/soft/5480.html
      

  13.   

    To:  bphantom(无花无酒) 仔细的看了一下您的程序:写的太复杂了。可以近可能的简单点。如果要实现:“每当我发SendCommData('GetMeTheData')到串口,串口设备就传数据给我,” 可以如此:
    过程1: 点击按键--关闭端口--设置端口参数--打开端口--发送'GetMeTheData’
    过程2: Comm1ReceiveData--如果收到'7B'--取出数据注意事项:
    1  Inx_XonXoffFlow Outx_XonXoffFlow 可设为 false
    2. 发送数据一句话就够了  Comm1.WriteCommData('GetMeTheData')
    3. 接收数据  Move(Buffer^,arrByte,25);---"其实收到的数据是21 Byte',读前面一些字节就够了,防止收到的数据长度超过[0..32] 
    4. 打开 onReceiveError 看看出错的时候错在那里
    5. 如果前面接收的数据没有问题,可能该线程中断
      

  14.   

    按键是不能点的,都是自动感应触发的。
    我防止了长度在10~25之间了。
    Inx_XonXoffFlow Outx_XonXoffFlow 可设为 false 流控制到底是做什么用的?可以告诉我么?
    好,我打开onReceiveError看看。
    谢谢各位的热心帮助!
    如果线程中断(因该就是了),该怎么防止呢?我在spcomm原代码中加了while not terminated do 都不行。
      

  15.   

    to MichealLee()
    Inx_XonXoffFlow Outx_XonXoffFlow 可设为 false
    就好象70次都不出错了也,现在能坚持到300次了。不知道能不能坚持1年以上?
    当onReceiveError时,我就显示错误码,然后StopComm,再StartComm,可以吗??
      

  16.   

    兄弟,帮不上你的忙了。
    现在贴出源码(Delphi7.0)---部分,希望对你有所帮助。
    (前些日期写的,运行的很顺利。用于从TMS320C54X DSP结构上获得数据)1. 控件Comm1
      object Comm1: TComm
        CommName = 'COM1'
        BaudRate = 9600
        ParityCheck = False
        Outx_CtsFlow = False
        Outx_DsrFlow = False
        DtrControl = DtrEnable
        DsrSensitivity = False
        TxContinueOnXoff = False
        Outx_XonXoffFlow = False
        Inx_XonXoffFlow = False
        ReplaceWhenParityError = False
        IgnoreNullChar = False
        RtsControl = RtsEnable
        XonLimit = 500
        XoffLimit = 500
        ByteSize = _8
        Parity = None
        StopBits = _1
        XonChar = #17
        XoffChar = #19
        ReplacedChar = #0
        ReadIntervalTimeout = 1
        ReadTotalTimeoutMultiplier = 0
        ReadTotalTimeoutConstant = 0
        WriteTotalTimeoutMultiplier = 0
        WriteTotalTimeoutConstant = 0
        OnReceiveData = Comm1ReceiveData
        Left = 48
        Top = 272
      end
    2. 打开端口
    begin
         comm1.CommName:=trim(ComboBox1.Text);  //从ComboBox1获得端口名称
         ComboBox1.Enabled:=false;
         comm1.StartComm;
    end;3.接收数据
    procedure TForm2.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
      BufferLength: Word);
    var    ReceivedData: array [1..1200] of byte;
           i:integer;
    begin
        //初始化:赋值0
        for i:=1 to 1200 do
        begin
             ReceivedData[i]:=0;
        end;
        move(buffer^,pchar(@ReceivedData)^,1100);  //只取部分(有效部分)
        
        //发回命令,告知数据已经收到。
        comm1.WriteCommData('0'#13,1);
    end;
      

  17.   

    to  MichealLee() 
    Inx_XonXoffFlow Outx_XonXoffFlow 设为 false
    后,现在运行3000次了,还没问题。可能以后也没问题了。谢谢。
      

  18.   

    to  MichealLee() 你就是救星,等我忙完这台事情,我请你来云南旅游。你在那?我先预算旅游费用。