Полная версия этой страницы:
RS232 и медиаплейеры
WEST128
Aug 28 2008, 11:15
Написал программу чтения-записи через COM-порт, и столкнулся с такой интересной особенностью - программа не читает данные с порта до тех пор, пока не запущен какой-нибудь медиаплейер, причем для FooBar2000 требуется, чтобы проигрывалась музыка, как только нажимаю паузу, прием данных тут же отваливается. Стандартный виндовый плейер достаточно просто запустить, и прием данных идет. Не могу предположить, в чем может быть причина столь странного поведения.
А вы "чужой" программой проверяли? ( терминалом например )
Может быть проблема в каких нибудь таймерах? Вы полностью настрайиваете порт, используете SetCommTimeouts?
отдыхать надо
WEST128
Aug 28 2008, 12:12
Проверял я не программой, а осциллографом, так что достоверность 100%. К тому же работает аппартное устройство, которое шлет/принимает данные, тоже гарантированно (проверял тем же осциллографом). Прикол исключительно виндовый какой-то.
Цитата(WEST128 @ Aug 28 2008, 16:12)

Проверял я не программой, а осциллографом, так что достоверность 100%. К тому же работает аппартное устройство, которое шлет/принимает данные, тоже гарантированно (проверял тем же осциллографом). Прикол исключительно виндовый какой-то.
Причем здесь осцилограф?
Я же говорю это только Ваша программа не принимает данные или другие ( терминал например) тоже?
скорее всего вы не полностью делаете инициализацию порта.... или синхронизация хромает. а загруженность системы на это влияет
Причина столь странного поведения в том, что криво сделан прием байтов с порта. Я не знаю что там умудрились намудрить, но скорее всего "додумались" между приёмами каждого байта ставить выдержку по таймеру (обыкновенному, WIN32, через систему сообщений).
Комп видать слабенький. Когда он ложится под нагрузкой, то сообщения таймера идут с нарушениями тайминга и то ли начинают обрабатываться, то ли наоборот, но прогая ваша начинает якобы "работать".
Разумеется под обыкновенной стандартной виндовой терминалкой ничего подобного не будет, так как там сделано всё нормально, ассинхронно и без извратов.
WEST128
Sep 2 2008, 03:49
Комп на CoreQuad 6600 с 2 Гб памяти, нагрузка исчисляется в 1-2 % максимум. Никакого таймера между приемом байтов нет, таймаут только общий. Причем протестил софт на еще одном компе - все работает без каких-либо замудрений, вот и думаю, почему так.
Было подобное. Одна программа работала нормально только в том случае, если запущена ICQ или QIP. Если программу отключить - начинает терять байты. Проявлялось на 2 компьютерах из 8 испытанных. Вылечилось увеличением таймингов.
Но, к слову сказать, программа была написана достаточно коряво.
WEST128
Sep 3 2008, 07:21
Суть программы такова: отсылаем короткий запрос на устройство (5 байт), далее переключается интерфейс RS485 на прием и ждем некоторое время ответа. Потом переключаем интерфейс RS485 на передачу и снова шлем запрос.
Свою проблему "вылечил" увеличением времени задержки в отвечающем устройстве до 18 мс, раньше было 2 мс. Программа стала работать на любом ПК, но решение мне категорически не нравится.
Вот собственно кусок кода, отвечающий за передачу-прием:
while(true)
{
WriteFile(CommHandle, wrbuffer, 3, &BytesWritten, &WriteEx);
ReadFile(CommHandle, rdbuffer, 7, &BytesRead, &ReadEx);
WaitForSingleObject(WriteEx.hEvent, 10);
GetOverlappedResult(CommHandle, &ReadEx, &BytesRead, true))
if (BytesRead == 0)
далее следует разбор на тему принято/не принято и декодируются кадры (если принято)
Sleep(10);
}
все работает в отдельном потоке, таймауты на передачу общий 5 мс, на прием 25мс
Цитата(WEST128 @ Sep 3 2008, 11:21)

WaitForSingleObject(WriteEx.hEvent, 10);
GetOverlappedResult(CommHandle, &ReadEx, &BytesRead, true))
}
все работает в отдельном потоке, таймауты на передачу общий 5 мс, на прием 25мс
смущают эти строчки! зачем два вызова функций? когда можно обойтись только GetOverlappedResult
к тому же если Event создан с bManualReset = false будет глючить!
Цитата
if (BytesRead == 0)
далее следует разбор на тему принято/не принято и декодируются кадры (если принято)
и эти
Вы проводите разбор если байты не считаны?
Ожидания завершения операции overlapped записи нету, результат WaitForSingleObject не анализируется...
Да и в курсе вы, что все задержки Windows для программ прикладного уровня считает с точностью плюс\минус эдак 30 ms запросто?..
PS: функцию SetupComm() используете, буферы какие заданы?
WEST128
Sep 4 2008, 04:29
SysRq WaitForSingleObject(WriteEx.hEvent, 10) как раз и делает ожидание завершения записи. Собственно, время ограничено, и бесконечно ждать я не могу. Однако, судя по тестовому прибору (анализатор кадров самодельный) все кадры на запись ходят нормально. SetupComm используется, само собой, буферы ставлю по 2 кБ.
KRS Попробую убрать WaitForSingleEvent(), может и действительно не нужно, я этой строчкой хотел подождать завершение записи, а потом уже приступить к чтению.
Цитата
к тому же если Event создан с bManualReset = false будет глючить!
- можете пояснить этот момент ? врде в документации написано, что функции WriteFile и ReadFile следует использовать именно с автоматическим сбросом, или я неправильно понял ?
Цитата
Вы проводите разбор если байты не считаны?
- конечно нет, просто я не стал приводить весь код целиком.
goodwin
Sep 4 2008, 05:36
Все вполне объяснимо - интервал стандартного таймера в NT - 10 мс, мультимедийного -1 мс.
При работе winamp в системе задействуется мультимедийный, посему и события обрабатываются оперативнее.
Попробуйте задействовать в своем приложении мультимедийный...
Цитата(WEST128 @ Sep 4 2008, 08:29)

- можете пояснить этот момент ? врде в документации написано, что функции WriteFile и ReadFile следует использовать именно с автоматическим сбросом, или я неправильно понял ?
Дело в том что если event автоматический, то его ждать можно только один раз на событие. Т.е. WaitForSingleObject у вас подождет окончания чтения, потом event сам сбросится.
А GetOverlappedResult - реализован криво. раз event не стоит он считает что результата надо ждать. и все...
Поэтому IMHO лучше там где можно всетаки использовать ручной сброс event. Тогда будет работать и в таком варианте.
Цитата(WEST128 @ Sep 4 2008, 08:29)

SysRq WaitForSingleObject(WriteEx.hEvent, 10) как раз и делает ожидание завершения записи.
Ваша правда, я мимо проглядел!
Можно попробовать переписать через WaitCommEvent...
WEST128
Sep 5 2008, 04:15
goodwin Спасибо за мультимедийный таймер, я даже не знал про его существование .
KRS почему криво, WaitForSingleEvent ждет запись, а GetOverlappedResult - чтение, или я не прав ?
На данный момент проблема решена, всем спасибо за помощь.
А вообще наверно стоило делать аппаратную примочку, чтобы сама опрашивало, будет явно быстрее. Если будет вторая версия, так и предложу заказчику.
Цитата(WEST128 @ Sep 5 2008, 08:15)

KRS почему криво, WaitForSingleEvent ждет запись, а GetOverlappedResult - чтение, или я не прав ?
Да, это я проглядел что event разные.
Но в таком случае IMHO лучше использовать WaitForMultipleObjects
но тогда Event нужен точно ручной ( ато GetOverlappedResult работать не будет)
Цитата(goodwin @ Sep 4 2008, 09:36)

При работе winamp в системе задействуется мультимедийный, посему и события обрабатываются оперативнее.
Глупости какие-то говорите. Мультимедийный таймер и таймер WIN32 работают совершенно не зависимо друг от друга.
Цитата
На данный момент проблема решена, всем спасибо за помощь.
Так в чем все таки был у Вас косяк?
WEST128
Sep 6 2008, 05:54
Мне помогло использование мультимедийного таймера, значит, причина в отсчете времени. Хотя это может быть и не причина, а только следствие, такое уже не раз бывало в моей практике. Сейчас разбираться особо некогда, да и смысла тратить время на СОМ-порт я не вижу, его уже далеко не во всех ПК можно увидеть, преобразователи USB->СОМ - вообще отдельная песня.
Цитата(WEST128 @ Sep 6 2008, 09:54)

Мне помогло использование мультимедийного таймера, значит, причина в отсчете времени.
Значит дело в полудуплексе и переключении с передачи на прием. Ошибка приводила к тому, что ответ принимали неверно.
WEST128
Sep 9 2008, 07:31
Может быть, сейчас просто нет времени выяснять это. Проект сдан, а там пусть мудрят разработчики железа.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.