Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с COM-портом
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы
CSB
Тема не раз поднималась, но все таки остались вопросы.
Есть датчик, который посылает на ПК некие промежуточные результаты. На ПК все нормально принимается и обсчитывется конечный результат. Пакеты по 8 байт. Скорость UART 115200 kbps. Использую ReadFile() и CPort ( В CPort тоже используется ReadFile() ). Но как только частота передачи возрастает до 1000 посылок в секунду, то в винде начинатся проблемы: приходят неполные пакеты, часто приходит только заголовок пакета, а остальная часть нули или заголовок может оказаться в середине пакета. Увеличение приемного буфера в винде не решило проблемы. При отключении графики и прочего пакеты иногда принимаются нормально. Но без отображения результатов никак.

ЗЫ
В Terminal все принимается нормально - там есть возможность записать в лог принимаемые байты.
Пробовал DLPortIО, но так и не понял как подружить COM с этим драйвером.
beer_warrior
А каким образом вызывается ReadFile()? По событию, таймеру, в отдельном потоке?
CSB
В потоке
beer_warrior
А portmonом его? Такое впечетление, что принимается оно правильно, а из буфера вынимается не в тот момент.
CSB
Дык, я ж говорю, что терминальной программой все нормально принимается (то что она несколько зависает, то ничего - главное все пакеты целые). Дело именно в моей программе =)

Этим читаю:
Код
procedure InComm1(var i:byte;var IsIn:boolean);
var
bytes1:dword;
begin
     IsIn:=false;
     clearcommerror(hcom1,com_error,@stat1);

   if stat1.cbInQue>0
   then
    begin
       if  readfile(hcom1,databuf1,bufsize1,bytes1,nil)
       then
        begin
         i:=databuf1;
         IsIn:=true;
        end
       else
        showmessage('Ошибка приема');
    end;

end;


Читаю просто вызовом функции в потоке.
(та же проблема остается при использовании CPort310)
lolikandr
ReadFile() вызывается в отдельном потоке по какому событию? При помощи SetCommMask или еще как?
PS: Пока писал, ответ появился. Почитайте что-нибудь типа такого:
http://www.delphimaster.ru/articles/comport2/index.html
Сразу скажу, что лучше Overlapped режим.
CSB
Сегодня выяснилось, что и в Terminal приходят обрывки пакетов, реже чем в моей программе, но все-таки они есть. portmon показывает, что там приходят именно обрывки sad.gif Сейчас железо очередной раз перепроверяю. Попробую снизить скорость.

Блин, где же собака порылась ?
Andrew2000
Цитата(CSB @ Feb 3 2007, 16:05) *
Попробую снизить скорость

Скорость чего? Ваши 8 байт раз в 1мс только на 115200 и пролезут (если я математику не забыл)
_Sam_
Может в паузе между байтами или пакетами?
CSB
Цитата
Скорость чего? Ваши 8 байт раз в 1мс только на 115200 и пролезут (если я математику не забыл)

Скорость передачи. Это тестовая задача, потому можно варьировать некоторыми параметрами. Просто буду снимать меньше показаний и все. Такое впечатление, что пакеты теряются по дороге к ПК, хотя если смотреть по JTAG'у, то все нормально.
Математика: 115200 kbps - это 11520 kBps (10 байт кадр). У меня получается 8 kBps. Поэтому остается некоторый запас.
CSB
Цитата
Может в паузе между байтами или пакетами?
Не понял что вы имели в виду. (Паузы между пакетами разные - зависят от воздействия на датчик.)

Ну путь винда как-то отделяет во времени пакеты, но теряться-то при этом они не должны, т.к. входного буфера должно вполне хватать.
Andrew2000
Цитата(CSB @ Feb 4 2007, 00:43) *
Скорость передачи. ...

Я имел ввиду, что на 57600 уже не пролезет.

Цитата(CSB @ Feb 4 2007, 00:43) *
... (10 байт кадр). ...

Бит? т.е. без контроля - тока старт и стоп.

Обычно, хвосты теряются из-за ошибок передающей стороны - когда выдаете следующий байт не дождавшись "ухода" предыдущего в линию.
CSB
Цитата
Бит? т.е. без контроля - тока старт и стоп.

угу, конечно бит.

Цитата
Обычно, хвосты теряются из-за ошибок передающей стороны - когда выдаете следующий байт не дождавшись "ухода" предыдущего в линию.

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

Стартовый байт есть в пакете? Байт стаффинг или 9битный формат передачи для стартового байта используется?
CSB
Пакет обрамлен стартовыми и оконечными байтами (при таком обрамлении пакета мне проще онадизировать целостность пакета). Формат передачи: 10 бит, стартовый бит + 8 бит данных + 1 стоп-бит. Все стандартно.
immelstorm
В принципе, можно попробовать работать с портом напрямую.
Я писал прогу, работающую как цифровой осциллограф, у меня получились следующие результаты:

Погрешность измерения временных интервалов:
На частоте до 1 кГц: не более 1%;
На частоте 1-10 кГц: не более 10%;
На частоте 10-50 кГц: не более 50%;

Вот кусок кода, отвечающий за доступ к порту:

//Маска битов для определения линии запуска
WaitMask:=$0;
if CTS_Start.Checked then WaitMask:=WaitMask or $10;
if DSR_Start.Checked then WaitMask:=WaitMask or $20;
if RI_Start.Checked then WaitMask:=WaitMask or $40;
if DCD_Start.Checked then WaitMask:=WaitMask or $80;

//Настройка порта
with SPort do begin
OpenDriver;
WriteByte(Base+3,$83);
WriteWord(Base,$0001);
WriteByte(Base+3,$3);
end;

HoldByte:=0;
WR:=SPort.ReadByte(Base+4);
SPort.WriteByte(Base+4,WR and $FC);
if HoldRTS.Checked then HoldByte:=HoldByte or $02;
if HoldDTR.Checked then HoldByte:=HoldByte or $01;

//Зарядка конденсатора, ожидание переходных процессов.
StartTimer.Enabled:=true;
While StartTimer.Enabled and (Aborted = false) do begin
//Держать сигналы
WR:=SPort.ReadByte(Base+4);
SPort.WriteByte(Base+4,WR or HoldByte);
Application.ProcessMessages;
end;

//Ожидание первого импульса.
D:=SPort.ReadByte(Base+6) and WaitMask;
//D1:=D and WaitMask;

repeat
Application.ProcessMessages;

WR:=SPort.ReadByte(Base+4);
SPort.WriteByte(Base+4,WR or HoldByte);

D1:=SPort.ReadByte(Base+6);
D1:=D1 and WaitMask;
until (D<>D1) or Aborted;

//Байт для удержания RTS и/или DTR
WR:=SPort.ReadByte(Base+4);
SPort.WriteByte(Base+4,WR or $02);

//Включение таймеров
HighResTimer1.Enabled:=true;
HighResTimer1.StartTimeMeasure;
STime:=GetTickCount;

while ((GetTickCount-STime)<MeasureTime) and (not Aborted) do begin
//RTS / DTR
SPort.WriteByte(Base+4,WR);
//Сигналы
D:=SPort.ReadByte(Base+6);
if D<>D1 then begin
HighResTimer1.StopTimeMeasure;
Time:=HighResTimer1.GetTimeDifference;
HighResTimer1.StartTimeMeasure;
SetLength(Data, I+1);
Data[I,0]:=Time+Data[I-1,0];
Data[I,1]:=D;
D1:=D;
Inc(I);
end;
end;

EndTime:=GetTickCount;

HighResTimer1.StopTimeMeasure;


Разумеется, нужно знать спецификации UART.
Сразу предупреждаю: в windows работа с железками в реальном времени возможна только из RING 0. Всё остальное - разные степени приближения.
_Sam_
Цитата
Пакет обрамлен стартовыми и оконечными байтами (при таком обрамлении пакета мне проще онадизировать целостность пакета). Формат передачи: 10 бит, стартовый бит + 8 бит данных + 1 стоп-бит. Все стандартно.

1.Байт стаффинг используется? Что например получится если один из неадресных байтов будет таким же как адресный?
2.Вы говорили что пакеты неполные получаете => целостность пакетов нарушена. Если п.1 не поможет попробуйте оставить всё как есть, но передавать из железяки всё время одинаковый пакет типа
s 1 2 3 4 5 e, где s, e стартовый и стоповый байты, а цифирки - значения передаваемых байтов. Может локализуете проблему.
CSB
Байт стаффинг не используется: пакет-то обрамлен с двух сторон и имеет фиксированную длину, поэтому отличать адресный байт от неадресного просто.

Цитата
2.Вы говорили что пакеты неполные получаете => целостность пакетов нарушена. Если п.1 не поможет попробуйте оставить всё как есть, но передавать из железяки всё время одинаковый пакет типа
s 1 2 3 4 5 e, где s, e стартовый и стоповый байты, а цифирки - значения передаваемых байтов. Может локализуете проблему.
Передавал и смотрел в железяку JTAG'ом - отправлялось все нормально. Кабель для связи - экранированный.
lolikandr
Была такая же бага (потери кусков данных), когда читал просто в цикле по такому же принципу:
Код
if stat1.cbInQue>0  then

И тоже терминальной программой все нормально принималось.
Только, когда использовал компонент TComm от AsyncPro и событие OnRxChar, получил все данные без потерь от непрерывного потока на обычном COM-порту при скорости 115200.
На том же компоненте удалось получать данные и при скорости 921600 на виртуальном COM-порту от FTDI.
По поводу проверки железа - Rx и Tx закорачивается в конце кабеля. Пишется микрокусок программы (а то и отдельная микропрограмма) на передачу-прием-контроль. Сразу видно, что не так. Для виндовс программы тоже желательно провести такую процедуру, чтобы быть увереным в своей программе.
Joy
Цитата(CSB @ Feb 2 2007, 16:11) *
Тема не раз поднималась, но все таки остались вопросы.
Есть датчик, который посылает на ПК некие промежуточные результаты. На ПК все нормально принимается и обсчитывется конечный результат. Пакеты по 8 байт. Скорость UART 115200 kbps. Использую ReadFile() и CPort ( В CPort тоже используется ReadFile() ). Но как только частота передачи возрастает до 1000 посылок в секунду, то в винде начинатся проблемы: приходят неполные пакеты, часто приходит только заголовок пакета, а остальная часть нули или заголовок может оказаться в середине пакета. Увеличение приемного буфера в винде не решило проблемы. При отключении графики и прочего пакеты иногда принимаются нормально. Но без отображения результатов никак.

ЗЫ
В Terminal все принимается нормально - там есть возможность записать в лог принимаемые байты.
Пробовал DLPortIО, но так и не понял как подружить COM с этим драйвером.

была похожая проблемма: никак не удавалось получить полный пакет. решил с помощью побайтового приема (ReadFile() в цикле принимает один байт, который потом складывается в буфер)
CSB
Цитата
терминальной программой все нормально принималось.

Повторюсь: проблема была выявлена и при работе с терминалом.

Цитата
решил с помощью побайтового приема

По-байтовый прием и делаю.

Тут на форуме читал, что ReadFile() весьма медленная функция и нужно писать свой драйвер или юзать что-то типа DriverLINX Port IO. Но DriverLINX Port IO пока так и не смог прикрутить к СОМ-порту.
_Sam_
Цитата
Тут на форуме читал, что ReadFile() весьма медленная функция и нужно писать свой драйвер

Ну хз. Ни в Win98 ни в WinXP подобной проблемы у меня не было, хотя пакеты имели бо'льший размер!
ReadFile должна возвращать количество принятых байт, возвращает 8? Было бы неплохо посмотреть код настройки ком порта.
AndrewKirs
По-моему, надо использовать асинхронный режим IO (CreateFile с флагом OVERLAPPED), и буфер достаточно большого размера (ну хоть несколько Кб).
Georgy
А ни слова про длительность и амплитуду импульсов.
Проверьтесь - было дело, бодался с таким явлением, оптопара H11Ll1 уродовала длительность. После подбора тока диода сбои истребились.
Удачи!
amw
Убедится в наличии паузы по сигналу Rx между пакетами.
Установить ПРАВИЛЬНО таймауты - SetCommTimeouts()
Проверят количество принятых байт после ReadFile()
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.