首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过串口(COM)实现无重叠通信的正确方法

通过串口(COM)实现无重叠通信的正确方法
EN

Stack Overflow用户
提问于 2013-10-09 08:00:01
回答 1查看 1.5K关注 0票数 0

我正在使用德尔福XE2,我试图通过串口与一些设备通信。沟通应该是直接的,但我有一些问题。设备通信协议如下:I(主)发送帧,以":“开头,以CRLF结束。设备(从)以相同的格式发送响应(以":“开头,以CRLF结尾)。

我正在使用WinAPI和不重叠的IO。我遇到的问题是,我经常从设备接收#0字符作为响应。我确信问题就在我这一边,因为我可以使用设备提供者应用程序,而且我可以看到通信进行得很好。

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

代码语言:javascript
复制
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;

我是这样写的:

代码语言:javascript
复制
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;

最后,我是这样读到的:

代码语言:javascript
复制
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调用,因为我是非常新的串行通信。

谢谢你帮忙!

EN

回答 1

Stack Overflow用户

发布于 2013-10-09 10:43:35

也许你忘记了"@":ReadFile(FFileHandle,@ S1,Length(S),BytesRead,0)

我这样做是为了读COM中的字符串:

代码语言:javascript
复制
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;

字符串字节/char的FEOSChar结束。要从string获得TBytes,可以使用SysUtils.StringOf()函数

upd:

代码语言:javascript
复制
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;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19266237

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档