Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2013.03.22;
Скачать: CL | DM;

Вниз

"Принудительная" запись в COM-порт   Найти похожие ветки 

 
Alex_C   (2009-11-24 08:35) [0]

В отдельном треде раз в N-милисекунд посылаю в COM-порт определенную комманду. Комманда очень короткая - всего 3 символа. Посылку контролирую при помощи монитора COM-портов HHD Free Serial Port Monitor. Так вот - пока время между коммандами "большое" - комманды идут как и положено - одна за другой. Но при уменьшении промежутка времени меньше какой то величины - комманды "накопливаются", и поступают в COM-порт как бы пакетом (сразу порядка 20 "накопленных" комманд.) Вопрос: как этого избежать и контролировать чтоб комманты шли не пакетами? Время между коммандами должно быть максимально маленьким.


 
Leonid Troyanovsky ©   (2009-11-24 08:49) [1]


> Alex_C   (24.11.09 08:35)  

http://delphimaster.net/view/2-1258959429/
See [5]

--
Regards, LVT.


 
Alex_C   (2009-11-24 08:53) [2]


> Leonid Troyanovsky


Да я это помню! Но есть одно НО: к оборудованию, которым я управляю по ком-порту идет "пробная" программа. Так вот: если в этой программе я задаю допустим интервал 100Мс - там все идет как надо, не пакетами, а по одной комманде. А если делаю у себя в программе - пакетами. Выходит все же как то это можно контролировать?


 
Alex_C   (2009-11-24 08:58) [3]

Возможно это поможет:
я пишу в ком-порт при помощи этой ф-ции


function TComPort.WriteBytes(ByteArray: Pointer; Count: integer): cardinal;
var
 Signaled, RealWrite, BytesTrans: cardinal;
 WriteOL: TOverLapped; {структура для асинхронной записи}
 Success: boolean;
begin
 Result := 0;

 {создание события для асинхронной записи}
 FillChar(WriteOL, SizeOf(WriteOL), 0);
 WriteOL.hEvent := CreateEvent(nil, True, True, nil);

 try
   {начало асинхронной записи}
   WriteFile(FHandle, ByteArray^, Count, RealWrite, @WriteOL);
   {ожидания завершения асинхронной операции}
   Signaled := WaitForSingleObject(WriteOL.hEvent, INFINITE);
   {получение результата асинхронной операции}
   Success  :=
     (Signaled = WAIT_OBJECT_0) and
     (GetOverlappedResult(FHandle, WriteOL, BytesTrans, False));
   if not Success then
     raise Exception.Create("Can not write to COM port!");
   Result := RealWrite;
 finally
   {освобождение дескриптора события}
   CloseHandle(WriteOL.hEvent);
 end;
end;


Ф-ция взята из очень хорошей книги "Работа с последовательным портом" - кажется так она называется.


 
Leonid Troyanovsky ©   (2009-11-24 09:16) [4]


> Alex_C   (24.11.09 08:58) [3]

> я пишу в ком-порт при помощи этой ф-ции

Пардон, а зачем писать асинхронно? Если уж 3 байта.

--
Regards, LVT.


 
Сергей М. ©   (2009-11-24 09:24) [5]

Что за мода такая - не анализировать рез-т вызова API-функциии ?

Ведь сказано же в справке :

If hFile was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, ..WriteFile may return before the write operation has been completed. In this case, WriteFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING

may - это не must !


 
MBo ©   (2009-11-24 09:31) [6]

FlushFileBuffers для порта работает?


 
Alex_C   (2009-11-24 09:49) [7]


> Что за мода такая - не анализировать рез-т вызова API-функциии
> ?


Поверил умной книжке - книга действительно классная и плюс единственная по работе с последовательными портами, где все так хорошо рассказано :)


> ..WriteFile may return before the write operation has been
> completed. In this case, WriteFile returns FALSE and the
> GetLastError function returns ERROR_IO_PENDING


...WriteFile может возвратить результат до того, как операция будет завершена. В этом случае WriteFile возвратит False и функция GetLastError возвратит ERROR_IO_PENDING.

Получается надо так:


function TComPort.WriteBytes(ByteArray: Pointer; Count: integer): cardinal;
var
 Signaled, RealWrite, BytesTrans: cardinal;
 WriteOL: TOverLapped; {структура для асинхронной записи}
 Success: boolean;
 y: Integer;
begin
 Result := 0;

 {создание события для асинхронной записи}
 FillChar(WriteOL, SizeOf(WriteOL), 0);
 WriteOL.hEvent := CreateEvent(nil, True, True, nil);

 try
   {начало асинхронной записи}
   if not WriteFile(FHandle, ByteArray^, Count, RealWrite, @WriteOL) then
   //*********** Результат False - операция WriteFile не завершена
   begin
      y := GetLastError;
      if y = ERROR_IO_PENDING then
        WaitForSingleObject(WriteOL.hEvent, INFINITE);
   end
   else
     {ожидания завершения асинхронной операции}
     Signaled := WaitForSingleObject(WriteOL.hEvent, INFINITE);
   {получение результата асинхронной операции}
   Success  :=
     (Signaled = WAIT_OBJECT_0) and
     (GetOverlappedResult(FHandle, WriteOL, BytesTrans, False));
   if not Success then
     raise Exception.Create("Can not write to COM port!");
   Result := RealWrite;
 finally
   {освобождение дескриптора события}
   CloseHandle(WriteOL.hEvent);
 end;
end;


 
Alex_C   (2009-11-24 09:52) [8]


> FlushFileBuffers для порта работает?


Попробовал - не помогает!


 
Сергей М. ©   (2009-11-24 10:18) [9]


> Получается надо так


Не получается.

Если WriteFile вернула True, то это означает, что запрошенная операция была успешно выполнена синхронно. Какой смысл ждать сигнал ивента и следом читать overlapped-результат, если операция заведомо успешно завершена на момент возврата из WriteFile ?


 
Alex_C   (2009-11-24 10:49) [10]


> Какой смысл ждать сигнал ивента и следом читать overlapped-
> результат, если операция заведомо успешно завершена на момент
> возврата из WriteFile ?


Ок!
Понял! Так получается:


function TComPort.WriteBytes(ByteArray: Pointer; Count: integer): cardinal;
var
Signaled, RealWrite, BytesTrans: cardinal;
WriteOL: TOverLapped; {структура для асинхронной записи}
Success: boolean;
y: Integer;
begin
Result := 0;

{создание события для асинхронной записи}
FillChar(WriteOL, SizeOf(WriteOL), 0);
WriteOL.hEvent := CreateEvent(nil, True, True, nil);

try
  {начало асинхронной записи}
  if not WriteFile(FHandle, ByteArray^, Count, RealWrite, @WriteOL) then
  // Операция WriteFile не завершена
  // Ожидаем завершение и анализируем результат
  begin
     y := GetLastError;
     if y = ERROR_IO_PENDING then
     begin
       {ожидания завершения асинхронной операции}
       Signaled := WaitForSingleObject(WriteOL.hEvent, INFINITE);
      {получение результата асинхронной операции}
      Success  :=
        (Signaled = WAIT_OBJECT_0) and
        (GetOverlappedResult(FHandle, WriteOL, BytesTrans, False));
      if not Success then
        raise Exception.Create("Can not write to COM port!");
      else
        Result := BytesTrans;
     end
     else
       raise Exception.Create("Can not write to COM port!");
  end
  else
    Result := RealWrite;
finally
  {освобождение дескриптора события}
  CloseHandle(WriteOL.hEvent);
end;
end;



 
vastani   (2009-11-24 11:20) [11]

Alex_C очень похоже, что Ваша беда называется FIFO последовательного порта!!! Ее можно рулить только в реестре(если программно) или ручками если зайти в система-девайсы-Ваш порт-пареметры порта-дополнительно(кнопка!)
Установить надо ПОБАЙТНУЮ работу т.е. FIFO =1 в два ручья, тогда железяка не должна ждать уровня переполнения и сразу отдать системе.
Второе. Надо в ините порта тоже поставить отдавать побайтно, т.е. чтобы уже связка(слой) система+драйвер не накапливали в буфере, а сразу трезвонили проге СОБЫТИЕ пришел(отправлен) байт!
Если непонятно могу ширше... )


 
Alex_C   (2009-11-24 21:53) [12]


> Если непонятно могу ширше... )


Хотя бы общий пример хотелось бы!


 
vastani   (2009-11-26 15:35) [13]

Меня не было тут немного :) надеюсь интерес не погиб...!
Ох-ох-ох.... тема то интересная, кто плавал уже, но разноплановая блин... с точки зрения комплексного затрагивания букета разных причин и свойств и пр...... ладно, придется подвинуть свою лень.
Итак, сначала по поводу сказанного и "с чем его едят":
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\1\Device Parameters
содержит 3 строковых параметра(текущие уставки) ответственных за FIFO COM1 порта в данном случае:
ForceFifoEnable (вкл/выкл вообщем),RxFIFO,TxFIFO=размерчики.
программно рулим естественно функциями работы с реестром.
Стандартные функции, включая API винды фифо не рулят вообще!
Лично я не находил даже упоминания об этом...


 
vastani   (2009-11-26 15:37) [14]

Работу фифо прочувствовать просто. Берем терминалочку, например мне нравится в таких случаях эта http://kolibdb.100free.com/files/wTerm.zip
далее соединяем два порта COM1+COM2 простейшим нульмодемным соединением Tx1+Rx2 и Rx1+Tx2. Затем запуск двух копий приложения и открытие этих портов с минимальной скоростью. Давим и удерживаем символьную клавишу и лицезреем, как на приемной стороне БАЙТЫ ПОЛУЧАЮТСЯ и отображаются ПАЧКАМИ= FIFO обьема! Т.е. они выплевываются, скажем по 8 байт, видно, что накапливаются и именно выплевываются, достигнув порога срабатывания. Рулим FIFO и зрим эффект.
Помимо фифо в сабже "замешаны" параметры при открытии порта, а именно "...Поля структуры COMMTIMEOUTS...".


 
vastani   (2009-11-26 15:38) [15]

В связи с этим НАСТОЯТЕЛЬНО советую перечитать статейку "Работа с коммуникационными портами (COM и LPT) в программах для Win32" (например тут http://www.citforum.ru/hardware/articles/comports/)
ЭТО КАЧЕСТВЕННЫЙ ПРОФЕССИОНАЛЬНЫЙ ПОДХОД при оседлании последовательных портов в WIN32! Для многих сведения там излагаемые просто открытие глаз на принципы и то как надо грамотно писать коммуникационные проги, особенно, когда работа идет с N портами одновременно (мультипортовка).
Еще важно знать это: "Точное время: измеряем, применяем" (http://habrahabr.ru/blogs/delphi/75234/)
Вот ИМЕННО на ПЕРЕСЕЧЕНИИ этих 3-х китов и только после хотябы вникания(лучше изучения) будет истина(решение) проблем сабжа и иже с ним.
Подобные вещи ипроблемы неоднократно возникают у спецов работающих с железом, контроллерами, сетями "нижнего уровня" и их протоколами, напрмер MODBUS и проблемы полудуплекса RS-485....
Считаю, что выдал обильную инфу, переборов свою лень и ничего не закуркулил :) успехов и продвинутых результатов!


 
Alex_C   (2009-11-27 08:46) [16]


> надеюсь интерес не погиб...!


Интерес очень большой :)
Темя для меня очень важная - хочу досканально в ней разобраться.
Спасибо за инфо - буду читать и разбираться!



Страницы: 1 вся ветка

Текущий архив: 2013.03.22;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.104 c
15-1353292991
MonoLife
2012-11-19 06:43
2013.03.22
Принтер Canon LBP-1120, HP LaserJet 1005 в Win 7 64 bit.


15-1338256419
J
2012-05-29 05:53
2013.03.22
скачать видео со станицы в Мазилле.


4-1261045077
Гном11
2009-12-17 13:17
2013.03.22
Что вместо WinSingt в Delphi 2006


15-1353075620
Kirill123
2012-11-16 18:20
2013.03.22
graphics32


15-1353242533
Jimmy
2012-11-18 16:42
2013.03.22
Проблемы с оперативкой