Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.55/56: Рейтинг темы: голосов - 56, средняя оценка - 4.55
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1

Класс для COM-порта с поддержкой событий

05.09.2014, 11:48. Показов 11679. Ответов 30

Студворк — интернет-сервис помощи студентам
Доброго. Мне нужен класс для работы с COM-портом с поддержкой событий.

У меня есть вариант: Serial Port Communication in Excel (VBA). Я его использую в Excel. Проблема в том, что нужно ручками регулировать время между командой и ответом, чтобы гарантировано принять данные во входной буфер. Хотелось бы иметь событие OnReceive(), которое основано на WaitCommEvent(). Без событийного решения трудно реализовать оптимальный по скорости алгоритм работы с устройствами. Мне нужно с определённой частотой читать данные и желательно получать их по мере заполнения входного буфера нужной посылкой.

Можно ли что-то такое сделать на vb6? Мне не нужны сторонние решения в готовом виде (ActiveX, dll и т.п.). Нужно всё реализовать на макросах в таблице.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
05.09.2014, 11:48
Ответы с готовыми решениями:

Класс для работы со строками (с поддержкой китайских символов)
Всем привет! Необходима помощь по созданию класса на C++ для работы со строками, строки должны поддерживать китайские символы. Заранее...

Календарь событий с заметками и поддержкой файлов
Помогите с курсовой роботой Пользователь на выбранную дату и время может установить произвольную событие. Дополнительный сервис включает...

Кто встречал контрол типа стандартного Line, но с поддержкой событий?
Нужен сабж, чтобы можно было ловить клики на нем.

30
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
18.09.2014, 18:00
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от уни Посмотреть сообщение
Ты даёшь совет как мне красивее и правильнее доставать байты из буфера?
Нет. Я даю правильное, прямое решение твоей проблемы. Кто-нибудь потом также будет мучиться с этим кодом, найдет мой пост и решит проблему. Я совершенно точно знаю почему твой код не работает, а ты не знаешь и еще пытаешься что-то мне доказать. Разве это не глупо?
Цитата Сообщение от уни Посмотреть сообщение
У меня уже всё работает.
Нет, это не будет работать, не нужно дезинформировать людей. Будет работать только когда чтение пройдет внутри ReadFile (вернет не NULL), считай практически никогда; эквивалентно вызову синхронной функции, т.е. эффекта от асинхронности нет никакого. Вот поэтому у тебя и синхронный вызов работает без проблем, а асинхронный не работает.
0
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
18.09.2014, 21:03  [ТС]
Я эффект замеряю статистически как разницу во времени при разных подходах. Монитор показывает дамп обмена по последовательному порту.

У меня есть прибор, который шлёт посылки с частотой 10 Гц без команд. Я должен их гарантировано принять. Код выше, который я нашёл в сети, не имеет прямого метода ожидания приёма, поэтому для гарантированного приёма мне приходилось обходить недостаток функционала. Самый простой способ - добавить задержку в 1-2 интервала между посылками и читать буфер. Это работало, но я не мог достичь скорости 10 Гц из-за искусственных задержек.

Поэтому я пришёл к более сложному методу с флагами и дополнительными winapi-функциями. Написал программу на с++ и сравнил в тех же условиях разницу по времени между запросом и ответом. На картинке выше изображен результат работы с другим прибором, у которого скорость можно задать до 38400 бод и возможно достичь скорости 45 отсчётов/сек.

В текущем приборе тем же методом на скорости 9600 бод задержки были 150 мсек в среднем. Моя программа на c++ уменьшила это число в три раза, плюс даёт больше возможностей по синхронизации. В предыдущей версии для изменения частоты опроса я менял задержку и это приводило к пропускам (системный буфер у меня сбрасывается каждый раз).

The trick, ты вообще на низком уровне с железом работал когда-нибудь? Ты знаешь назначение таймаутов операций чтения байтов? Через сколько буферов проходит байт прежде, чем он от провода придёт ко мне в программу?

У меня такое чувство, что ты никогда не видел как ведётся отладка программы, которая работает с COM-портом. Вот пример лога, который я снял при работе с прибором в командном режиме на скорости 9600 бод (8-N-1):
Code
1
2
3
4
5
6
7
8
9
10
11
12
[13:51:49:199] - Open COM3 port (C:\Cloud\Projects\cpp\Projects\TestSerial\Debug\TestSerial.exe)
 
[13:51:51:407] - Written data
 
41 54 30 32 52                                      AT02R
 
[13:51:51:460] - Read data
 
3c 30 32 52 3d 20 20 20 20 30 2e 30 30 43 30 00     <02R=    0.00C0.
33 44 0d 0a                                         3D..
 
[13:52:09:046] - Close port
Скажи сколько миллисекунд физически длится ответ и почему?

Добавлено через 1 час 32 минуты
Цитата Сообщение от The trick Посмотреть сообщение
Нет, это не будет работать, не нужно дезинформировать людей. Будет работать только когда чтение пройдет внутри ReadFile (вернет не NULL), считай практически никогда; эквивалентно вызову синхронной функции, т.е. эффекта от асинхронности нет никакого. Вот поэтому у тебя и синхронный вызов работает без проблем, а асинхронный не работает.
Будет, не будет. Это смотря какая постановка задачи и что мы имеем практически. Представь, у тебя есть Windows, у которой и запись, и чтение буферизированы. У тебя есть источник посылок, который генерирует их каждые 100 мсек. По ТЗ у конечного пользователя есть только офис с поддержкой макросов. Нужно принять данные и отобразить их графически. Использовать Excel. Есть также источники с протоколом запрос-ответ, желательно иметь минимальные издержки обмена по времени.

Это сильные ограничения, но WinAPI тебе доступен. Далее, ты находишь в сети готовый код, который работает, но не совсем. К примеру, в командном режиме, если ты делаешь так:

1. Сброс буферов записи и чтения Windows.
2. WriteFile
3. ReadFile

то это не работает (программный буфер пустой), а если ты делаешь так:

1. Сброс буферов записи и чтения Windows.
2. WriteFile
3. Sleep(100)
4. ReadFile

то ответ всегда можно считать из приёмного буфера Windows. Можешь с ходу указать в том исходнике почему так?

Вот отсюда все и проблемы. Sleep(100) на самом деле эмпирическая вещь, кроме того есть неучтённые задержки, которые зависят от производительности компа (мы работаем в Excel). Это +/- 20-50 мсек, точно не знаю. А эти задержки на больших скоростях уже сопоставимы с длиной пакетов байт команд. Считать-то мы уже умеем?

Я уж не упоминаю DoEvents, которая там в коде используется для сброса буфера записи в физический порт. Это что-то вообще ненормальное.

Так вот, чтобы понять, почему ReadFile там не ждёт посылки, а сразу возвращает управление, нужно разобраться в инициализации порта, используемом алгоритме и хорошо прочитать MSDN. И совершенно параллельно каким образом тут ReadFile работает с буфером пользователя.
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
18.09.2014, 21:31
Лучший ответ Сообщение было отмечено The trick как решение

Решение

Цитата Сообщение от уни Посмотреть сообщение
The trick, ты вообще на низком уровне с железом работал когда-нибудь?
Работал. Собирал несколько устройств на AVR которые обменивались данными с компьютером по UART.
Цитата Сообщение от уни Посмотреть сообщение
Ты знаешь назначение таймаутов операций чтения байтов?
Зависит от скорости, количества бит (данные, стартовый, стоповый, четность и т.д.), интервала между данными и еще от кучи факторов. Рассчитать можно так:
Visual Basic
1
numChars*bitsOnSymbol/BaudRate + (numChars-1)*Interval
Цитата Сообщение от уни Посмотреть сообщение
Через сколько буферов проходит байт прежде, чем он от провода придёт ко мне в программу?
Как минимум через буфер, задаваемый SetupComm.
Цитата Сообщение от уни Посмотреть сообщение
Скажи сколько миллисекунд физически длится ответ и почему?
При скорости 9600 бод, время передачи 1 байта данных (10 бит в твоем случае) будет составлять ~1042 мкс + интервал между символами (зависит от устройства), умножать на количество байт, в твоем случае 20.
Цитата Сообщение от уни Посмотреть сообщение
Будет, не будет. Это смотря какая постановка задачи и что мы имеем практически. Представь, у тебя есть Windows, у которой и запись, и чтение буферизированы. У тебя есть источник посылок, который генерирует их каждые 100 мсек. По ТЗ у конечного пользователя есть только офис с поддержкой макросов. Нужно принять данные и отобразить их графически. Использовать Excel. Есть также источники с протоколом запрос-ответ, желательно иметь минимальные издержки обмена по времени.
Не вижу связи с проблемой типизации данных в твоем случае. Тип Byte() в Excel'е есть.
Цитата Сообщение от уни Посмотреть сообщение
Так вот, чтобы понять, почему ReadFile там не ждёт посылки, а сразу возвращает управление, нужно разобраться в инициализации порта, используемом алгоритме и хорошо прочитать MSDN. И совершенно параллельно каким образом тут ReadFile работает с буфером пользователя.
Что за бред? Твой вопрос как был поставлен:
Цитата Сообщение от уни Посмотреть сообщение
запрос-ответ происходит (слежу монитором порта), а вот в приёмный буфер данные не записываются, хотя принятое количество байт показывается. Не пойму в чём дело.
Что ты теперь говоришь тут что тебе параллельно каким образом функция работает с буфером? Твоя проблема в том что ты используешь тип String для буфера, и совершенно не понимаешь как это работает. И самое интересное что ты не слушаешь других. Зачем тогда задавать вопрос на форум?
Ты передаешь String по значению - это обозначает автоматическую конвертацию строки из Unicode в Ansi перед вызовом функции, передачи Ansi буфера в функцию и конвертации из Ansi в Unicode буфера при выходе из функции. Это знает любой более-менее разбирающийся программист на VB6. Смотри - у тебя асинхронная запись в буфер, т.е. после выхода из функции данные в буфер будут писаться в него, а у тебя уже этого временного буфера нет (данные пишутся в никуда, хорошо что приложение не вылетает и число прочитанных байт соответствуют истине), а с исходной строкой ничего не происходит, она вообще не участвует в операции. Если ты передашь туда указатель на первый элемент массива - то они будут писаться туда и никуда больше.
И как после такого можно говорить о неважности типа?
0
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
18.09.2014, 22:06  [ТС]
Молодец, приятно увидеть логичные рассуждения. Этот факт я не учитывал, так как не обратил внимания на ByVal по причине уже работающего кода. Мог бы и раньше сделать такое пояснение, оно не очевидное.

Цитата Сообщение от The trick Посмотреть сообщение
При скорости 9600 бод, время передачи 1 байта данных (10 бит в твоем случае) будет составлять ~104 мкс + интервал между символами (зависит от устройства), умножать на количество байт, в твоем случае 20.
Формула правильная, только на порядок в расчётах ошибся. Прикинь, 9600 бит в сек (бод - baud rate - битовая скорость), 10 бит в символе - 960 символов в сек, округлим - 1000 симв в сек - это 1 мсек на символ. Итого, около 20 мсек на ответ.
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
18.09.2014, 22:21
Цитата Сообщение от уни Посмотреть сообщение
Мог бы и раньше сделать такое пояснение, оно не очевидное.
Я тебе явно написал
Цитата Сообщение от The trick Посмотреть сообщение
у тебя в коде на C++ буфер представляет собой массив из 21 элемента типа char (аналог VB6 - byte)
Цитата Сообщение от уни Посмотреть сообщение
Формула правильная, только на порядок в расчётах ошибся.
Это опечатка, невнимательно проверил пост перед отправкой, там не 104 мкс, ~1042 мкс (10/9600), исправил.
0
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
19.09.2014, 10:18  [ТС]
Я имел в виду двойную неявную конвертацию String при использовании WinAPI в vb6. Я к этому не привык. Ни за что бы не догадался о таком подводном камне.

На самом деле меня конечно смутило такое обертывание ReadFile, так как мне удобнее было работать с байтами (в примере выше текстовый протокол, есть ещё бинарный), но это строковое представление в коде сильно завязано и мне просто лень было всё переделывать, считай, писать заново.

Добавлено через 13 минут
Чтобы пока сильно не переделывать, попробую совет отсюда тоже:
И с "ByVal s As String" и "ByRef s As String" передается строка ANSI, только в первом случае передается адрес этой строки (char*), а во втором — адрес адреса (char**). Чтобы VB не преобразовывал строки, их нужно передавать через Long: "ByVal s As Long" и передавать StrPtr(s).
Добавлено через 11 часов 20 минут
Чтобы VB не преобразовывал строки, их нужно передавать через Long: "ByVal s As Long" и передавать StrPtr(s).
Это не заработало в моём случае. Тут тоже такой способ советуют.

Замена на байтовый буфер заработала. Признаю свою ошибку и ограниченность знания внутренней кухни vb6 при работе с WinAPI.
0
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
25.09.2014, 08:43  [ТС]
Получил хорошие результаты с конкретным прибором. Длина команды 4 байта, ответа - 6 байт, скорость - 38400 бод. Получается теоретическое минимальное время между запросами: 10 / 3840 байт/сек ~= 2,6 мс. Практически у меня сейчас получается 180 Гц ~ 5,6 мсек (у меня введена дополнительная задержка между командой и ответом в 1 мсек). Стабильность между запросами пытаюсь поддерживать при помощи QueryPerformanceCounter(), регулируя задержку, которую делаю при помощи Sleep(). Но сам Sleep(), я думаю, не всегда может точно выдержать интервал в несколько мсек, хотя результаты достаточно стабильны: 5-6 мсек между отсчётами.

Зазубрины на графике связаны с ограниченной частотой измерения в самом приборе. Результаты для COM-порта и переходника USB-COM (Moxa) получились практически одинаковыми.

Асинхронный режим работы позволил увеличить частоту опроса с 50 Гц до 180 Гц. Код оформлен в виде макросов для Excel.
Миниатюры
Класс для COM-порта с поддержкой событий  
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
25.09.2014, 08:46
Почему-бы не использовать буфер для сразу нескольких команд?
0
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
25.09.2014, 08:55  [ТС]
Прибор этого не понимает. Я пытался скормить ему через монитор порта посылку из нескольких команд, но он ответил только на одну из них, т.е. у него нет буферизации команд.
0
Модератор
10048 / 3894 / 883
Регистрация: 22.02.2013
Сообщений: 5,847
Записей в блоге: 79
25.09.2014, 08:57
Лучший ответ Сообщение было отмечено The trick как решение

Решение

Цитата Сообщение от уни Посмотреть сообщение
Прибор этого не понимает. Я пытался скормить ему через монитор порта посылку из нескольких команд, но он ответил только на одну из них, т.е. у него нет буферизации команд.
Каково время ответа? Забей буфер так с 0 между командами, чтобы было время для обработки.
1
 Аватар для уни
368 / 146 / 17
Регистрация: 06.03.2010
Сообщений: 327
Записей в блоге: 1
25.09.2014, 09:10  [ТС]
Надо же, это заработало. Мне не пришло такое в голову, спасибо за идею. Я вбил в мониторе 10 байтов нулей между командами (длина ответа 6 байт) и прибор ответил на каждую. Пробовал пока вручную 2 и 3 команды.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
25.09.2014, 09:10
Помогаю со студенческими работами здесь

Класс с поддержкой интерфейса IEnumerable<T>
Имеется некоторый класс: class DoublyLinkedList&lt;T&gt; : IEnumerable&lt;T&gt; {...} Хочу реализовать у него поддержку интерфейса...

Класс длинная арифметика с поддержкой арифметических операций
Кто-нибудь уже писал класс для работы с очень большими числами, с поддержкой операторов +-/*, если да, то дайте, пожалуйста, ссылку на код....

Нужен батник для создания отчета событий и их свойств из журнала событий на локальном компьютере
Пакетный файл, предназначенный для создания отчета событий и их свойств из журнала событий на локальном компьютере. Журналы событий:...

Реализовать хранилище событий, для хранения событий в БД
Доброго дня! Поставлена задача реализовать хранилище событий, для хранения событий в БД) Событие представляет собой обработанную...

Подскажите бесплатный хостинг с поддержкой MySQL баз и с поддержкой внешних подключений к базе данных
Нужен бесплатный хостинг, у которого нет такого прикола как указание IP адреса явно разрешённого для подключения к MySQL базе данных....


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

Или воспользуйтесь поиском по форуму:
31
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru