2013-10-09 37 views
0

我正在使用Delphi XE2,并尝试通过串口与某些设备进行通信。沟通应该直截了当,但我有一些问题。设备通信协议如下: I(主)发送以“:”开始并以CRLF结束的帧。 设备(从站)以相同的格式发送响应(以“:”开头并以CRLF结尾)。通过串口(COM)进行非重叠通信的正确方法

我正在使用WinAPI和非重叠IO。我遇到的问题是,我经常收到#0字符作为设备的响应。我相信问题出在我身上,因为我可以使用设备提供商应用程序,并且我可以看到沟通顺利。

下面是如何设置我的COM端口:

Result := False; 
FFileHandle := CreateFile('COM3', GENERIC_READ OR GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); 
if FFileHandle = INVALID_HANDLE_VALUE then 
    Exit; 

if not GetCommState(FFileHandle, DCB) then 
    Exit; 
DCB.BaudRate := ASettings.BaudRate; 
DCB.Flags := 1 OR // BINARY 
      (DTR_CONTROL_ENABLE shl 4) OR 
      (RTS_CONTROL_ENABLE shl 12); 

DCB.XonLim := 100;   // transmit XON threshold 
DCB.XoffLim := 100;   // transmit XOFF threshold 
DCB.ByteSize := 8;   // number of bits/byte, 4-8 
DCB.Parity := 0;    // 0-4=no,odd,even,mark,space 
DCB.StopBits := ONESTOPBIT; // 0,1,2 = 1, 1.5, 2 
DCB.XonChar := #1;   // Tx and Rx XON character 
DCB.XoffChar := #2;   // Tx and Rx XOFF character 
DCB.ErrorChar := #$FF;  // error replacement character 
DCB.EofChar := #$0A;   // end of input character 
DCB.EvtChar := #$0A;   // received event character 
if not SetCommState(FFileHandle, DCB) then 
    Exit; 
if not SetCommMask(FFileHandle, EV_RXCHAR OR EV_TXEMPTY OR EV_RXFLAG) then 
    Exit; 
Timeouts.ReadIntervalTimeout := 1200; 
Timeouts.ReadTotalTimeoutMultiplier := 1; 
Timeouts.ReadTotalTimeoutConstant := 1200; 
Timeouts.WriteTotalTimeoutMultiplier := 0; 
Timeouts.WriteTotalTimeoutConstant := 0; 
if not SetCommTimeouts(FFileHandle, Timeouts) then 
    Exit; 
if not PurgeComm(FFileHandle, PURGE_TXABORT OR PURGE_RXABORT OR PURGE_TXCLEAR OR PURGE_RXCLEAR) then 
    Exit; 
if not ClearCommError(FFileHandle, Errors, @ComStat) then 
    Exit; 
if not SetupComm(FFileHandle, 1024, 1024) then 
    Exit; 
Result := True; 

这里是如何我不写:

function TCOMPortWrapper.Write(const AFrame: AnsiString): TComPortWriteRes; 
var 
    Written: Cardinal; 
    Err: Cardinal; 
    Stat: TComStat; 
    Mask: Cardinal; 
begin 
    Result := CPW_ERROR; 
    ClearCommError(FFileHandle, Err, @Stat); 
    if not IsOpened then 
    Exit; 
    if not WriteFile(FFileHandle, AFrame[1], Length(AFrame), Written, nil) then 
    Exit; 
    Mask := EV_TXEMPTY; 
    if not WaitCommEvent(FFileHandle, Mask, nil) then 
    Exit; 
    ClearCommError(FFileHandle, Err, @Stat); 
    Result := CPW_OK; 
end; 

最后这里是我如何读取:

function TCOMPortWrapper.Read(out Frame: AnsiString): TComPortReadRes; 
var 
    S: AnsiString; 
    BytesRead: Cardinal; 
    Mask: Cardinal; 
begin 
    Result := CPR_ERROR; 
    if not IsOpened then 
    Exit; 
    SetLength(S, 4096); 
    Mask := EV_RXFLAG; 
    if not WaitCommEvent(FFileHandle, Mask, nil) then 
    Exit; 
    if not ReadFile(FFileHandle, S[1], Length(S), BytesRead, nil) then 
    Exit; 
    SetLength(S, BytesRead); 
    Frame := S; 
    Result := CPR_OK; 
end; 

正如我上面提到的,在读取而不是获取实际框架,我得到#0字符串。我想,我的错误可能是WaitCommEvent API调用,因为我对串行通信非常陌生。

感谢您的帮助!

+0

虽然这不会回答你的问题,有一些很好的水果盘组件在那里。过去我多次使用TPAPRO。这是当时的商业组件,但现在它已经作为开源发布:http://tpapro.sourceforge.net/ – whosrdaddy

回答

0

也许你忘了 “@”:ReadFile的(FFileHandle,@ S [1],长度(S),BytesRead,无)

我做这样从COM读字符串:

constructor TSerialPort.Create(const APortName: String); 
begin 
    inherited Create; 

    FPortHandle := INVALID_HANDLE_VALUE; 

    FPortName := APortName; 

    FDCB.DCBlength := SizeOf(DCB); 
    FDCB.BaudRate := CBR_19200; 
    FDCB.Flags := MakeCommFlags(True, False, True, True, DTR_CONTROL_DISABLE, 
    False, False, False, False, False, False, RTS_CONTROL_DISABLE, False); 
    FDCB.wReserved := 0; 
    FDCB.XonLim := 2048; 
    FDCB.XoffLim := 512; 
    FDCB.ByteSize := 8; 
    FDCB.Parity := NOPARITY; 
    FDCB.StopBits := ONESTOPBIT; 
    FDCB.XonChar := #0; 
    FDCB.XoffChar := #0; 
    FDCB.ErrorChar := #0; 
    FDCB.EofChar := #255; 
    FDCB.EvtChar := #0; 
    FDCB.wReserved1 := 0; 

    FCTO.ReadIntervalTimeout := 0; 
    FCTO.ReadTotalTimeoutMultiplier := 20; 
    FCTO.ReadTotalTimeoutConstant := 500; 
    FCTO.WriteTotalTimeoutMultiplier := 10; 
    FCTO.WriteTotalTimeoutConstant := 200; 

    FEOSChar := #13; 
end; 

function TSerialPort.Open: Boolean; 
begin 
    Result := False; 
    if FPortHandle <> INVALID_HANDLE_VALUE then 
    Close; 

    FPortHandle := CreateFile(PChar('\\.\'+FPortName), GENERIC_READ or GENERIC_WRITE, 0, 
    nil, OPEN_EXISTING, 0, 0); 

    if FPortHandle <> INVALID_HANDLE_VALUE then 
    begin 
    // setup device buffers 
    SetupComm(FPortHandle, 2048, 2048); 

    Flush; // purge any information in the buffer 

    Result := True; 
    end; 
end; 


function TSerialPort.ReadString(var S: SysUtils.TBytes): Boolean; 
const 
    MAX_BUF = 255; 
var 
    B: Byte; 
    iCounter: Integer; 
begin 
    Result := True; 
    B := 0; 

    SetLength(S, MAX_BUF); 
    ZeroMemory(@S[0], Length(S)); 
    iCounter := 0; 

    while (B <> Ord(FEOSChar)) and Result and (iCounter < MAX_BUF) do 
    begin 
    Result := Read(B, 1); 

    if (B <> Ord(FEOSChar)) and Result then 
    begin 
     S[iCounter] := B; 
     Inc(iCounter); 
    end; 
    end; 

    if Result then 
    begin // delete leading zeros 
    while (Length(S) > 0) and (S[0] = 0) do 
    begin 
     for iCounter := 0 to Length(S)-2 do 
     S[iCounter] := S[iCounter+1]; 
     SetLength(S,Length(S)-1); 
    end; 
    end 
    else 
    SetLength(S, 0); 
end; 

function TSerialPort.Read(var inbuf; inlen: DWORD): Boolean; 
var 
    dwBytesRead: DWORD; 
begin 
    Result := False; 
    if FPortHandle = INVALID_HANDLE_VALUE then 
    Exit; 

    dwBytesRead := 0; 
    Result := ReadFile(FPortHandle, inbuf, inlen, dwBytesRead, nil); 
end; 

FEOSChar字符串的结尾字节/字符。为了得到stringTBytes可以使用SysUtils.StringOf()功能

UPD:

function MakeCommFlags(fBinary, fParity, fOutxCtsFlow, fOutxDsrFlow: Boolean; 
    fDtrControl: Byte; fDsrSensitivity, fTXContinueOnXoff, fOutX, fInX, 
    fErrorChar, fNull: Boolean; fRtsControl: Byte; 
    fAbortOnError: Boolean): DWORD; 
begin 
    Result := 0; 

    fDtrControl := fDtrControl and $03; 
    fRtsControl := fRtsControl and $03; 

    Result := Result or (Byte(fBinary) shl 0); 
    Result := Result or (Byte(fParity) shl 1); 
    Result := Result or (Byte(fOutxCtsFlow) shl 2); 
    Result := Result or (Byte(fOutxDsrFlow) shl 3); 
    Result := Result or (Byte(fDtrControl) shl 4); 
    Result := Result or (Byte(fDsrSensitivity) shl 6); 
    Result := Result or (Byte(fTXContinueOnXoff) shl 7); 
    Result := Result or (Byte(fOutX) shl 8); 
    Result := Result or (Byte(fInX) shl 9); 
    Result := Result or (Byte(fErrorChar) shl 10); 
    Result := Result or (Byte(fNull) shl 11); 
    Result := Result or (Byte(fRtsControl) shl 12); 
    Result := Result or (Byte(fAbortOnError) shl 14); 
end; 
相关问题