Форум: "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.072 c