Передача данных по COM-порту.

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Zer
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 460
Зарегистрирован: 26.09.2003 (Пт) 13:08
Откуда: Нижний Новгород

Передача данных по COM-порту.

Сообщение Zer » 29.10.2003 (Ср) 15:00

Народ! Вот какое дело. Очень нужно пересылать данные через COM-порт, а я не знаю как. Пытался с помощью MSCOMM( Элемент управления такой отрыл) , но чё-то не выходит. Может кто знает, как сделать?
Microsoft DirectX - Маломягкий Прямой Х...
Не откладывай на завтра то, что можно выпить сегодня...

RayShade
Scarmarked
Scarmarked
Аватара пользователя
 
Сообщения: 5511
Зарегистрирован: 02.12.2002 (Пн) 17:11
Откуда: Russia, Saint-Petersburg

Сообщение RayShade » 29.10.2003 (Ср) 15:23

За фразы класса "че-то не выходит" банить буду.

Вопрос должен содержать маскимум полезной информациию Иначе на него нельзя ответить.

kazah_
Обычный пользователь
Обычный пользователь
 
Сообщения: 99
Зарегистрирован: 13.01.2003 (Пн) 18:37
Откуда: Russia

почему.. почему...

Сообщение kazah_ » 31.10.2003 (Пт) 14:37

можешь нажимать ALT+F4 а про пуск забыть
Mr DEN - THE WAY YOU KNOW / Мр. ДЕН - Ваш Путь к Познанию!

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 12.10.2023 (Чт) 12:51

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

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

COM-портом я пользуюсь часто, потому что пишу интерфейсы к создаваемым мною конструкциям на МК, которые подключаю через COM.
Чтобы работать с COM и иметь при этом единственный .exe, не требующий инсталляции, я решил использовать API. Под это был написан модуль, который выкладываю здесь ниже.
Функции модуля предназначены для работы одновременно только с одним портом (т.к. подразумевается, что именно на нем висит устройство, которым управляем). Работаем только с номерами портов 1 - 9. Модуль подробно откомментирован русским текстом.

Нет ни малейшего сомнения, что можно написать куда более красивый и эффективный код, чем мой; но у моего есть одно преимущество - он работает. Причем даже на WIN98 (проверялось!). Его функции можно использовать также и в VBA.
Однако, у этого модуля есть существенное неудобство: функцию чтения порта нужно периодически запускать, чтобы посмотреть - не пришло ли что-нибудь в порт.
Использовать механизм прерываний от COM-порта у меня не получилось.

Подозреваю, что для того, чтобы получать данные с COM-а по прерываниям, нужна квалификация на уровне уважаемого The trick, у которого я и прошу помощи в этом деле.
Если Вам не очень трудно - можно, пожалуйста, действующий пример приема с СОМ-порта по прерываниям через API.
Вложения
commctl2.zip
Модуль для работы с COM-портом через API
(4.05 Кб) Скачиваний: 21

The trick
Постоялец
Постоялец
 
Сообщения: 775
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Передача данных по COM-порту.

Сообщение The trick » 12.10.2023 (Чт) 13:04

Глянь эту тему https://www.cyberforum.ru/visual-basic/ ... 51471.html не это ли тебе нужно?
UA6527P

The trick
Постоялец
Постоялец
 
Сообщения: 775
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Передача данных по COM-порту.

Сообщение The trick » 12.10.2023 (Чт) 13:17

Вообще такие вещи правильнее делать через OVERLAPPED-IO. Я бы вообще применил IOCP, но тут придется работать с потоками, что мало кто любит делать на vb.
UA6527P

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 12.10.2023 (Чт) 13:26

Киберфорум - да, интересное.
Но все ссылки там (кроме Вашего блога) умерли, скачать не удалось ни одного исходника :(

Касательно же потоков и им подобной высокой материи - сам я едва ли справлюсь((((((

Может быть можно малой кровью мой модуль модифицировать? Там BarDCB уже проинициализирована, имя порта есть, отправка данных работает, к ней нету претензий.
Только прием переделать... (Сильно большую глупость сморозил? :oops: )

The trick
Постоялец
Постоялец
 
Сообщения: 775
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Передача данных по COM-порту.

Сообщение The trick » 12.10.2023 (Чт) 13:37

viewtopic.php?f=28&t=46826 вот этот класс.

Открывай порт через CreateFile.
Создавай событие CreateEvent
Заполняй в структуре OVERLAPPED поле hEvent.
Делай ReadFile/WriteFile передавая структуру OVERLAPPED последним параметром.
Запускай бесконечный цикл с WaitForSingleObject с таймаутом и в теле вызывай DoEvents.
При установке в сигнальное состояние эвента, вызывай GetOverlappedResult для получения статуса


Только вместо бесконечного цикла, передаешь hEvent в vbWaitForSingleObject. Когда нужное количество байт считается/произойдет ошибка класс сгенерирует событие где и узнать статус через GetOverlappedResult. Без класса все тоже самое только статус нужно периодически проверять через hEvent/GetOverlappedResult.
UA6527P

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 12.10.2023 (Чт) 13:47

Не думаю, что могу этим гордиться, - но я с трудом понимаю даже буковки, написанные Вами...
Можно рабочий пример кода?

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 12.10.2023 (Чт) 13:51

Нету смысла периодически проверять какой-то статус. Я точно так же могу периодически проверять буфер - и всё работает.

Смысл в том, чтобы как только пришел байт в порт - автоматически вызывалась бы подпрограмма чтения, как это делает MSCOMM.
(Для этого объект нужен, да? А как его сделать?)
Последний раз редактировалось серверянин 12.10.2023 (Чт) 13:56, всего редактировалось 1 раз.

The trick
Постоялец
Постоялец
 
Сообщения: 775
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Передача данных по COM-порту.

Сообщение The trick » 12.10.2023 (Чт) 13:55

Ну с классом CTrickWait можно через события так сделать. Давай я вечером гляну как там в MSCOMM это дело реализовано, скорее всего также.
UA6527P

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 12.10.2023 (Чт) 13:57

ОК! Буду премного благодарен!

The trick
Постоялец
Постоялец
 
Сообщения: 775
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Передача данных по COM-порту.

Сообщение The trick » 12.10.2023 (Чт) 19:47

серверянин писал(а):Смысл в том, чтобы как только пришел байт в порт - автоматически вызывалась бы подпрограмма чтения, как это делает MSCOMM.
(Для этого объект нужен, да? А как его сделать?)

Ну юзай WaitCommEvent, а в экземпляр класса CTrickWait передавай hEvent от OVERLAPPED структуры передаваемой в качестве параметра lpOverlapped. В SetCommMask должен быть установлен бит EV_RXCHAR. COM порт должен быть открыт с флагом FILE_FLAG_OVERLAPPED. В этом случае будет генерировать событие при получении символа по COM порту.
UA6527P

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 13.10.2023 (Пт) 12:23

Плиииииз, пример действующего кода.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Передача данных по COM-порту.

Сообщение Хакер » 13.10.2023 (Пт) 14:44

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

Блин, если вам так противна регистрация (хотя это вещь безусловно хорошая и правильная), почему бы не пользоваться registration-free подходом через манифест и SxS-перенаправление вызова CoCreateInstance/CoCreateClassFactory?

Просто кладём манифест-файл рядом с exe-файлом и не надо ничего регистрировать. Или даже не кладём рядом, а зашиваем в ресурсы.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 13.10.2023 (Пт) 15:33

Хакер писал(а): почему бы не пользоваться registration-free подходом через манифест и SxS-перенаправление вызова CoCreateInstance/CoCreateClassFactory?
Потому что никто не научил. Сорь, но впервые слышу. Где можно толково и внятно прочитать про это (на русском языке)?

The trick
Постоялец
Постоялец
 
Сообщения: 775
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Передача данных по COM-порту.

Сообщение The trick » 13.10.2023 (Пт) 20:27

серверянин писал(а):Потому что никто не научил. Сорь, но впервые слышу. Где можно толково и внятно прочитать про это (на русском языке)?

Глянь эту тулзу - автоматом создает манифест. https://github.com/wqweto/UMMM
UA6527P

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 14.10.2023 (Сб) 1:07

Глянул. Интересно.
Прочитал через Гуглотранслятор. Не понял ничего.
Я слыхал про это только вот такое:
Царь испугался,
Издал манифест:
"Мертвым - свободу,
Живых - под арест"

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 30.10.2023 (Пн) 13:56

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

Современный COM пользуется в основном тремя проводами: TxD -передающая линия, RxD -приемная линия, и GND -общий, "земля", обыкновенно соединенный с корпусом компа (часто сокращают до Tx, Rx, G). На компьютерном 9-контактном разъеме они выведены на следующие пины:
Rx - 2
Tx - 3
G - 5
В древние времена использовались еще 25-контактные разъемы, но сейчас их уже очень давно не встречается.
Есть еще служебные контакты для передачи сигналов готовности, но в абсолютном большинстве случаев обходятся без них. Мои подпрограммы тоже не используют эти режимы, так что спокойно довольствуемся тремя проводами.

Выводов питания (12V или 5V) на COM-разъеме нет.

Напряжение сигналов на COM-порте считается +-12V, но на деле бывает приблизительно 8. Как правило, компьютерный COM-порт исправно принимает даже 5-вольтовые ТТЛ-сигналы.

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

Изображение

Обратите внимание, что активный уровень - низкий (-12V).
То, что тут в частности описано, называется стандартом RS-232.

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

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

Каналы приема и передачи могут работать одновременно. Так что если на COM-порт поставить перемычку между Tx и Rx, то порт начнет принимать всё то, что сам же передает. Этот фокус часто используется для проверки исправности работы порта или отладки программ.

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 30.10.2023 (Пн) 13:58

Настройки COM-порта.
Если посмотреть COM-порт в Диспетчере устройств Виндовс или в Панели управления, можно увидеть настройки, но Visual Basic, на них плюет; ваша программа обязана сама настроить порт, чтобы с ним работать.
В моем модуле (выложенном выше в теме) для этого есть функция initCOM. У нее пять параметров, все они - целые числа.
Первое число - номер COM-а. В Виндовс может быть много COM-ов, но функция умеет обращаться только к первым девяти. Обычно этого достаточно, потому что на компе как правило только два аппаратных порта (если вообще есть), а виртуальные COM, которые создаются различными USB-переходниками можно переименовать в желаемый номер через Панель управления или Диспетчер устройств.
Примечание.
Бывает, что при попытке назначить виртуальному COM новый номер, Виндовс сообщает, что номер уже используется. Но если это не 1 или 2, то можно всё равно назначить, и будет исправно работать. Если, конечно, реально не используется в это же самое время другим переходником или какой-нибудь вашей программой.

Итак, первое число функции initCOM -это номер порта (от 1 до 9), с которым дальше будет работать программа.

Второй параметр - это скорость приемопередачи. Это число не произвольное. Существует стандартный набор скоростей. Вот какие они могут быть:
50
110
150
300
600
1200
1800
2000
2400
3600
4800
7200
9600
19200
38400
115200
Выбирайте именно ту скорость, которую хочет присоединенное к порту устройство.
Чаще всего применяется 9600.
(Я работаю с микроконтроллерами PIC и использую с ними 2400.)
Скорость - одна и та же на прием и на передачу.

Третий параметр - это количество битов в посылке. Ставьте 8.
(В древние времена, когда были телетайпы, они обменивались по 5 бит, но такого с прошлого века уже нигде нет. А стандарт остался.)

Четвертый параметр определяет, нужно ли проверять четность.
Проверка четности - это страховка от ошибок приема. Следует применять, если используются ненадежные линии связи с помехами и искажением импульсов.
Режим проверки добавляет в посылку дополнительный бит, с которым сверяется сумма битов данных. Если данные нарушены во время передачи, то образуется несовпадение, по которому принимающая программа может знать, что пришедший байт - с глюком, и как-то это обработать (например запросить передачу повторно). Исправление ошибок не происходит автоматически, а только их обнаружение.
Если Вы используете для подсоединения нормальный провод длиной в единицы метров, то с ним не предвидится таких проблем и данный параметр можно ставить 0. Означает режим без проверки, бит четности не добавляется.

Пятый, последний, параметр - количество стоповых бит. Их может быть один, полтора, или два. Такую дичь, как полтора бита, моя функция не переваривает. Используйте 1, как все здравые люди.

Примечание.
Во времена DOS-бейсиков (QBasic) COM-порт можно было открыть директивой OPEN при этом имя порта и режим четности обозначались буквами. Отсутствие четности задавалось литерой N, так что стандартный режим выглядел как "8N1".
В VB6, к сожалению, OPEN так больше не работает.
Последний раз редактировалось серверянин 30.10.2023 (Пн) 16:40, всего редактировалось 1 раз.

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 30.10.2023 (Пн) 14:02

Передача данных.
Следует понимать, что COM-порт только передает байты, преобразуя их из параллельного представления в последовательное и обратно. При это он не знает, что именно эти байты означают: это какие-нибудь команды, или части чисел, или точки какого-то изображения.
Знают это отправляющая и принимающая программы, котоые этим портом пользуются.
Так что, чтобы отправить какую-нибудь команду например на модем, Вы должны знать заранее, какие команды принимает этот модем, и что собою они должны представлять.
С точки зрения программы, байт проще всего отправлять в символьном виде, потому что один байт = одна литера (а в десятичном представлении - это до трех знаков, напр. 255).
Поэтому функции передачи и приема в моем модуле работают в строковом формате.
Последовательность отправляемых и принимаемых байтов оформляются как строки букв.
Соответствие буквы числу определяется таблицей ASCII. Но Вам не обязательно знать эту таблицу. В VB существуют стандартные функции преобразования буквы в число и обратно, работающие по этой таблице. Их можно применять для преобразования принятых/отправляемых байтов.
Функция Asc преобразует литеру в число, а Chr$ -число в литеру. Прям нумерология какая-то)))))))
Аргументом Chr$ должно быть целое число от 0 до 255, а аргументом Asc -строка, содержащая литеру. Если это будет строка из многих букв, то в число преобразуется только первая из них.
А что делать, если нужна не первая буква, а откуда-нибудь из середины строки?
На это существует очень удобная функция Mid$. Она выдает буквы из указанного места в строке. У нее три аргумента. Первый - исходная строка. Второй - позиция в строке, откуда надо взять символы. Третий - количество символов, которые надо взять.
Счет символов строки начинается с 1.
Есть еще функция Str$. В отличие от Chr$, она преобразует число не в единую литеру, а в его десятичное написание. Например Str$(128) выдаст строку из четырех знаков: пробел, 1, 2 и 8. А если число отрицательное, то вместо пробела перед ним будет литера "-". Таким образом, Str$ может обрабатывать любые числа, в т.ч. дробные и отрицательные.
Используя эти функции, легко передавать и принимать данные чеез COM-порт.
Функция моего модуля WriteCOM передает строку символов в порт, а ReadCOM -принимает.

серверянин
Новичок
Новичок
 
Сообщения: 28
Зарегистрирован: 19.09.2023 (Вт) 8:00
Откуда: РФ

Re: Передача данных по COM-порту.

Сообщение серверянин » 30.10.2023 (Пн) 14:08

Работа с портом.
Делаем следующим образом.

При запуске программы вызываем initCOM, чтобы настроить выбранный порт. Это достаточно сделать один раз (например в Form_Load).
Если не получилось, напр. нет такого порта, или он уже занят - то функция возвратит строку с сообщением об ошибке, а если всё удачно - то пустую строку.
Это даже можно использовать, чтобы автоматически обнаруживать свободные COM-порты. Я обычно в цикле перебираю все номера от 1 до 9, работу компа это не нарушает.
Сообщение об ошибке дублируется в глобальной переменной COMerr$. (И так поступают и остальные функции модуля.)

После того, как порт настроен, его надо открыть. Для этого используется функция OpenCOM. Аргуметов не имеет, т.к. порт уже настроен.
Открытый порт теперь принадлежит вашей программе, он становится недоступен для других процессов. Вы можете в него писать (отправлять), и читать (принимать).
Приходящие извне в COM-порт байты накапливаются в буфере, поэтому не требуется ловить их каждый в процессе прибытия. Можно немного подождать, а потом прочитать их все.
Прочитанные байты удаляются из буфера.
Функция чтения ReadCOM имеет аргументом количество символов, которое требуется прочитать. Ставьте столько, сколько ожидается получить. Если задать чтение большего количества, то к ошибке это не приведет, но несколько замедлит работу, потому что, прочитав из буфера всё, что там было, функция еще несколько десятков миллисекунд будет ожидать прихода недостающих байтов.
Если буфер пуст изначально, то функция возвратит пустую строку.

Перед завершением работы программы ОБЯЗАТЕЛЬНО(!) следует порт закрыть, вызвав функцию CloseCom. Ей аргументы не требуются. (Если порт уже был закрыт или не открыт - функция не произведет никакого действия.)
Закрытие освобождает порт и делает его снова доступным для других.

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

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

Чтобы избежать этих осложнений, я в некоторых программах поступал так: открывал порт, посылал команду устройству, принимал его ответ, - и сразу же порт закрывал.
А потом делал всякие обработки, в процессе которых программа если вылетала по ошибке - то порт-то был уже закрыт и никаких эксцессов не происходило.

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

Спасибо за внимание.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot и гости: 1

    TopList  
cron