Вопрос по – Синхронизация последовательного порта в Delphi

1

У меня все еще есть проблемы с компонентом TComPort, но на этот раз логика не лежит на самом компоненте. У меня есть устройство, которое отправляет некоторые строки ascii через последовательный порт, мне нужно вставить эти строки, проблема в том, что компьютер реагирует очень быстро, поэтому в случае, если char захватывает только часть строки, остальная часть строки возвращается позже ... поэтому анализ, когда он получен, делает невозможным.

Я думал о написании таймера, который проверял, не было ли последовательной активности 10 секунд или более, а затем вставлял строку, которую я сохраняю, в буфер. Но этот метод непрофессионален, если нет праздного события, которое я могу выслушать ... В ожидании лучшего решения моей проблемы. Благодарю.

Это известная проблема. Имел это в большем количестве сред. Триггер события данных действительно быстрее, чем данные, которые следуют. Не уверен, что есть что-то еще, кроме небольшого ожидания перед чтением. pritaeas
написать пакетный компонент не так сложно. все данные из события поступают в буфер, а пакет анализирует буфер, в зависимости от ваших потребностей, вы можете иметь начальное условие, конечное условие и так далее ... whosrdaddy
Это вполне нормально, и вы должны просто сохранить символы в буфере и сбросить таймер. Затем используйте таймер для запуска фактической активности - таймер может быть довольно жестким. Вы хотите получить "конечный автомат" и есть триггеры для событий. mj2008
Предположим, вы используете Djean Crnila и др. TComport (несколько компонентов называются «TComport»). Эта проблема может быть связана с триггером события данных, но также возможно, что скорость передачи данных вашего последовательного устройства установлена на скорость, отличную от скорости вашего управления компортом. Если ваше устройство отправляет пакеты раз в несколько мс, вы легко сможете захватить и проанализировать весь пакет данных, если пакет имеет разумную длину. Отправляет ли устройство символ завершения пакета? Делает это проще. Если вы предоставите более подробную информацию об устройстве, полученном пакете и т. Д., Кто-то может оказать помощь. SteveJG

Ваш Ответ

5   ответов
2

Note. Most com-port components do not have a clue when to report back to the owner. Normally the thread that is responsible to gather the bytes from the port is informed by the OS that one or more bytes are ready to be processed. This information is then simply popped up to your level. So when you expect the message to be transferred, you get what the OS is giving you.

Вы должны буферизовать все входящие символы в глобальном буфере. Когда вы получите последний символ в строке сообщения, обработайте сообщение.

Вот пример, где начало сообщения идентифицируется специальным символом, а конец сообщения идентифицируется другим символом.

Если ваше сообщение составлено по-другому, я уверен, что вы сможете выяснить, как адаптировать код.

var
  finalBuf: AnsiString;

{- Checking message }
Function ParseAndCheckMessage(const parseS: AnsiString) : Integer;
begin
  Result := 0; // Assume ok
  {- Make tests to confirm a valid message }
  ...
end;


procedure TMainForm.ComPortRxChar(Sender: TObject; Count: Integer);
var
  i,err: Integer;
  strBuf: AnsiString;
begin
  ComPort.ReadStr(strBuf, Count);
  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 := ParseAndCheckMessage(finalBuf);
              if (err = 0) then 
                {- Handle validated string }
              else
                {- Handle error } 
            end;
          finalBuf := '';
        end; 
    else
      finalBuf := finalBuf + strBuf[i];  
    end;
end;
3

Типичный обработчик для события OnRXChar:

procedure XXX.RXChar(Sender: TObject; Count: Integer);
begin
  ComPort.ReadStr(s, Count);
  Accumulator := Accumulator + s;
  if not AccumContainsPacketStart then
    Accumulator := ''
  else if AccumContainsPacketEndAfterStart then begin
    ExtractFullStringFromAccum;
    ParseIt;
  end;
end;
Error: User Rate Limit Exceeded opc0de
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededReading binary data from serial port using Dejan TComport Delphi componentError: User Rate Limit ExceededTComPort.Read( var buffer; Count:Integer)Error: User Rate Limit ExceededTComPort.ReadStr( var Str:AnsiStr; count:Integer).
-2

Для определенного количества символов мы можем использовать задержку за несколько миллисекунд до ReadStr, чтобы убедиться, что данные полностью отправлены. Пример для 4 количества символов:

procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
  Str: String;
  tegangan : real;
begin
  sleep(100); //delay for 100ms
  ComPort1.ReadStr(Str, 4);

...

3

После использования ряда компонентов последовательного порта я получил лучшие результаты до сих пор, используяCreateFile('\\?\COM1',GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0), передавая этот дескриптор экземпляру THandleStream и запуская выделенный поток для чтения из него. Я знаю, что потоки занимают немного больше времени, чем написание обработчика событий, но это все же лучший способ справиться с любыми проблемами синхронизации, возникающими при использовании последовательных портов.

1

Если у вашего протокола есть маркеры начала / конца, вы можете использовать TComDataPacket для предоставления вам полных пакетов, когда они будут доступны.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded opc0de

Похожие вопросы