Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.71/56: Рейтинг темы: голосов - 56, средняя оценка - 4.71
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712

И снова работа с COM портом

16.11.2016, 14:03. Показов 12136. Ответов 67
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую всех. Уже измучился и измаялся весь пытаясь написать функцию. Помогите, пожалуйста...

Описание задачи
Создается программа для работы с прибором. Соединение с прибором осуществляется посредством преобразователей, которые при подключении к компьютеру создают виртуальный COM порт. Преобразователь может подключаться к прибору посредством проводного (RS-485) или беспроводного (инфракрасный канал) соединения. Прибор всегда является ведущим, то есть информацию выдает только по запросу от компьютера (получил корректный запрос - выдал ответ). Целостность запросов и ответов определяется циклическим избыточным кодом в конце запроса или ответа.

Текущая реализация
На данный момент я создал класс для работы с прибором. Экземпляр этого класса будет создаваться и работать в отдельном потоке. В классе будут реализованы конкретные функции для работы с прибором (например - прочитать серийный номер прибора). Каждая из этих функций подготавливает соответствующий запрос прибору и вызывает внутреннюю функцию обмена данными SwapData. Указанная функция, по сути, выполняет основную работу класса: отправляет созданный запрос в COM порт и получает ответ из COM порта. Именно данную функцию я не могу написать. Начало функции SwapData выглядит примерно так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int SwapData()
{
 // COMHandle - хендл открытого COM порта
 // Data - вектор байт для запроса и ответа
 // eCOM... - константы ошибок обмена
 DWORD dw;
 
 /* Очистка буферов и очередей COM порта */
 if(!PurgeComm(COMHandle, 0x0F)) return eCOMPurge;                              // Не удается очистить буферы COM порта: возвращаю ошибку
 
 /* Отправка данных в COM порт */
 if(!WriteFile(COMHandle, &Data.front(), Data.size(), &dw, NULL) ||             // Не удается отправить данные в COM порт или
     dw != Data.size()) return eCOMWrite;                                       // отправлены не все данные: возвращаю ошибку
 
 /* Чтение данных из COM порта */
}
К приведенной части кода функции претензий нет: буферы очищаются, запрос отправляется (при этом функция WriteFile ждет пока не отправятся все данные, ибо синхронный режим). Проблема возникает с приемом ответа.

Описание проблемы
Прием ответа от прибора сопряжен с несколькими трудностями. Во первых, ответ необходимо принять максимально быстро. То есть, не должно быть простоев в работе функции SwapData. Во вторых, на один и тот же запрос прибор может ответить разным количеством байт (либо вообще не ответить). Это связано с тем, что прибор может получить некорректный запрос (например, ошибка при передаче). Тогда он, скорее всего, вообще не ответит. Так же в каком-то конкретном приборе может быть отключена какая-то функция и прибор на запрос, связанный с этой функцией, выдаст не ожидаемое количество байт, а другое, которое сигнализирует об ошибке. В связи со всем этим появилась попытка решения задачи приема данных.

Попытка реализации чтения данных
В нижеприведенном коде я реализовал алгоритм, когдаПривожу код, который отвечает за прием данных:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 // COMHandle - хендл открытого COM порта
 // COMSpeed - скорость COM порта в бит/с
 COMSTATE cs;
 DWORD dw;
 
 /* Цикл ожидания ответа от прибора */
 for(DWORD in = 0, vl = 0, st = GetTickCount();;)
  {
   /* Останавливаю программу на время приема одного байта */
   Sleep(10000 / COMSpeed);
 
   /*  В буфер COM порта поступили новые данные */
   if(ClearCommError(COMHandle, &dw, &cs) && !dw && cs.cbInQue > in)
    {
     in = cs.cbInQue; /* Сохраняю количество данных в буфере COM порта */
     vl = 0; /* Обнуляю количество "пустых циклов" (когда данные не поступили) */
     continue;
    }
 
   /* Прерываю цикл ожидания ответа от прибора если:
      - в буфере COM порта нет данных и время ожидания превысило 3 секунды;
      - в буфере COM порта есть данные и было более одного "пустого цикла" */
   if((!in && ((GetTickCount() - st) > 3000)) || (in && ++vl > 1)) break;
  }
 
 /* Выполняю чтение данных из буфера COM порта */
 if(!cs.cbInQue) return eNotData;
 Data.resize(cs.cbInQue);
 if(!ReadFile(COMHandle, &Data.front(), Data.size(), &dw, NULL) ||
     dw != Data.size())) return eCOMRead;
Данный код отлично работает на скорости 300 бит/с, но на скорости 9600 бит/с цикл приема завершается до приема всех данных.

Помогите советом как реализовать прием данных максимально быстро и полно.
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
16.11.2016, 14:03
Ответы с готовыми решениями:

Работа с COM портом
по COM порту через Agilen подключается вольтметр с адресом 1. необходимо "прозвонить" все порты и автоматически сделать рабочим тот,...

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

Работа с COM-портом
Подскажите, какие компоненты нужны для работы с ком-портами? а именно (хотя бы для начала) отправка шестнадцатиричного кода на порт, к...

67
45 / 44 / 1
Регистрация: 11.07.2012
Сообщений: 1,024
19.11.2016, 07:18
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от vxg Посмотреть сообщение
В тех настройках UART что я видел максимум 16 байт
Да я пока просто разбираюсь с теорией, в том числе и UART ПК по книгам, просто нашел на форуме тему подходящую, думаю параллельно с темой мне объяснят умные люди что есть что. Ну вот пишут что в UART 16950 буфер FIFO для передачи блоков данных у них - 512 байт, а эти микросхемы в ПК ставятся с 1990х годов. Может мы про разные UART говорим , вы про МК, а я про те что стоят на материнской плате компьютера. Ну может я что то не так понял, тогда пожалуйста поясните?

Добавлено через 8 минут
Цитата Сообщение от d7d1cd Посмотреть сообщение
если Вы не читали всю эту тему, то повторю цитату из протокола обмена:
Мне кажется не правильно анализировать данные по тайм ауту в конце передачи, анализом проще заниматься по протоколу обмена, например нулевой бит регистра LSR (база+5) в состоянии 1, сообщает, что данные поступили или в регистр RBR или в буфер FIFO (если он используется при передаче данных)) таким образом можно начать передавать данные по одному байту и анализировать по протоколу обмена в каком именно месте происходит ошибка ( выше я писал как можно проверить еще и ошибки передачи данных), потом количество байт в пачке передачи данных можно увеличивать и снова анализировать ошибку. Проблема может быть любой, просто ее нужно определить, аналогично тому как мы проверяем код в отладчике в пошаговом режиме.
0
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
19.11.2016, 08:10
седьмой, Avazart, протокол ТС РЕАЛЬНО не позволяет различить ответ при ошибке от ответа при успехе. УВЫ. Поэтому такие вот загоны
2
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.11.2016, 09:41  [ТС]
Avazart, спасибо за пример. Так как с асинхронным режимом не работал, то мне надо немного времени чтобы разобраться. Но параллельно с этим у меня к Вам вопрос. Почему Вы опять ругаете за использование синхронного режима? Если ранее причину я видел в использовании Sleep-ов и циклов, то сейчас этого нет. Функции WriteFile и ReadFile работают по настроенным таймаутам и, как показал эксперимент, работают правильно без лишних задержек. Почему синхронный режим deprecated?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
19.11.2016, 14:41
Цитата Сообщение от vxg Посмотреть сообщение
протокол ТС РЕАЛЬНО не позволяет различить ответ при ошибке от ответа при успехе. УВЫ. Поэтому такие вот загоны
Ну тут можно только посочувствовать и предложить предложить заменить/перепрошить устройство.

Цитата Сообщение от d7d1cd Посмотреть сообщение
Почему Вы опять ругаете за использование синхронного режима?
Я не всматривался особо в код, ничего против не имею, но могу сказать что скорее всего будет проблема с прерыванием во время чтения.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.11.2016, 15:44  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Ну тут можно только посочувствовать и предложить предложить заменить/перепрошить устройство.
Устройство массового производства, которое продается в России и нескольких странах СНГ в огромных количествах. Так что изменение протокола обмена на уровне прошивки нереально.

Цитата Сообщение от Avazart Посмотреть сообщение
Я не всматривался особо в код, ничего против не имею, но могу сказать что скорее всего будет проблема с прерыванием во время чтения.
Вы имеете ввиду, будет проблема прервать выполнение функции ReadFile если прибор не ответит и в порт не придет ни одного байта?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
19.11.2016, 15:49
А что за устройство такое? И кто производит такое?
Цитата Сообщение от d7d1cd Посмотреть сообщение
Вы имеете ввиду, будет проблема прервать выполнение функции ReadFile если прибор не ответит и в порт не придет ни одного байта?
Имею ввиду что нельзя будет закрыть программу во время чтения, пока не выйдет таймаут.
Хотя с таким маленьким таймаутом это вовсе будет не заметной задержкой.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.11.2016, 16:00  [ТС]
Avazart, возможно ли отправить и принять данные асинхронно в рамках одной функции и без создания потоков?
C++
1
2
3
4
5
6
// Вектор Data содержит запрос
// COM порт уже открыт в асинхронном режиме
 
/* В функции SwapData данные из массива Data отправляются в COM порт и
   в этот же массив помещается ответ, прочитанный из COM порта */
int result = SwapData(Data);
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
19.11.2016, 17:28
Без подвисания интерфейса- нет.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.11.2016, 19:12  [ТС]
Цитата Сообщение от Avazart Посмотреть сообщение
Без подвисания интерфейса- нет.
У меня функции работы с COM портом будут "обернуты" в класс. Экземпляр этого класса будет создаваться и работать в отдельном потоке. Поэтому подвисания интерфейса исключены.
В связи с этим уточнением снова задаю тот же вопрос: возможно ли отправить и принять данные асинхронно в рамках одной функции и без создания потоков?
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
19.11.2016, 19:55
Так с потоком или без?

Цитата Сообщение от d7d1cd Посмотреть сообщение
возможно ли отправить и принять данные асинхронно в рамках одной функции и без создания потоков?
Непонятно, что вы имеете ввиду? Зачем пихать прием и передачу в одну функцию?

Обычно передача и прием чередуются, т.е. по принципу запрос-ответ.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.11.2016, 20:51  [ТС]
Попробую снова объяснить что я хочу реализовать, хотя в первом посте такая попытка была. Буду объяснять упрощенно, главной сути это не меняет.
В главном окне программы есть кнопка для чтения параметров из прибора. При нажатии на эту кнопку создается поток, а так же окно процесса чтения, которое тут же выводится в модальном режиме. Поток при создании начинает сразу выполняться. В первую очередь он создает объект класса, который содержит функции для получения информации от прибора. С помощью этого объекта поток открывает COM порт и настраивает его. Далее поток начинает вызывать функции, которые получают от прибора нужную информацию.
При вызове такой функции она формирует запрос для прибора, вызывает внутреннюю функцию класса SwapData, которая отправляет запрос в прибор и получает ответ, и возвращает результат ответа от прибора (или возвращает ошибку обмена с прибором). Во всех функциях класса, которые получают информацию от прибора, есть функция SwapData. После подготовки запроса его надо отправит в прибор и получить ответ. После отправки запроса и до получения ответа от прибора делать ничего не надо. Именно поэтому передача и прием находятся в одной функции.
Экземпляр класса для работы с прибором создается и работает в потоке. Но сам он потоков не создает.

Добавлено через 42 секунды
Цитата Сообщение от Avazart Посмотреть сообщение
Обычно передача и прием чередуются, т.е. по принципу запрос-ответ.
Функция SwapData именно это и делает.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
19.11.2016, 21:17
Я нифига не понял. Я не знаю такой ф-ции, можете кинуть ссылку на MSDN ?
0
Модератор
 Аватар для vxg
3409 / 2180 / 354
Регистрация: 13.01.2012
Сообщений: 8,457
20.11.2016, 09:48
d7d1cd, все будет работать в одной функции - и передача и прием. лагов интерфейса не будет если этот обмен будет не в потоке UI. хотя, если речь идет об однократном запросе-приеме с малыми тайм-аутами то лагов не будет заметно даже если вы все это сделаете в UI
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
20.11.2016, 17:08  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
d7d1cd, все будет работать в одной функции - и передача и прием. лагов интерфейса не будет если этот обмен будет не в потоке UI. хотя, если речь идет об однократном запросе-приеме с малыми тайм-аутами то лагов не будет заметно даже если вы все это сделаете в UI
vxg, я это понимаю. Просто хотел Avazart-у и всем показать как я реализовываю свою программу. Сделаю это завтра-послезавтра. Запрос будет не однократный, поэтому и делаю дополнительный поток. И еще: если у меня передача и прием будут в одной функции и с таймаутами, то различия в эффективности я не вижу. Только в синхронном режиме реализовать все намного проще.
0
 Аватар для ITDeveloper
86 / 86 / 6
Регистрация: 14.01.2011
Сообщений: 265
21.11.2016, 06:46
Цитата Сообщение от vxg Посмотреть сообщение
протокол ТС РЕАЛЬНО не позволяет различить ответ при ошибке от ответа при успехе
Как это? По контрольной сумме можно определить мусор пришел или корректные данные!
Цитата Сообщение от d7d1cd Посмотреть сообщение
Просто хотел Avazart-у и всем показать как я реализовываю свою программу
Цитата Сообщение от d7d1cd Посмотреть сообщение
И еще: если у меня передача и прием будут в одной функции и с таймаутами, то различия в эффективности я не вижу
Вы разрабатываете класс для решения вашей задачи! То есть, на сколько я понимаю, хотите написать хорошую универсальную программу для решения подобных задач в будующем! Это все хорошо! Но при вашем выборе метода решения сделать универсальную вещь не получится! Представьте что начнется при вашей реализации(использование синхронного режима и парсинг данных по таймаутам), когда будет подключено более одного устройства!
Напишите, что это хоть за устройство такое)))
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
21.11.2016, 08:19  [ТС]
Цитата Сообщение от ITDeveloper Посмотреть сообщение
По контрольной сумме можно определить мусор пришел или корректные данные!
Корректность да, а конец сообщения нет. Почитайте тут и тут.

Цитата Сообщение от ITDeveloper Посмотреть сообщение
То есть, на сколько я понимаю, хотите написать хорошую универсальную программу для решения подобных задач в будующем!
Совершенно верно.

Цитата Сообщение от ITDeveloper Посмотреть сообщение
Представьте что начнется при вашей реализации(использование синхронного режима и парсинг данных по таймаутам), когда будет подключено более одного устройства!
Может я чего-то не понимаю, но не вижу проблем. В этом случае для каждого устройства будет создан отдельный экземпляр класса и, естественно, каждое устройство будет работать через свой COM порт.
0
 Аватар для ITDeveloper
86 / 86 / 6
Регистрация: 14.01.2011
Сообщений: 265
21.11.2016, 08:32
Цитата Сообщение от d7d1cd Посмотреть сообщение
каждое устройство будет работать через свой COM порт.
А зачем? Если будет 100 устройств, то вам понадобится 100 com- портов. Где же их столько взять то. Даже если у вас там виртуальные порты, это надо будет 100 конвертеров подключать (мощности шины usb не хватит запитать все это дело)))))))). Можно ведь просто все устройства на один конвертер посадить(один com порт)! Modbus это поддерживает!
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
21.11.2016, 08:41  [ТС]
ITDeveloper, согласен. В моем случае возможно на один COM порт (точнее на один преобразователь) повесить даже более 100 устройств. COM порт будет при этом один. Только в этом случае разве можно одновременно отправить запросы более чем к одному устройству? COM порт, на сколько я знаю, передает данные последовательно бит за битом. Одновременно данные передавать не получится, одновременно работать более чем с одним устройством не получится.
0
 Аватар для ITDeveloper
86 / 86 / 6
Регистрация: 14.01.2011
Сообщений: 265
21.11.2016, 08:57
Во первых: цена вопроса( на каждое устроство не надо будет отдельный преобразователь). Во вторых: когда у вас будут все устройства в одной сети modbus, то вы можете формировать шировещательные запросы ко всем устройствам одной командой. В общем нижний уровень(архитектура) системы значительно упрощается и удешевляется!
Цитата Сообщение от d7d1cd Посмотреть сообщение
Только в этом случае разве можно одновременно отправить запросы более чем к одному устройству
как раз для этого нужны широковещательные запросы.
Конечно здесь не будет полного параллелизма в работе с устройствами, в прочем, как и не будет его даже если вы будете использовать разные com порты. Ваша задача это обычная типовая задача. Для этого существуют стандартные решения. Поверьте не логично и не правильно городить огород из кучи преобразователей! Этот проект в итоге знающие специалисты в конечном счете похоронят и вам придется начинать сначала!
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
21.11.2016, 09:07  [ТС]
ITDeveloper, я признал свою ошибку. Не будет кучи преобразователей. Он будет один.
По поводу широковещательного запроса Вы тоже правы. Вот только на широковещательный запрос прибор не отвечает и отпадает необходимость читать ответ.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
21.11.2016, 09:07
Помогаю со студенческими работами здесь

Работа с COM портом
Здравствуйте! В процессе написания программы работы с устройством, подключенным к ПК через преобразователь интерфейсов RS485 - USB,...

Работа с Com портом
Привет всем! У меня собственно такая ситуация, есть bluetooth и телефон Nokia устанавливаю соединение через виртуальный com порт, мне...

Работа с COM портом в Builder C++ 6.0
Добрый день, уважаемые форумчане. Никогда не спрашивал совета на форумах, но нужна подсказка. Кто располагает временем, буду очень...

Работа с COM портом на С++ Builder 6
Работаю я с GSM модемами, пишу под них программу на C++ Builder 6. Посылаю в модем, через COM порт соответственно, AT команды (строку...

Работа с USB портом.
Доброго всем времени суток! Суть задачи в следующем: Есть устройство (USB принтер этикеток) и им можно управлять при помощи...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru