Быстрый обмен данными через COM-порт

Модератор: Модераторы разделов

v2e
Сообщения: 50
ОС: GGL (Gentoo GNU/Linux)

Быстрый обмен данными через COM-порт

Сообщение v2e »

Приветствую всех!

Ситуация:
Есть прибор, подключённый к COM-порту компьютера. Компьютер посылает прибору 1 байт, в ответ на который прибор посылает в компьютер 4 байта. Такую операцию необходимо повторять 1000 раз в секунду. То есть период одного такого обмена должен составлять 1 мс.

Попытки:
  • Сперва я пытался открывать СОМ-порт как файл и использовать для чтения и записи функции read() и write() соответственно. В результате получил хороший стабильный обмен, но с периодом никак не меньше 2 мс. Такой результат мне не подходит.
  • Потом я попробовал считывать и записывать в СОМ-порт по его адресу функциями inb() outb(). В результате получил сумасшедшее быстродействие, но никакой стабильности. Причёсывание программы, поиск и устранение сомнительных мест в ней привели меня к довольно странным результатам. А именно:
    После запуска программы обмен идёт около секунды (каждый раз по-разному) нормально, а потом вдруг останавливается, как будто программа ждёт прихода байт от прибора, а они не приходят. Причём, обрыв происходит строго между "четвёрками". Т.е. не бывает случая, чтобы пришло, скажем, 3 байта вместо 4-х.
    В связи с этим я заподозрил, что прибор не получает "сигнального" байта, раз не выдаёт ответа, поместил в программу проверку "ухода" байт из СОМ-порта. Итак, программа показывает, что последний байт (перед остановкой) ушёл, а ответные не пришли.
    Если в программе сделать задержку вместо 1 мс, скажем, 50 мс, то обмен длится несколько минут до остановки. Если поставить 100 мс, то обрыва омена я вообще не дождался.

Прибор работает "железно". То есть, в ём микроконтроллер, в котором всё запрограммировано по тактам, так что если ему придёт байт, то не выдать ответных он не может.

Может быть, у кого есть какие мысли по этому поводу? Или собственный похожий опыт? В чём может таиться проблема?

P.S.И всё это время меня не оставляет в покое мысль о поразительной стабильности работы функций read() и write() с этим прибором при периоде обмена 2-3 мс.

Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: Быстрый обмен данными через COM-порт

Сообщение sash-kan »

может быть, вы упираетесь в ограниченные возможности контроллера (что там нынче интегрируется вместо чипа 8259?)
внешним контроллером не пробовали воспользоваться? pci-ным каким-нибудь.
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
ssh
Сообщения: 78
ОС: Debian

Re: Быстрый обмен данными через COM-порт

Сообщение ssh »

v2e писал(а):
02.09.2010 18:24
После запуска программы обмен идёт около секунды (каждый раз по-разному) нормально, а потом вдруг останавливается, как будто программа ждёт прихода байт от прибора, а они не приходят. Причём, обрыв происходит строго между "четвёрками". Т.е. не бывает случая, чтобы пришло, скажем, 3 байта вместо 4-х.
В связи с этим я заподозрил, что прибор не получает "сигнального" байта, раз не выдаёт ответа, поместил в программу проверку "ухода" байт из СОМ-порта. Итак, программа показывает, что последний байт (перед остановкой) ушёл, а ответные не пришли.
Если в программе сделать задержку вместо 1 мс, скажем, 50 мс, то обмен длится несколько минут до остановки. Если поставить 100 мс, то обрыва обмена я вообще не дождался.


Все-таки это сильно напоминает ситуацию с недоходящим до прибора запросным байтом. Оттого возникают вопросы:

1. как именно проверяется уход этого самого байта? программная "проверка" тут ничего не даст, в правильности отправки запроса надо убедиться, поймав посылку непосредственно на линии осциллографом.

2. допустимо ли изменить алгоритм так, чтобы программа, не дождавшись в течение, скажем, секунды, ответа на свой запрос, его - запрос - принудительно повторяла?

3. есть ли гарантия, что начало ответной посылки от прибора не перекрывает конец запроса? (и наоборот, начало следующего запроса не перекрывает окончания предыдущей посылки?)

4. есть ли гарантия, что ваша программа взаимодействует с портом монопольно, без вклинивающихся в ее работу сторонних драйверов?

5. и, наконец, есть подозрение, что при быстрой работе в дуплексном режиме каким-то образом слетают настройки последовательного порта (типа, там, скорость обмена), которые вы, вероятно, как-то выставляете при инициализации своей программы (кстати, это тоже можно увидеть осциллографом). так вот, я бы в такой ситуации стал повторять для профилактики инициализацию порта каждые полсекунды, высылая запросный байт после такой пере-инициализации.
Спасибо сказали:
v2e
Сообщения: 50
ОС: GGL (Gentoo GNU/Linux)

Re: Быстрый обмен данными через COM-порт

Сообщение v2e »

sash-kan писал(а):
02.09.2010 19:03
может быть, вы упираетесь в ограниченные возможности контроллера (что там нынче интегрируется вместо чипа 8259?)
внешним контроллером не пробовали воспользоваться? pci-ным каким-нибудь.

По поводу возможностей контроллера сказать затрудняюсь что-либо. Однако проверил на двух компьютерах (один ~2007 года выпуска, другой ~ 1997 г.). Результаты одинаковые.
Внешним контроллером не пробовал пользоваться, потому что у меня его никогда не было. Да и я думаю, что мои запросы вполне под силу среднему контроллеру, т.к. скорость передачи даже не максимальная ставится, а 57600. Думаю, должно хватать его возможностей.

ssh писал(а):
02.09.2010 21:36
Все-таки это сильно напоминает ситуацию с недоходящим до прибора запросным байтом. Оттого возникают вопросы:

1. как именно проверяется уход этого самого байта? программная "проверка" тут ничего не даст, в правильности отправки запроса надо убедиться, поймав посылку непосредственно на линии осциллографом.

На осциллографе поймать конкретный байт на такой скорости не удаётся, но сегодня проверили прохождение байтов электронной "ловушкой" (см. ниже)

2. допустимо ли изменить алгоритм так, чтобы программа, не дождавшись в течение, скажем, секунды, ответа на свой запрос, его - запрос - принудительно повторяла?

Да, допустимо. Я даже нарочно ставил посылку вместо одного "сигнального" байта двух или трёх подряд (всё равно после приёма любого байта прибор переходит в режим вычислений, в котором он игнорирует любой ввод). Результат тот же.

3. есть ли гарантия, что начало ответной посылки от прибора не перекрывает конец запроса? (и наоборот, начало следующего запроса не перекрывает окончания предыдущей посылки?)

Как я уже говорил, прибор запрограммирован "железно". Т.е. он сперва целиком принимает входящий байт, потом проводит вычисления, и только потом начинает выдавать ответ.
А впрочем, раз уж об этом разговор зашёл, разве компьютерный СОМ-порт не может принимать байты одновременно с передачей? В смысле, аппаратно же приём и передача - разные линии, не так ли? Я полагаю, что приёмный буфер работает и во время передачи. Или я ошибаюсь?

4. есть ли гарантия, что ваша программа взаимодействует с портом монопольно, без вклинивающихся в ее работу сторонних драйверов?

Вот в этом и я теперь сомневаюсь (см. ниже).

5. и, наконец, есть подозрение, что при быстрой работе в дуплексном режиме каким-то образом слетают настройки последовательного порта (типа, там, скорость обмена), которые вы, вероятно, как-то выставляете при инициализации своей программы (кстати, это тоже можно увидеть осциллографом). так вот, я бы в такой ситуации стал повторять для профилактики инициализацию порта каждые полсекунды, высылая запросный байт после такой пере-инициализации.

Вообще-то, мне это кажется странным - слёт настроек во время работы. У вас такое бывало?
Мы смотрели осциллографом, и похоже, скорость обмена была постоянной.


Обновление:
Проверка при помощи "ловушки" показала, что прибор работает честно и "заклинивает" по какой-то другой причине. Т.е. на последний принятый от компьютера байт прибор отвечает корректно, после чего ждёт следующего запроса. Программа же в это время ждёт входящих данных.
Сегодня попробовали ещё в DOS и Windows. Оказалось, что в Windows и GNU/Linux (двух разных дистрах с ядрами 2.4 и 2.6) заклинивает, а в DOS - нет. И это как раз меня тоже наталкивает на мысль о том, монопольный ли доступ имеет моя программа к порту. Но как это проверить?

И ещё есть одна мысль. Она может оказаться довольно обывательской, но тем не менее:
Не может ли драйвер порта Linux вытягивать пришедшие в порт байты в какой-то программный буфер, и моя программа обращается к уже опустошённому порту? Но с другой стороны, раз при большой задержке между записью и чтением работает корректно, значит никто байты из порта не забирает. Но тогда мне вообще ничего не понятно. :)

Видимо, единственная зацепка - это то, что в однозадачной операционке всё идёт нормально, а в многозадачных срывается. А?
Спасибо сказали:
Аватара пользователя
Denjs
Сообщения: 1685
ОС: SuSe 10.2

Re: Быстрый обмен данными через COM-порт

Сообщение Denjs »

Есть пишушие исцилографы... ну впрочем не важно. если осцилогафом никак - ну и пусть.

Тогда поставьте вместо вашего прибора второй компьютер, залинкуйте их по нуль-модему и имитируйте на втором компьютере ваш прибор.
Заодно и гарантированно узнаете доходят байты или нет.
Может это у вас прибор с ума сходит? Скажем на 32000-м байте данных в секунду умирает, т.к. буфек всего 32 кб а сброс происходит раз в секнду? ну я так... к слову...

ещё вопрос: у вас связь с прибором по какому кабелю? по 3-м проводам "облегченным вариантом" или полностью все 9 сигналов залинкованы "по честному"??
если все 9 - то я бы ещё посмотрел как именно инициируется контроллер, что в регистрах и что у вас творится в разных вариантах (под дос/линукс/виндоус) на других сигнальных проводах - может они там с вашим прибором не успевают договориться натчет того как обрабатывать RTS, DSR, CTS ...
В досе например порт тупо инициируется так что бы плевать на эти сигналы.... а под линуксом виндой все по полному - пока сигнал CTS от девайса не получен - данные слать не будем...
имхо - ищите различия в том, что творится в регистрах контроллера под досом и под линем...

в конце концов, залинкуйте комп и прибор кабелем с другой распайкой.... скажем полный кабель замените облегченным о трех жилах)))

извините если что напутал - я контроллер последовательного порта в институте под досом/вынью95 программировал последний раз)))) мог забыть что...
QDroid - Среда исполнения и фреймворк для QtScript.
OTPD - Открытые драйвера промышленных принтеров чеков и этикеток (кроссплатформенная подсистема печати).
Спасибо сказали:
Аватара пользователя
Denjs
Сообщения: 1685
ОС: SuSe 10.2

Re: Быстрый обмен данными через COM-порт

Сообщение Denjs »

Если в программе сделать задержку вместо 1 мс, скажем, 50 мс, то обмен длится несколько минут до остановки.

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

Ещё вопрос. по архитектуре программы. Как я понял - оно у вас ЦИКЛОМ с задержкой между опреациями организовано? или же у вас есть таймер в одном потоке, или скажем вы пользуете прерывание, которое строго 1000 раз в секунду дергает обращение к порту?

Я бы сделал по второму варианту - даже если что-то пропущено - это не приводит к затыканию. А факты того что мы не получили данных - я бы просто записывал в лог... мол - "что делать - не понятно, но вот статистика..."
QDroid - Среда исполнения и фреймворк для QtScript.
OTPD - Открытые драйвера промышленных принтеров чеков и этикеток (кроссплатформенная подсистема печати).
Спасибо сказали:
v2e
Сообщения: 50
ОС: GGL (Gentoo GNU/Linux)

Re: Быстрый обмен данными через COM-порт

Сообщение v2e »

Denjs писал(а):
03.09.2010 00:38
Тогда поставьте вместо вашего прибора второй компьютер, залинкуйте их по нуль-модему и имитируйте на втором компьютере ваш прибор.
Заодно и гарантированно узнаете доходят байты или нет.

Да, это мысль. Надо попробовать. Спасибо за совет.

Может это у вас прибор с ума сходит? Скажем на 32000-м байте данных в секунду умирает, т.к. буфек всего 32 кб а сброс происходит раз в секнду? ну я так... к слову...

Это вряд ли. Дело в том, что прибор просто ждёт сигнала во входной линии. Ему, в принципе, всё равно, что я там ему передаю. Он ждёт стартового бита, можно так сказать.

если все 9 - то я бы ещё посмотрел как именно инициируется контроллер, что в регистрах и что у вас творится в разных вариантах (под дос/линукс/виндоус) на других сигнальных проводах - может они там с вашим прибором не успевают договориться натчет того как обрабатывать RTS, DSR, CTS ...
В досе например порт тупо инициируется так что бы плевать на эти сигналы.... а под линуксом виндой все по полному - пока сигнал CTS от девайса не получен - данные слать не будем...

Управляющие сигналы я игнорирую. Они и в приборе игнорируются, и в программе при задании настроек порта.

Denjs писал(а):
03.09.2010 01:04
Ещё вопрос. по архитектуре программы. Как я понял - оно у вас ЦИКЛОМ с задержкой между опреациями организовано? или же у вас есть таймер в одном потоке, или скажем вы пользуете прерывание, которое строго 1000 раз в секунду дергает обращение к порту?

Да, вы правильно поняли. У меня цикл примерно такой структуры:

Код: Выделить всё

unsigned char incoming_data[4];
while (true)
{
  outb(0x00, 0x3f8); // Посылка сигнального байта в прибор
  usleep(1000); // Пауза

  for (int i=0; i<4;i++)
  incoming_data[i] = inb(0x3f8);
}


Я бы сделал по второму варианту - даже если что-то пропущено - это не приводит к затыканию. А факты того что мы не получили данных - я бы просто записывал в лог... мол - "что делать - не понятно, но вот статистика..."

Да, я тоже уже об этом подумывал, но дело в том, что данные эти, полученные из прибора нужны для анализа спектра. А тогда должны присутствовать строго все выборки. А если каких-то будет не хватать, придётся их как-то (читай - от фонаря) компенсировать. Не хотелось бы, честно говоря.

И потом, как-то ведь функции read() и write() работают с "/dev/ttyS0" в качестве файла. Медленновато, но ведь стабильно. Значит, можно как-то. Вот только как?
Спасибо сказали:
Аватара пользователя
Denjs
Сообщения: 1685
ОС: SuSe 10.2

Re: Быстрый обмен данными через COM-порт

Сообщение Denjs »

Управляющие сигналы я игнорирую. Они и в приборе игнорируются, и в программе при задании настроек порта.

гм... а что на самом деле твориться в регистрах контроллера под вендой / под линуксом / под досом смотрели? (последний наиболее интересен.. мне рассказывать не надо - я уже не пойму... - сами сравните ваши 3 набора...)...

кабель какой у вас? пробовали заменить на 3-х жильный? что-бы гарантированно игнорировать управляющие сигналы...

и ещё мысль... тупая но кто знает что "там" происходит... у вас программа с каким приоритетом запускается? в досе-то он понятно практически всегда "почти-реал-таймовый"... просто я к отличию однозадачных ОС от многозадачных...

QDroid - Среда исполнения и фреймворк для QtScript.
OTPD - Открытые драйвера промышленных принтеров чеков и этикеток (кроссплатформенная подсистема печати).
Спасибо сказали:
ssh
Сообщения: 78
ОС: Debian

Re: Быстрый обмен данными через COM-порт

Сообщение ssh »

v2e писал(а):
02.09.2010 22:48
А впрочем, раз уж об этом разговор зашёл, разве компьютерный СОМ-порт не может принимать байты одновременно с передачей? В смысле, аппаратно же приём и передача - разные линии, не так ли? Я полагаю, что приёмный буфер работает и во время передачи. Или я ошибаюсь?


в теории, конечно, это так; на практике все что угодно бывает.


v2e писал(а):
02.09.2010 22:48
Вообще-то, мне это кажется странным - слёт настроек во время работы. У вас такое бывало?


см. выше.

v2e писал(а):
02.09.2010 22:48
На осциллографе поймать конкретный байт на такой скорости не удаётся, но сегодня проверили прохождение байтов электронной "ловушкой" (см. ниже)


надо постараться. и притом рассмотреть вид последовательной посылки. если в процессе самопроизвольно меняется скорость обмена, то прибор может перестать реагировать на вашу посылку, даже если она и уходит. проверка с нуль-модемом этого не покажет (что такое "электронная ловушка", не знаю).


v2e писал(а):
02.09.2010 22:48
Не может ли драйвер порта Linux вытягивать пришедшие в порт байты в какой-то программный буфер, и моя программа обращается к уже опустошённому порту? Но с другой стороны, раз при большой задержке между записью и чтением работает корректно, значит никто байты из порта не забирает. Но тогда мне вообще ничего не понятно.


вот надо убедиться, что все эти драйверы вырублены во время работы вашей программы. в частности, адреса используемого вами сом-порта НЕ должно быть в файле "/proc/ioports", а его прерывания - в "/proc/interrupts". если это не так - то кто-то с вами конкурирует (это не полная проверка, но хоть что-то).

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

насчет инициации обмена по прерываниям - мысль хорошая.

и наконец, если у вас дело хорошо идет под досом - то есть шанс, что и под dosemu неплохо будет. можно попробовать запустить программу в ее досовской версии под эмулятором (но все же лучше разобраться с чистым линуксом).
Спасибо сказали:
v2e
Сообщения: 50
ОС: GGL (Gentoo GNU/Linux)

Re: Быстрый обмен данными через COM-порт

Сообщение v2e »

Товарищи! Похоже, проблема РЕШИЛАСЬ. Осталось только выяснить, каким образом (см. ниже).
Но мне всё равно хотелось бы разобраться с этим как следует, чтобы был урок на будущее.

Denjs писал(а):
04.09.2010 15:30
Управляющие сигналы я игнорирую. Они и в приборе игнорируются, и в программе при задании настроек порта.

гм... а что на самом деле твориться в регистрах контроллера под вендой / под линуксом / под досом смотрели? (последний наиболее интересен.. мне рассказывать не надо - я уже не пойму... - сами сравните ваши 3 набора...)...

Что творится в регистрах порта я не проверял. До этого просто не дошло. Хотя, надо бы, действительно, посмотреть, что там в разных операционках.

кабель какой у вас? пробовали заменить на 3-х жильный? что-бы гарантированно игнорировать управляющие сигналы...

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

и ещё мысль... тупая но кто знает что "там" происходит... у вас программа с каким приоритетом запускается? в досе-то он понятно практически всегда "почти-реал-таймовый"... просто я к отличию однозадачных ОС от многозадачных...

С приоритетом я тоже пробовал поиграться. Но оказалось, что разницы между обычным и "приоритетом реального времени" (если быть точным, то не совсем реального времени, а в том, что присутствует в стандартном ядре "Linux". Т.е. установил планировщик "SCHED_FIFO" при помощи функции sched_setscheduler() для этой программы. Это немного стабилизировало периодичность действий программы, но не помогло устранить обрывов передачи.

ssh писал(а):
04.09.2010 15:59
v2e писал(а):
02.09.2010 22:48
На осциллографе поймать конкретный байт на такой скорости не удаётся, но сегодня проверили прохождение байтов электронной "ловушкой" (см. ниже)


надо постараться. и притом рассмотреть вид последовательной посылки. если в процессе самопроизвольно меняется скорость обмена, то прибор может перестать реагировать на вашу посылку, даже если она и уходит. проверка с нуль-модемом этого не покажет (что такое "электронная ловушка", не знаю).

На осциллографе мы просмотрели передачу, засинхронизировав его с периодом работы программы. Наблюдали некоторое время, и скорость передачи не менялась (рассинхронизации развёртки осциллографа и сигнала не происходило). Видимо, скорость обмена самопроизвольно не менялась. Да и, честно говоря, я никогда не сталкивался с самопроизвольным изменением скорости обмена COM-порта. Но раз вы обратили на это внимание (видимо, преценденты были), то теперь я буду держать ухо востро.
вот надо убедиться, что все эти драйверы вырублены во время работы вашей программы. в частности, адреса используемого вами сом-порта НЕ должно быть в файле "/proc/ioports", а его прерывания - в "/proc/interrupts". если это не так - то кто-то с вами конкурирует (это не полная проверка, но хоть что-то).

Хм... Я об этих файлах не знал. Спасибо за совет. Надо будет и за ними понаблюдать как-нибудь.
насчет инициации обмена по прерываниям - мысль хорошая.

Дело в том, что я совершенно не знаю, как пользоваться прерываниями. Знаком с ними только по наслышке, но никогда не доводилось использовать. Может быть, вы могли бы мне дать какую-нибудь ссылку на пример или документацию какую-нибудь по этому поводу?
и наконец, если у вас дело хорошо идет под досом - то есть шанс, что и под dosemu неплохо будет. можно попробовать запустить программу в ее досовской версии под эмулятором (но все же лучше разобраться с чистым линуксом).

Вот я тоже решил, что надо "разобраться с чистым линуксом". Как минимум, у Linux открыты исходники и большое сообщество, что должно упрощать разбирательство, как я полагаю. :)

Теперь о некоторых достижениях.
Итак, РЕШЕНИЕМ проблемы послужило включение аппаратного буфера FIFO при инициализации и настройке порта.

Код: Выделить всё

  outb(0x01, base_address+2); // FIFO buffer on.
  // Запись единицы в младший разряд регистра 0x3f8+2
  // 0x3f8 - базовый адрес используемого СОМ-порта

Я полагал, что если микросхема этот буфер поддерживает, то он по умолчанию используется. Видимо, это совсем не обязательно. Получается, что
  • В DOS'е он либо работает по умолчанию, либо программа попросту успевает забирать из порта байты быстрее, чем прибор их туда поставляет (не знаю, насколько это возможно), либо аппаратный буфер FIFO включён и накапливает эти байты.
  • В Windows он, выходит, выключен по умолчанию.
  • В GNU/Linux'e он по умолчанию выключен.

Однако, несмотря на успешную работу с включённым вручную буфером, остаётся неясным следующий момент.
Насколько я понимаю, когда буфер не используется, порт может содержать только один байт. Тогда, если в порт приходит ещё один байт, то он должен переписать прежний байт, не так ли? По идее, должен подняться флаг ошибки, но тем не менее, бит, показывающий наличие в порту пришедшего байта, должен быть равен 1. А у меня получается, что он равен 0, т.к. программа останавливается на этапе ожидания прихода байт в порт (т.е. ожидания единицы в этом разряде).
Что же происходит с принимаемыми байтами в порту при отключенном аппаратном буфере?
Кроме того, я не могу объяснить теперь, почему программа довольно стабильно работала при задержке между записью в порт и чтением из него в 50 мс. Уж за это время там точно должно было всё поперазаписаться в этом порту. :mellow:
Спасибо сказали:
Аватара пользователя
deadhead
Сообщения: 1913
Статус: zzz..z

Re: Быстрый обмен данными через COM-порт

Сообщение deadhead »

v2e писал(а):
06.09.2010 14:28
Кроме того, я не могу объяснить теперь, почему программа довольно стабильно работала при задержке между записью в порт и чтением из него в 50 мс. Уж за это время там точно должно было всё поперазаписаться в этом порту. (IMG:style_emoticons/default/mellow.gif)

Ну, видимо, используется программный буфер ;-)
[x] close
Спасибо сказали:
Аватара пользователя
Denjs
Сообщения: 1685
ОС: SuSe 10.2

Re: Быстрый обмен данными через COM-порт

Сообщение Denjs »

йа зналЪ шоДело в регистрах! :hands: :bb:

рад за автора.
опыт запомним. )
QDroid - Среда исполнения и фреймворк для QtScript.
OTPD - Открытые драйвера промышленных принтеров чеков и этикеток (кроссплатформенная подсистема печати).
Спасибо сказали:
v2e
Сообщения: 50
ОС: GGL (Gentoo GNU/Linux)

Re: Быстрый обмен данными через COM-порт

Сообщение v2e »

deadhead писал(а):
06.09.2010 14:36
v2e писал(а):
06.09.2010 14:28
Кроме того, я не могу объяснить теперь, почему программа довольно стабильно работала при задержке между записью в порт и чтением из него в 50 мс. Уж за это время там точно должно было всё поперазаписаться в этом порту. (IMG:style_emoticons/default/mellow.gif)

Ну, видимо, используется программный буфер ;-)

Хм... Но как понять, используется он или нет? И потом, всё же это как-то странно... Считываешь сразу же после прихода - не считывается. Ждёшь 2 мс - не считывается, а вот ждёшь 50 мс - оно оказывается в программном буфере? Я всё-таки не понимаю, как это всё может работать.
Кстати, а программный буфер как-то включается/выключается?

Denjs писал(а):
06.09.2010 15:02
йа зналЪ шоДело в регистрах! :hands: :bb:

Да, дело оказалось примерно там. :)

рад за автора.
опыт запомним. )

Вот только я боюсь ставить в заголовке темы "РЕШЕНО", поскольку сам не могу внятно никому объяснить, почему в порту не устанавливается (или снимается) флаг прихода байт при выключенном аппаратном буфере и, вероятно, при приходе в порт больше одного байта. Должно же быть возможным считывание последнего пришедшего байта, если даже один пропустил, не так ли?
Спасибо сказали:
Doublespace
Сообщения: 275
ОС: Debian Lenny,Squeeze,Centos

Re: Быстрый обмен данными через COM-порт

Сообщение Doublespace »

Насчет винды странно- по умолчанию птичка "Использовать FIFO" там уже сто лет стоит.
Кстати, когда я возился с QExtSerial под Qt- если между посылкой и приемом ответа принудительно не ставил задержку хотя бы на 1 мс, ответ не принимался,как-то так.
Спасибо сказали:
Аватара пользователя
Denjs
Сообщения: 1685
ОС: SuSe 10.2

Re: Быстрый обмен данными через COM-порт

Сообщение Denjs »

Doublespace писал(а):
07.09.2010 15:16
Кстати, когда я возился с QExtSerial под Qt- если между посылкой и приемом ответа принудительно не ставил задержку хотя бы на 1 мс, ответ не принимался,как-то так.

Сдается мне нужно было если не паузу (sleep) - то какойнибудь QApplication::ProcessMessages() вызывать.
Если не ошибоюсь, он там с сигнал-слотовым механизмом и EventLoop как-то завязан.
QDroid - Среда исполнения и фреймворк для QtScript.
OTPD - Открытые драйвера промышленных принтеров чеков и этикеток (кроссплатформенная подсистема печати).
Спасибо сказали:
Doublespace
Сообщения: 275
ОС: Debian Lenny,Squeeze,Centos

Re: Быстрый обмен данными через COM-порт

Сообщение Doublespace »

Denjs писал(а):
07.09.2010 16:53
Сдается мне нужно было если не паузу (sleep) - то какойнибудь QApplication::ProcessMessages() вызывать.
Если не ошибоюсь, он там с сигнал-слотовым механизмом и EventLoop как-то завязан.

Не, это все не помогало, без паузы мертво вешалось при вызове Read, bytesAvailable и т.п. Читался ответ модема после отправки на него AT различных форм.
Спасибо сказали:
v2e
Сообщения: 50
ОС: GGL (Gentoo GNU/Linux)

Re: Быстрый обмен данными через COM-порт

Сообщение v2e »

К сожалению на вышеописанном проблемы с быстрым обменом данными через COM-порт не закончились, и я вынужден снова поднимать эту тему.

Сейчас хотя связь внешнего прибора с компьютером через COM-порт работает достаточно надёжно, но возникла проблема корректной обработки получаемых данных. Задача стоит, как я раньше отмечал, в том, чтобы производить замеры некоторой величины (в данном случае - напряжения) строго через промежутки в 1 мс. Для этого я воспользовался режимом реального времени обычного ядра "Linux":

Код: Выделить всё

  struct sched_param scheduler_parameters; // создаём структуру для хранения параметров планировщика задач
  sched_getparam(0, &scheduler_parameters); // получаем текущие параметры планировщика
  scheduler_parameters.sched_priority = 1; // устанавливаем приоритет процесса в списке задач реального времени
  sched_setscheduler(0, SCHED_FIFO, &scheduler_parameters); // передаём ядру выбранные параметры планировщика, устанавливая приоритет реального времени

Насколько я понимаю, других задач реального времени в системе нет, поэтому моя программа должна получать ровно столько времени, сколько требует. По началу программа моя была организована так, что запрос напряженя от внешнего прибора происходил быстрее 1мс, а оставшееся до миллисекунды время программа "добирала" простыми запросами текущего времени. Однако, в такой ситуации система "замораживалась" до завершения работы программы. Т.е. отклика на устройства ввода просто не было. Оно и понятно - режим реального времени, видимо, работает.
В принципе, меня это не очень беспокоит. Я запрограммировал её на работу в течение 10 секунд и выходе по истечении этого времени.
При этом программа постоянно записывает измеренное напряжение в файл. И вот возникла некая странность: со временем начинают набегать лишние микросекунды

Код: Выделить всё

  1000     22.5    -0.25
  2000     15.0    -0.75
  3000     20.0    -0.25
  4000     20.0    -0.25
  5000     25.0    -0.75
  6000     20.0    -0.75
  7000     22.5    -0.25
  8000     20.0    -0.50
  9000     15.0    -0.25
 10001     20.0    -0.75
 11001     15.0    -0.75
 12001     22.5    -0.25
 13001     15.0    -0.50
 14001     22.5    -0.75
 15001     20.0    -0.75
 16001     15.0    -0.75
 17001     20.0    -0.50
 18001     17.5    -0.25
 19001     22.5    -0.75
 20002     15.0    -0.75
 21002     22.5    -0.50
 22002     20.0    -0.25
 23002     15.0    -0.25
 24002     20.0    -0.75
 25002     25.0    -0.50
 26002     20.0    -0.50
 27002     22.5    -0.75
 28002     20.0    -0.75
 29002     15.0    -0.75
 30002     20.0    -0.50
 . . .
 9999103     25.0    -5.75
 10000103     20.0    -5.75
 10001103     25.0    -5.25

Я никак не могу понять, отчего они набегают. Поначалу я думал, что система пытается всё-таки время от времени выполнить какие-то другие небольшие задачи (возможно, свои внутренние нужды), которые и приводят к периодическому "выскакиванию" одной или нескольких микросекунд. Чтобы проверить эту догадку, я ввёл в алгоритм микросны на время ожидания ответа от прибора

Код: Выделить всё

while ((inb(0x3fd) & 1) == 0) usleep(50);

Это существенно улучшило отклик системы на устройства ввода во время работы моей программы (хотя бы реагирует на Ctrl+C), но лишние микросекунды всё равно остались.

Может быть, у кого-то есть какие-нибудь догадки или даже достоверная информация на этот счёт?
Спасибо.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Быстрый обмен данными через COM-порт

Сообщение eddy »

Засекайте не интервалы времени, а абсолютное время с момента запуска программы. Тогда таких проблем с округлениями у вас не возникнет.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали: