четверг, 25 апреля 2013 г.

RS232 в Lazarus (COM порт) - первое знакомство


Возникла необходимость работы с COM портом (RS232).
Для работы решил использовать библиотеку Synapse. Хорошая и быстрая библиотека. Модуль synaser.

Работать с портом довольно просто.
Основной класс для работы - TBlockSerial.
Для передачи команд я использую строку AnsiString. В ответ я так же жду строку. Мне кажется
такой способ передачи наиболее удобным.

const
  recvtimeout=3000; // время ожидания ответа от устройства

var
  ser: TBlockSerial;
  s:AnsiString;
  waiting:integer;
  dtStart:TDateTime;
  has_timed_out:boolean;
  tempbuf, output:AnsiString;

begin
  ser:= TBlockSerial.Create;
  ser.RaiseExcept := True;
  ser.LinuxLock := False; // это требуется для Linux. Если это не установить, то не удастся открыть порт.

  ser.Connect('COM1'); // открытие порта
  ser.Config(9600, 8, 'N', 0, false, false); // указываем параметры передачи данных

  
  s:='AT'+#13; // это для примера
  ser.SendBuffer(@s[1],Length(s)); // отправляем буфер в порт
  s:='';

  
  {Если размер ответа известен и устройство стабильно отвечает то все просто.}
  sleep(200); // делаем небольшую задержку, так как устройство не сразу отвечает
  waiting:=ser.WaitingData; // сохраняем в переменную сколько символов ждут в порту считывания
  SetLength(s,waiting);
  ser.RecvBuffer(@s[1], waiting);
  // в строке s будет результат
  
  
  { У меня устройства могут отвечать долго и понемногу. Поэтому я несколько усложнил механизм опроса.
    Я жду ответа от устройства. И если ничего не будет в течении recvtimeout миллисекунд,
    то будем считать что весь ответ уже получен. Этот способ подойдет, когда вы не знаете 
какой ответ вам может прийти.  
  }

  output:='';
  while 1=1 do begin
    // начинаем ждать ответа
    dtStart := Now;
    has_timed_out:=false;
    while ser.WaitingData=0 do begin
      if MilliSecondsBetween(dtStart, Now) > recvtimeout then begin
        has_timed_out:=true;
        break;
      end;
      sleep(200);
    end;

    if has_timed_out then break; // выход. в буфере ничего нет

    // считываем все из буфера порта
    waiting:=ser.WaitingData;
    SetLength(tempbuf, waiting);

    try
      ser.RecvBuffer(@tempbuf[1], waiting);
    except
    end;

    output+=tempbuf;
  end;
  // в строке output результат 
  

  
  // а теперь получим результат, когда известно размер ответа
  ser.RecvBufferEx(@s[1], waiting,500);
  
  ser.CloseSocket; // закрытие порта
  FreeAndNil(ser);
 

4 комментария: