delphi serial-port delphi-7

delphi - ¿Cómo aumentar el número de datos en serie asignados a la variable?



serial-port delphi-7 (3)

Deberías hacer tu propio buffering. Eso le da más flexibilidad en cuanto a lo que delimita un mensaje. Por ejemplo, si delimita los mensajes con un retorno de carro (# 13), puede hacer:

var Buf: string; procedure DoSomething(const Str: String); begin Memo.Text := Memo.Text + Str; end; procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer); var I: Integer; begin ComPort.ReadStr(CPort.Str, Count); Buf := Buf + CPort.Str; for i := 1 to Length(Buf) do if Buf[i] = #13 then begin DoSomething(Copy(Buf, 1, i)); Delete(Buf, 1, i+1); Break; end; end;

He descargado e instalado la biblioteca de conducta. Tengo un simulador que envía datos a través de la serie RS232 a un programa Selphi. Este es el siguiente fragmento de código.

procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer); begin ComPort.ReadStr(CPort.Str, Count); Memo.Text := Memo.Text + CPort.Str; end;

En cuanto a la parte de la biblioteca CPort, agregué:

var Str: String; here is the problem.

El ejemplo de datos que está llegando es más o menos como

$HEHDT,288.45,T*1D $HEHDT,288.46,T*18 $HEHDT,288.47,T*1A

y así. Cada línea se envía por segundo. Entonces, con el código anterior, la nota mostrará todos estos datos como tal.

Sin embargo, si cambio el código a:

procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer); begin ComPort.ReadStr(CPort.Str, Count); Memo.Text := Memo.Text + CPort.Str + ''haha''; end;

Esto es lo que aparece en la nota:

$HEHDT,2haha88.45,T*haha1Dhaha $HEHDT,2haha88.46,T*haha18haha $HEHDT,2haha88.47,T*haha1Ahaha

El "haha" aparece después de 8 caracteres ASCII. Entonces, ¿eso significa que en la biblioteca CPort.pas, en la parte asíncrona / síncrona, solo se asignan 8 caracteres ASCII máximos a la variable Str?

¿Cómo hago para cambiar los códigos de modo que toda la cadena de datos, independientemente de su tamaño, se asigne a la variable Str en lugar de solo 8 bytes?

ACTUALIZACIÓN ** Me di cuenta de que hay esta parte de la biblioteca CPort que contiene el siguiente código. ¿Alguien puede aclararme sobre cómo editar el código? o si es el bloque correcto que he obtenido. ¡Gracias!

// split buffer in packets procedure TComDataPacket.HandleBuffer; procedure DiscardPacketToPos(Pos: Integer); var Str: string; begin FInPacket := True; if Pos > 1 then begin Str := Copy(Buffer, 1, Pos - 1); // some discarded data Buffer := Copy(Buffer, Pos, Length(Buffer) - Pos + 1); DoDiscard(Str); end; end; procedure FormPacket(CutSize: Integer); var Str: string; begin Str := Copy(Buffer, 1, CutSize); Buffer := Copy(Buffer, CutSize + 1, Length(Buffer) - CutSize); CheckIncludeStrings(Str); DoPacket(Str); end; procedure StartPacket; var Found: Integer; begin // check for custom start condition Found := -1; DoCustomStart(Buffer, Found); if Found > 0 then DiscardPacketToPos(Found); if Found = -1 then begin if Length(FStartString) > 0 then // start string valid begin Found := Pos(Upper(FStartString), Upper(Buffer)); if Found > 0 then DiscardPacketToPos(Found); end else FInPacket := True; end; end; procedure EndPacket; var Found, CutSize, Len: Integer; begin // check for custom stop condition Found := -1; DoCustomStop(Buffer, Found); if Found > 0 then begin // custom stop condition detected CutSize := Found; FInPacket := False; end else if Found = -1 then begin Len := Length(Buffer); if (FSize > 0) and (Len >= FSize) then begin // size stop condition detected FInPacket := False; CutSize := FSize; end else begin Len := Length(FStartString); Found := Pos(Upper(FStopString), Upper(Copy(Buffer, Len + 1, Length(Buffer) - Len))); if Found > 0 then begin // stop string stop condition detected CutSize := Found + Length(FStopString) + Len - 1; FInPacket := False; end; end; end; if not FInPacket then FormPacket(CutSize); // create packet end;


Si está utilizando la biblioteca ComPort de Dejan Crnila, debería echarle un vistazo al componente TComDataPacket , especialmente sus eventos OnPacket y OnCustomStop .

Actualización: Aquí hay un ejemplo de código. Suponiendo que la cadena de inicio es siempre la misma y la cadena final comienza con '', T *'' seguido de dos caracteres (quizás un código CRC). Si esa suposición es incorrecta, la lógica de parada debe ajustarse.

procedure TForm136.ComDataPacketCustomStop(Sender: TObject; const Str: string; var Pos: Integer); begin Pos := System.Pos('',T*'', Str); if (Pos > 0) then begin Inc(Pos, 4); if Pos <= Length(Str) then Exit; end; Pos := -1; end; procedure TForm136.FormCreate(Sender: TObject); begin ComDataPacket.ComPort := ComPort; ComDataPacket.StartString := ''$HEHDT,''; ComDataPacket.OnCustomStop := ComDataPacketCustomStop; end;


Una solución minimalista con verificación completa de errores sería:

Actualización:

(Dado que la cadena recibida termina con una combinación CRLF y la longitud del paquete no es constante. Este es un paquete NMEA 0183)

var finalBuf: AnsiString; // Example packet: $HEHDT,10.17,T*28 + CRLF // This is a NMEA 0183 protocol (Marine and GPS standard) // Subset for reading the heading. // HDT Heading – True // 1 2 3 // | | | //$--HDT,x.x,T*hh //1) Heading Degrees, true //2) T = True //3) Checksum // HE stands for: Heading – North Seeking Gyro {- Checking packet and checksum, calculating heading } Function ParseAndCheckNMEA_HDT(const parseS: AnsiString; var heading: Double): Integer; // Example packet: $HEHDT,10.17,T*28 + CRLF var i, p, err: Integer; xorSum: Byte; xorStr: AnsiString; headingStr: AnsiString; begin Result := 0; // Assume ok if (Pos(''$HEHDT'', parseS) = 1) then // Start header ok ? begin p := Pos(''*'', parseS); if (p <> 0) and (Length(parseS) >= p + 2) then // Assumes a checksum in packet begin xorSum := Ord(parseS[2]); for i := 3 to p - 1 do // Calculate checksum xorSum := xorSum xor Ord(parseS[i]); xorStr := IntToHex(xorSum, 2); if (UpperCase(xorStr) = Copy(parseS, p + 1, 2)) then // Checksum ok ? begin // Validate heading headingStr := Copy(parseS, 8, p - 10); Val(headingStr, heading, err); if (err <> 0) then Result := 4; // Not a valid float end else Result := 3; // Wrong checksum end else Result := 2; // No checksum end else Result := 1; // Wrong header end; procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer); var i,err: Integer; strBuf: AnsiString; heading: Double; begin ComPort.ReadStr(CPort.Str, Count); strBuf := CPort.str; for i := 1 to Length(strBuf) do case strBuf[i] of ''$'' : finalBuf := ''$''; // Start of package #10 : begin if (finalBuf <> '''') and (finalBuf[1] = ''$'') then // Simple validate check begin SetLength( finalBuf, Length(finalBuf) - 1); // Strips CR err := ParseAndCheckNMEA_HDT(finalBuf, heading); if (err = 0) then Memo.Lines.Add(finalBuf); // Add validated string //else // Memo.Lines.Add(''Error:'' + IntToStr(err)); end; finalBuf := ''''; end; else finalBuf := finalBuf + strBuf[i]; end; end;

Conociendo el carácter de inicio y el final del paquete, esto debería ser bastante seguro de usar. Los caracteres # 13 y # 10 (CR LF) que marcan el final del paquete, se eliminan y el paquete se comprueba para una suma de comprobación válida y se calcula el valor del encabezado resultante. La cadena validada se agrega a la nota.

Actualización 2

Para responder la pregunta directa, ¿por qué su método de recepción puede agregar su cadena ''jaja'' en el medio de la cadena de datos?

La rutina de comportamiento proporciona datos, uno o más caracteres, a su propio ritmo. No puede controlar cuándo obtendrá los datos o cuántos caracteres habrá. Usando el esquema en mi respuesta, los datos se almacenan en un búfer hasta que se entrega un paquete completo. Con el soporte de paquete de TComPort es posible hacer lo mismo.

Según sus comentarios, parece que hay varios tipos de sensores NMEA 0183 conectados al puerto serie. (Dando otras longitudes de los paquetes pero todos comenzando con $ character).

Reemplace ParseAndCheckNMEA_HDT con la siguiente función para validar las cadenas en ese caso:

Function ParseAndCheckNMEA(const parseS: AnsiString): Integer; // Example packet: $HEHDT,10.17,T*28 + CRLF var i, p: Integer; xorSum: Byte; xorStr: AnsiString; begin Result := 0; // Assume ok if (Pos(''$'', parseS) = 1) then // Start header ok ? begin p := Pos(''*'', parseS); if (p <> 0) and (Length(parseS) >= p + 2) then // Assumes a checksum in packet begin xorSum := Ord(parseS[2]); for i := 3 to p - 1 do // Calculate checksum xorSum := xorSum xor Ord(parseS[i]); xorStr := IntToHex(xorSum, 2); if (UpperCase(xorStr) <> Copy(parseS, p + 1, 2)) then // Checksum ok ? Result := 3; // Wrong checksum end else Result := 2; // No checksum end else Result := 1; // Wrong header end;