我正在使用Delphi XE2,我尝试通过串口与某些设备通信。沟通应该是直截了当的,但我有一些问题。设备通信协议如下: 我(主)发送以“:”开头并以CRLF结尾的帧。 设备(从设备)以相同的格式发送响应(以“:”开头,以CRLF结尾)。
我正在使用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 :(得分: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
字符串字节/字符的结尾。要从string
获取TBytes
,您可以使用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;