Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Вниз

"Принудительная" запись в 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 вся ветка

Форум: "WinAPI";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.076 c
15-1343987497
AV
2012-08-03 13:51
2013.03.22
Quip 2012. Как раз и навсегда изменить порт с 433 на 5190?


2-1338711145
Разветка
2012-06-03 12:12
2013.03.22
как заставить выполнить полность все условия


15-1343713763
Артём
2012-07-31 09:49
2013.03.22
MD5 hash


15-1331053532
vrem
2012-03-06 21:05
2013.03.22
телевизор 42" как монитор для компьютера


6-1264429152
Цукор5
2010-01-25 17:19
2013.03.22
Остановка сервера





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский