Открыть com порт как файл
В предыдущем посте было показано как запустить UART на отладочной плате Launchpad для MSP430. Теперь рассмотрим как общаться с платой при помощи средств командной строки Linux. Используется плата с прошивкой из предыдущего поста. Для подробностей - см. под кат
Как известно, все устройства последовательных портов представлены файлами устройств в каталоге /dev.Через эти файлы и происходит общение ОС Linux с внешним устройством на последовательном порту. Чтобы передать что-то на внешнее устройство нужно записать данные в файл устройства, а чтобы считать информацию из устройства --- прочитать данные из файла устройства. Это можно делать при помощи команд cat и echo так же как для обычных файлов на диске. Или внутри программы на С при помощи вызовов ioctl(), read() и write() или библиотеки termios.
Физическим последовательным портам RS232, к которым подключались диалапные модемы на старых компьютерах, соответствуют файлы устройств /dev/ttyS*, начиная с /dev/ttyS0. Виртуальным последовательным портам, которые создаются различными конвертерами USB<->UART соответствуют файлы устройств /dev/ttyUSB* и /dev/ttyACM*. Ядро Linux автоматически разпознаёт подключенное устройство, загружает для него драйвер и создаёт файл устройства. Вручную устанавливать драйвер, как в ОС Windows не требуется. Например, если подключить к USB преобразователь USB<->UART FT232, то создаётся файл устройства /dev/ttyUSB0, с которым можно работать также как и с обычным последовательным портом. На плате Launcpad находится микросхема TUSB3410, которая тоже представляет собой конвертер USB<->UART. Если подключить её к USB, то создаётся файл устройства /dev/ttyACM0. Чтобы общаться с платой нужно что-либо писать/читать с этого файла.
Чтобы пользователь мог читать или писать в файл устройства последовательного порта, его нужно добавить в группу dialout. Иначе работать с последовательным портом сможет только администратор root.
Простейшим приложением с графическим интерфейсом, которое работает с последовательным портом, является CuteCOM. Он обычно уже есть в вашем дистрибутиве Linux. Его можно установить из репозиториев. При помощи CuteCOM мы работали с платой в предыдущем посте. Выглядит CuteCOM вот так:
Работать с ним крайне просто. Указываем нужное устройство, если его нет в списке, то его можно впечатать вручную. Затем указываем скорость и параметры и нажимаем OpenDevice. В окне видим данные, которые пришли от устройства. В поле ввода в нижней части можем печать строку символов, которые предаются на устройство. Чтобы передать данный нажимаем Enter и смотрим ответ устройства в окне.
Теперь рассмотрим как работать с COM-портом из командной строки. Для этого служат три команды: stty, cat и echo.
Команда stty устанавливает параметры и скорость COM-порта. Её формат:
stty <СКОРОСТЬ> -F <УСТРОЙСТВО> <ПАРАМЕТРЫ>
Чтобы установить параметры для платы Launchpad для соединения на скорости 9600 нужно выполнить:
$ stty 9600 -F /dev/ttyACM0 raw -echo
Параметр raw устанавливает, что данные в компьютер передаются байт за байтом так же как приходят в порт без преобразований. Аппаратное управление потоком отключено. Подробнее о том, что включает и выключает raw - см. man stty. Если не включить raw, то скорее всего ничего работать не будет.
Теперь в той же консоли нужно набрать
$ cat /dev/ttyACM0
И можно смотреть данные, которые приходят от платы. Выход - нажать Ctrl+C.
Теперь нажимаем на плате RESET и видим, что в консоди напечатался текст.
Чтобы передать в плату данные, в другой консоли нужно использовать команду echo и перенаправление вывода в файл устройства. Наберём в другой консоли:
В итоге должно получиться так:
Чтобы увидеть 16-ричные коды данных, приходящих от устройства, нужно использовать команду hexdump:
$ cat /dev/ttyACM0|hexdump -C
Получится вот так:
Чтобы иметь вывод данных от устройство на экран и в текстовый файл нужно использовать tee:
Написать программу, управляющую устройством через COM-порт, для MS-DOS не так сложно. С платформой Win32 дело обстоит сложнее. Но только на первый взгляд. Конечно напрямую работать с регистрами портов нельзя, Windows это не позволяет, зато можно не обращать внимания на тонкости различных реализаций (i8251, 16450, 16550A) и не возиться с обработкой прерываний.
Содержание
С последовательными и параллельными портами в Win32 работают как с файлами. Для открытия порта используется функция CreateFile . Эта функция предоставляется Win32 API. Ее прототип выглядит так:
Указатель на строку с именем открываемого или создаваемого файла. Формат этой строки может быть очень «хитрым». В частности можно указывать сетевые имена для доступа к файлам на других компьютерах. Можно открывать логические разделы или физические диски и работать в обход файловой системы.
Последовательные порты имеют имена "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9". Для доступа к портам, чей номер больше 9, необходимо указывать имя порта как "\\.\COMx", где x - номер порта. Например, "\\.\COM72" (в нотации языка C/C++ строка будет выглядеть "\\\\.\\COM72"). Такой синтаксис подходит для любого номера порта. Точно так же они назывались в MS-DOS. Параллельные порты называются «LPT1», «LPT2» и так далее.
Задает тип доступа к файлу. Возможно использование следующих значений:
- 0 Опрос атрибутов устройства без получения доступа к нему.
- GENERIC_READ Файл будет считываться.
- GENERIC_WRITE Файл будет записываться.
- GENERIC_READ|GENERIC_WRITE Файл будет и считываться и записываться.
Задает параметры совместного доступа к файлу. Коммуникационные порты нельзя делать разделяемыми, поэтому данный параметр должен быть равен 0.
Задает атрибуты защиты файла. Поддерживается только в Windows NT. Однако при работе с портами должен в любом случае равняться NULL .
Управляет режимами автосоздания, автоусечения файла и им подобными. Для коммуникационных портов всегда должно задаваться OPEN_EXISTING .
Задает атрибуты создаваемого файла. Также управляет различными режимами обработки. При работе с портом этот параметр должен быть или равным 0 , или FILE_FLAG_OVERLAPPED . Нулевое значение используется при синхронной работе с портом, а FILE_FLAG_OVERLAPPED при асинхронной, или, другими словами, при фоновой обработке ввода/вывода. Подробнее про асинхронный ввод/вывод я расскажу позже.
Задает описатель файла-шаблона. При работе с портами всегда должен быть равен NULL .
При успешном открытии файла, в данном случае порта, функция возвращает дескриптор ( HANDLE ) файла. При ошибке [[| INVALID HANDLE VALUE ]]. Код ошибки можно получитить вызвав функцию [[| GetLastError ]].
Открытый порт должен быть закрыт перед завершением работы программы. В Win32 закрытие объекта по его дескриптору выполняет функция CloseHandle :
При успешном завершении функция возвращает не нулевое значение, при ошибке нуль.
Основные параметры последовательного порта описываются структурой DCB . Временные параметры - структурой COMMTIMEOUTS . Существует еще несколько информационных и управляющих структур, но они используются реже. Настройка порта заключается в заполнении управляющих структур и последующем вызове функций настройки.
Основную информацию содержит структура DCB :
Эта структура содержит почти всю управляющую информацию, которая в реальности располагается в различных регистрах последовательного порта.
Задает длину, в байтах, структуры DCB . Используется для контроля корректности структуры при передаче ее адреса в функции настройки порта.
Скорость передачи данных. Возможно указание следующих констант: CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400, CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400, CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000 . Эти константы соответствуют всем стандартным скоростям обмена. На самом деле, это поле содержит числовое значение скорости передачи, а константы просто являются символическими именами. Поэтому можно указывать, например, и CBR_9600 , и просто 9600 . Однако рекомендуется указывать символические константы, поскольку при компиляции программы проверяется корректность их имен.
Включает двоичный режим обмена. Win32 не поддерживает недвоичный режим, поэтому данное поле всегда должно быть равно 1 , или логической константе TRUE (что предпочтительней). В Windows 3.1, если это поле было равно FALSE , включался текстовый режим обмена. В этом режиме поступивший на вход порта символ, заданный полем EofChar , свидетельствовал о конце принимаемых данных.
Включает режим контроля четности. Если это поле равно TRUE , то выполняется проверка четности, при ошибке, в вызывающую программу, выдается соответствующий код завершения.
Включает режим слежения за сигналом [[| CTS ]]. Если это поле равно [[| TRUE ]] и сигнал [[| CTS ]] сброшен, передача данных приостанавливается до установки сигнала CTS . Это позволяет подключеному к компьютеру прибору приостановить поток передаваемой в него информации, если он не успевает ее обрабатывать.
Включает режим слежения за сигналом [[| DSR ]]. Если это поле равно TRUE и сигнал DSR сброшен, передача данных прекращается до установки сигнала DSR .
Задает режим управления обменом для сигнала [[| DTR ]]. Поле может принимать следующие значения:
Задает чувствительсть коммуникационного драйвера к состоянию линии [[| DSR ]]. Если это поле равно TRUE , то все принимаемые данные игнорируются драйвером (коммуникационный драйвер расположен в операционной системе), за исключением тех, которые принимаются при установленом сигнале DSR .
Задает, прекращается ли передача при переполнении приемного буфера и передаче драйвером символа XoffChar . Если это поле равно TRUE , то передача продолжается, несмотря на то, что приемный буфер содержит более XoffLim символов и близок к переполнению, а драйвер передал символ XoffChar для приостановления потока принимаемых данных. Если поле равно FALSE , то передача не будет продолжена до тех пор, пока в приемном буфере не останется меньше XonLim символов и драйвер не передаст символ XonChar для возобновления потока принимаемых данных. Таким образом это поле вводит некую зависимость между управлением входным и выходным потоками информации.
Задает использование XON/XOFF управления потоком при передаче. Если это поле равно TRUE , то передача останавливается при приеме символа XoffChar , и возобновляется при приеме символа XonChar .
Задает использование XON/XOFF управления потоком при приеме. Если это поле равно TRUE , то драйвер передает символ XoffChar , когда в приемном буфере находится более XoffLim , и XonChar , когда в приемном буфере остается менее XonLim символов.
Указывает на необходимость замены символов с ошибкой четности на символ задаваемый полем ErrorChar . Если это поле равно TRUE , и поле fParity равно TRUE , то выполняется замена.
Определяет действие выполняемое при приеме нулевого байта. Если это поле TRUE , то нулевые байты отбрасываются при передаче.
Задает режим управления потоком для сигнала RTS. Поле может принимать следующие значения:
Задает игнорирование всех операций чтения/записи при возникновении ошибки. Если это поле равно TRUE , драйвер прекращает все операции чтения/записи для порта при возникновении ошибки. Продолжать работать с портом можно будет только после устранения причины ошибки и вызова функции ClearCommError.
Зарезервировано и не используется.
Не используется, должно быть установлено в 0 .
Задает минимальное число символов в приемном буфере перед посылкой символа XON .
Определяет максимальное количество байт в приемном буфере перед посылкой символа XOFF . Максимально допустимое количество байт в буфере вычисляется вычитанием данного значения из размера приемного буфера в байтах.
Определяет число информационных бит в передаваемых и принимаемых байтах. Число информационных бит может быть в диапазоне от 4 до 8 .
Определяет выбор схемы контроля четности. Данное поле должно содержать одно из следующих значений:
Задает количество стоповых бит. Поле может принимать следующие значения:
Задает символ XON используемый как для приема, так и для передачи. Обычно 0x11 ( 17 ).
Задает символ XOFF используемый как для приема, так и для передачи. Обычно 0x13 ( 19 ).
Задает символ, использующийся для замены символов с ошибочной четностью.
Задает символ, использующийся для сигнализации о конце данных.
Задает символ, использующийся для сигнализации о событии.
Зарезервировано и не используется.
Если структура DCB содержит конфигурацию для последовательного порта, совместимого с 8250, то к значениям полей ByteSize и StopBits применяются следующие ограничения:
- Количество информационных бит должно быть от 5 до 8 .
- Не допускается использование 5 информационных бит с 2 стоповыми битами, также как 6 , 7 или 8 информационных бит с 1,5 стоповыми битами.
ReadIntervalTimeout - время в миллисекундах, задающее максимальное время, для интервала между поступлением двух символов по линии связи. Если интервал между поступлением каких-либо двух символов будет больше этой величины, операция ReadFile завершается и любые буферизированные данные возвращаются.
Чтобы операция ReadFile немедленно возвращала управление со всеми полученными данными (асинхронный режим) следует задавать следующие значения:
ReadTotalTimeoutMultiplier - Множитель, используемый, чтобы вычислить полный период времени простоя для операций чтения, в миллисекундах. Для каждой операции чтения, это значение умножается на затребованное число байтов, которые читаются.
ReadTotalTimeoutConstant - Константа, используемая, чтобы вычислить полный (максимальный) период времени простоя для операций чтения, в миллисекундах. Для каждой операции чтения, это значение добавляется к произведению члена структуры ReadTotalTimeoutMultiplier и прочитанного числа байтов.
Значение нуля и для члена ReadTotalTimeoutMultiplier, и для члена ReadTotalTimeoutConstant указывает, что полное время простоя не используются для операций чтения.
WriteTotalTimeoutMultiplier - Множитель, используемый, чтобы вычислить полный период времени простоя для операций записи, в миллисекундах. Для каждой операции записи, это значение умножается на число записываемых байтов.
WriteTotalTimeoutConstant - Константа, используемая, чтобы вычислить полный период времени простоя для операций записи, в миллисекундах. Для каждой операции записи, это значение добавляется к произведению члена структуры WriteTotalTimeoutMultiplier и записанного числа байтов.
Значение нуля и для члена WriteTotalTimeoutMultiplier, и для члена WriteTotalTimeoutConstant указывает, что полное время простоя не используются для операций записи.
Вариант 1: (максимальная задержка при чтении и записи = TIMEOUT)
Вариант 2: Инициализация значениями (без задержки при чтении)
Для настройки параметров COM - порта может быть вызвано штатное окно Windows. Вызов осуществляется функцией CommConfigDialog(), которая в качестве параметров принимает имя настраиваемого порта, хендл родительского окна и указатель на структуру COMMCONFIG. Следует отметить, что для корректного вызова окна, структура COMMCONFIG должна быть заполнена значениями заранее. Настройку структуры можно выполнить вручную или при помощи функции GetCommConfig(). Например:
Прием и передача данных для последовательного порта может выполнятся в синхронном или асинхронном режимах. Асинхронный режим позволяет реализовать работу по событиям, в то время как синхронный лишен этой возможности, но является более простым в реализации. Для работы в синхронном режиме, порт должен быть открыт следующим образом:
Предпоследний параметр dwFlagsAndAttributes должен быть равен 0. После успешного открытия порта, данные могут быть считаны или записаны при помощи функций ReadFile() и WriteFile().
Функция ReadFile/WriteFile осуществляет чтение/запись из файла (устройства) начиная с текущей позиции после окончания чтения обновляет указатель в файле.
Недостатком этого способа является то, что вызывая функцию ReadFile(), мы не знаем есть ли данные для чтения. Можно циклически проверять их наличие, но это приводит к дополнительным расходам времени ЦП. Поэтому на практике часто удобней использовать асинхронный режим. Для этого при вызове функции CreateFile() параметр dwFlagsAndAttributes должен быть равен FILE_FLAG_OVERLAPPED.
Далее, необходимо настроить реакцию порта на события при помощи функции SetCommMask() и используя функции WaitCommEvent() и WaitForSingleObject() ожидать событие или тайм аут. Например:
Код для работы с COM-портом. Многострадальный, соответственно относительно простой и понятный, при этом обходит основные подводные камни. Надеюсь, может быть полезен.
вторник, 31 марта 2015 г.
Работа с COM портом из командной строки. Мониторинг
. вот все-таки батники незаслуженно игнорируются любителями высокоуровневых языков, а тем не менее даже на них можно решить задачи по мониторингу не только удаленных хостов, но и мониторинга COM-порта, что под DOS, что под Windows. К примеру, возникла задача реагирования (запуска какого-либо приложения) на приход сигнала на один из пинов, кнопка к примеру (выставить DTR тот же и замкнуть с CTS).
Напомню еще раз распиновку COM-порта:
Нам нужно управлять состоянием устройства ввода-вывода. Одной из таких команд - mode (синтаксис см. по mode /?):
Что мы видим? Видим возможность установки скорости, паритета, служебных пинов, паритета и иже с ними. А что нам даст обращение (mode com1) к конкретному COM-порту? А вот сие даст:
Cостояние пинов и настроек порта. Можем прочитать? Можем. Для этого воспользуемся FIND="параметр" (важно точное указание всех знаков):
@ echo off
mode com1 dtr=on > nul
:m1
mode com1 | find "CTS: ON" > nul
if errorlevel=1 goto m1
if errorlevel=0 start notepad.exe
- "dtr=on" установит единичку на DTR.
- "> nul" - этим мы убираем вывод ответа на экран.
- "errorlevel" - отрабатываем результат выполнения.
Передача в COM-порт
Отослать число в COM порт через ECHO (служит для вывода текста в стандартный поток вывода информации):
Если же вам нужен полный контроль отсылаемых символов (байтов) без лишних нечитаемых и извращением с экранированием символов, то самое верное и простое - создать текстовый файл, записать туда нужный пакет данных в бинарном виде и воспользоваться старым и надежным copy myfile.ext > \\.\com46 . Простенько и со вкусом )))
Прием из COM-порта
4 комментария:
Добрый день.
Подскажите как сделать из командной строки в Windows XP это:
Доброго времени суток. Когда речь о виндах, можно реализовать VBS скриптом (прямо в блокноте) через OLE DynamicWrapperX или X.2, обращаясь прямо к WinAPI функциям (в частности, открыть порт по CreateFile() и дергая EscapeCommFunction() c заданной задержкой).
Полный сабж залил сюда.
Касательно командной строки в Windows XP: штатной задержки sleep в языке сценариев не реализовано, а timeout появился только с висты. Да и то в секундах. Потому как вариант реализации чистого пакетного файла через подсчет сотых долей секунды:
echo %time%
echo Wait 500 ms (n*0.01sec).
for /l %%i in (1,1,8) do (
mode com1 dtr=on > nul
call :sleep 50
mode com1 dtr=off > nul
call :sleep 50
)
echo %time%
pause
exit /b
:sleep
:: пауза в сотых долях сек
setlocal
call :gettick
set /a finish=%errorlevel%+%1
if %finish% geq 8640000 set finish=0
:slplabel
call :gettick
if %errorlevel% lss %finish% goto slplabel
endlocal & exit /b
:gettick
:: долей сек, прошедших с начала дня
setlocal
set t=%time: =0%
set /a tick=1%t:
0,2%-100)*360000
endlocal & exit /b %tick%
Данный код создаст 8 импульсов по DTR в цикле. Удачи!
Примечание. Отправлять комментарии могут только участники этого блога.
Translate
Поиск по блогу (831 topic)
Избранное
Авторский опыт в помощь разработчику
Популярное
Cross-YAGI & Helix и Zastone M7 на SATCOM. Резюмируя.
Ранее в 1 и 2 части был подробно рассмотрен конструктив простой 3el антенны бегущей волны круговой RHCP-поляризации (Cross-YAGI 3el) с уче.
У меня стоит задача мониторинга и управления ИБП АРС, подключенного к удаленной ПЭВМ через COM-порт RS232. Как работать с COM-портом на локальной ПЭВМ и осуществить мониторинг и управление ИБП АРС я знаю. А также я знаю как подключиться (через WMI или Telnet) к удаленной ПЭВМ и запустить и запустить задачу и исполнить её в консольном режиме. На удаленной ПЭВМ я не могу устанавливать своего ПО, т.е. мне необходимо пользоваться стандартными средствами Windows. А на ПЭВМ где производиться мониторинг (локальная) я хозяин, поэтому моя задача узнать как стандартными средствами Windows манипулировать COM-портом (а значит ИБП АРС) на удаленной ПЭВМ, а результаты получать и обрабатывать на локальной ПЭВМ (где мониторинг).
Слышал я, что есть возможность удаленно манипулировать COM-портом можно через WMI, но я не знаю как.
В командной строке Windows есть возможность обращаться к COM-порту по имени вида COMx , где x — номер порта. Эта возможность пришла ещё из MS DOS.
Например, для отправки текста «123» устройству можно воспользоваться командой
В порт будут отправлены байты, содержащие коды символов из параметра команды echo .
Для указания параметров порта можно воспользоваться командой mode . Пример использования:
Это означает, что порт COM1 работает со скоростью 9600 бод, передаёт данные по 8 бит и не использует проверку чётности.
Возможно есть и другие средства для удалённой работы с оборудованием машины, которые вам лучше подойдут. Например, если установлен PowerShell, то можно воспользоваться его возможностями.
Пример работы с портом из VBScript (к сожалению, не было возможности проверить на реальном железе).
В настоящее время существует множество устройств, которые обмениваются с компьютером информацией через последовательный порт (COM1, COM2) по протоколу RS-232. Причем такие устройства разрабатывают до сих пор и, я уверен, будут разрабатывать и в дальнейшем. Ведь несмотря на недостатки такой связи: медленная скорость обмена информацией, ограничение на длину соединительных линий — существует и немало достоинств: программная поддержка протокола RS-232 и ему подобных многими периферийными устройствами, специализированными микросхемами, низкая стоимость, минимальное количество соединительных проводов, простота.
Но, как это ни странно, информации по работе с последовательными портами в программах под Win32 очень мало. Материал этой статьи основан на статье Олега Титова Работа с коммуникационными портами (COM и LPT) в программах для Win32 — ознакомиться с ней можно по адресу. Автором очень подробно описаны функции для работы с коммуникационными портами, основное внимание уделено синхронному обмену информацией. Мы же рассмотрим вариант обмена между компьютером и периферийным устройством в асинхронном режиме (как правило, используемом наиболее часто) — причем для простейшего соединения по трем проводам, без использования управляющих сигналов. Таким же образом можно организовать связь между двумя компьютерами (хотя бы для проверки работы своей программы).
Начнем с главного: с последовательными портами в Win32 работают как с файлами. Причем используют только функции API Win32.
Начинается работа с открытия порта как файла, причем для
асинхронного режима ввода-вывода возможен только один вариант:
Других вариантов быть не может, поэтому не будем рассматривать
параметры этой функции подробно, единственное, что можно сделать —
это заменить “COM1” на “COM2”. Больше последовательных портов на
компьютере, как правило, нет. При успешном открытии порта функция
возвращает дескриптор handle, с которым и будем работать в
дальнейшем. При неудачном открытии порта функция вернет значение
INVALID_HANDLE_VALUE.
Настройка порта
Получив доступ к порту, необходимо его настроить — задать
скорость обмена, формат данных, параметры четности и т. д. Основные
параметры последовательного порта задают структуры DCB и
COMMTIMEOUTS. Структура DCB содержит основные параметры порта и,
кроме этого, довольно много специфических полей.
typedef struct _DCB
DWORD DCBlength; // sizeof(DCB)
DWORD BaudRate; // current baud rate
DWORD fBinary:1; // binary mode, no EOF check
DWORD fParity:1; // enable parity checking
DWORD fOutxCtsFlow:1; // CTS output flow control
DWORD fOutxDsrFlow:1; // DSR output flow control
DWORD fDtrControl:2; // DTR flow control type
DWORD fDsrSensitivity:1; // DSR sensitivity
DWORD fTXContinueOnXoff:1; // XOFF continues Tx
DWORD fOutX:1; // XON/XOFF out flow control
DWORD fInX:1; // XON/XOFF in flow control
DWORD fErrorChar:1; // enable error replacement
DWORD fNull:1; // enable null stripping
DWORD fRtsControl:2; // RTS flow control
DWORD fAbortOnError:1; // abort reads/writes on error
DWORD fDummy2:17; // reserved
WORD wReserved; // not currently used
WORD XonLim; // transmit XON threshold
WORD XoffLim; // transmit XOFF threshold
BYTE ByteSize; // number of bits/byte, 4-8
BYTE Parity; // 0-4=no,odd,even,mark,space
BYTE StopBits; // 0,1,2 = 1, 1.5, 2
char XonChar; // Tx and Rx XON character
char XoffChar; // Tx and Rx XOFF character
char ErrorChar; // error replacement character
char EofChar; // end of input character
char EvtChar; // received event character
WORD wReserved1; // reserved; do not use
Мы рассмотрим назначение только некоторых основных полей этой
структуры, используемых для нашего случая ввода-вывода, так как
многие поля можно заполнить значениями “по умолчанию”, пользуясь
функцией GetCommState:
BOOL GetCommState(
HANDLE hFile,
LPDCB lpDCB
Таким образом, нет необходимости вникать во все тонкости
структуры. После этого некоторые поля DCB все же придется заполнить
вручную, а именно:
BaudRate — скорость передачи данных. Возможно указание
следующих констант: CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400,
CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400, CBR_56000,
CBR_57600, CBR_115200, CBR_128000, CBR_256000. Можно просто указать
соответствующее число, например 9600, но предпочтительнее все-таки
пользоваться символическими константами.
ByteSize — определяет число информационных бит в
передаваемых и принимаемых байтах. Может принимать значение 4, 5, 6,
7, 8.
Parity — определяет выбор схемы контроля четности. Данное
поле должно содержать одно из следующих значений:
- EVENPARITY — дополнение до четности;
- MARKPARITY — бит четности всегда равен 1;
- NOPARITY — бит четности отсутствует;
- ODDPARITY — дополнение до нечетности;
- SPACEPARITY — Бит четности всегда 0.
StopBits — задает количество стоповых бит. Поле может
принимать следующие значения:
- ONESTOPBIT — один стоповый бит;
- ONE5STOPBIT — полтора стоповых бита (практически не
используется); - TWOSTOPBIT — два стоповых бита.
После того как все поля структуры DCB заполнены, необходимо
произвести конфигурирование порта, вызвав функцию SetCommState:
BOOL SetCommState(
HANDLE hFile,
LPDCB lpDCB
В случае успешного завершения функция вернет отличное от нуля
значение, а в случае ошибки — нуль.
Второй обязательной структурой для настройки порта является
структура COMMTIMEOUTS. Она определяет параметры временных задержек
при приеме-передаче. Вот описание этой структуры:
typedef struct _COMMTIMEOUTS
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultiplier;
DWORD WriteTotalTimeoutConstant;
> COMMTIMEOUTS,*LPCOMMTIMEOUTS;
Поля структуры COMMTIMEOUTS имеют следующие значения:
- ReadIntervalTimeout — максимальное временной промежуток
(в миллисекундах), допустимый между двумя считываемыми с
коммуникационной линии последовательными символами. Во время
операции чтения временной период начинает отсчитываться с момента
приема первого символа. Если интервал между двумя
последовательными символами превысит заданное значение, операция
чтения завершается и все данные, накопленные в буфере, передаются
в программу. Нулевое значение данного поля означает, что данный
тайм-аут не используется. - ReadTotalTimeoutMultiplier — задает множитель (в
миллисекундах), используемый для вычисления общего тайм-аута
операции чтения. Для каждой операции чтения данное значение
умножается на количество запрошенных для чтения символов. - ReadTotalTimeoutConstant — задает константу (в
миллисекундах), используемую для вычисления общего тайм-аута
операции чтения. Для каждой операции чтения данное значение
плюсуется к результату умножения ReadTotalTimeoutMultiplier на
количество запрошенных для чтения символов. Нулевое значение полей
ReadTotalTimeoutMultiplier и ReadTotalTimeoutConstant означает,
что общий тайм-аут для операции чтения не используется. - WriteTotalTimeoutMultiplier — задает множитель (в
миллисекундах), используемый для вычисления общего тайм-аута
операции записи. Для каждой операции записи данное значение
умножается на количество записываемых символов. - WriteTotalTimeoutConstant — задает константу (в
миллисекундах), используемую для вычисления общего тайм-аута
операции записи. Для каждой операции записи данное значение
прибавляется к результату умножения WriteTotalTimeoutMultiplier на
количество записываемых символов. Нулевое значение полей
WriteTotalTimeoutMultiplier и WriteTotalTimeoutConstant означает,
что общий тайм-аут для операции записи не используется.
Немного поподробнее о тайм-аутах. Пусть мы считываем из порта 50
символов со скоростью 9 600 бит/с. Если при этом используется 8 бит
на символ, дополнение до четности и один стоповый бит, то на один
символ в физической линии приходится 11 бит (включая стартовый бит).
Значит, 50 символов на скорости 9 600 бит/с будут приниматься
или примерно 57,3 миллисекунды, при условии нулевого интервала
между приемом последовательных символов. Если же интервал между
символами составляет примерно половину времени передачи одного
символа, т. е. 0,5 миллисекунд, то время приема будет
или примерно 82 миллисекунды. Если в процессе чтения прошло более
82 миллисекунд, то мы вправе предположить, что произошла ошибка в
работе внешнего устройства и можем прекратить считывание, тем самым
избежав зависания программы. Это и есть общий тайм-аут операции
чтения. Аналогично существует и общий тайм-аут операции записи.
Формула для вычисления общего тайм-аута операции, например,
чтения, выглядит так:
NumOfChar x ReadTotalTimeoutMultiplier +
ReadTotalTimeoutConstant
где NumOfChar — число символов, запрошенных для операции чтения.
В нашем случае тайм-ауты записи можно не использовать и
установить их равными нулю.
После заполнения структуры COMMTIMEOUTS, необходимо вызвать
функцию установки тайм-аутов:
BOOL SetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
Поскольку операции передачи-приема ведутся на малой скорости,
используется буферизация данных. Для задания размера буфера приема и
передачи необходимо воспользоваться функцией:
BOOL SetupComm(
HANDLE hFile,
DWORD dwInQueue,
DWORD dwOutQueue
Допустим, вы обмениваетесь с внешним устройством пакетами
информации размером 1024 байта, тогда разумным размером буферов
будет значение 1200. Функция SetupComm интересна тем, что она может
просто принять ваши размеры к сведению, внеся свои коррективы, либо
вообще отвергнуть предложенные вами размеры буферов — в таком случае
эта функция завершится ошибкой.
Приведу пример открытия и конфигурирования последовательного
порта COM1. Для краткости — без определения ошибок. В данном примере
порт открывается для работы со скоростью 9 600 бит/c, используется 1
стоповый бит, бит четности не используется:
HANDLE handle;
COMMTIMEOUTS CommTimeOuts;
SetupComm(handle, SizeBuffer, SizeBuffer);
GetCommState(handle, &dcb);
dcb.BaudRate = CBR_9600;
dcb.fBinary = TRUE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fDsrSensitivity = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = 1;
SetCommState(handle, &dcb);
CommTimeOuts.ReadIntervalTimeout= 10;
CommTimeOuts.ReadTotalTimeoutMultiplier = 1;
// значений этих тайм – аутов вполне хватает для уверенного
приема
// даже на скорости 110 бод
CommTimeOuts.ReadTotalTimeoutConstant = 100;
// используется в данном случае как время ожидания
посылки
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(handle, &CommTimeOuts);
PurgeComm(handle, PURGE_RXCLEAR);
PurgeComm(handle, PURGE_TXCLEAR);
После открытия порта первым делом необходимо сбросить его, так
как в буферах приема и передачи может находиться “мусор”. Поэтому в
конце примера мы применили ранее не известную нам функцию
PurgeComm:
BOOL PurgeComm(
HANDLE hFile,
DWORD dwFlags
Эта функция может выполнять две задачи: очищать очереди
приема-передачи в драйвере или же завершать все операции
ввода-вывода. Какие именно действия выполнять, задается другим
параметром:
- PURGE_TXABORT — немедленно прекращает все операции
записи, даже если они не завершены; - PURGE_RXABORT — немедленно прекращает все операции
чтения, даже если они не завершены; - PURGE_TXCLEAR — очищает очередь передачи в драйвере;
- PURGE_RXCLEAR — очищает очередь приема в
драйвере.
Эти значения можно комбинировать с помощью побитовой
операции OR. Очищать буферы рекомендуется также после ошибок
приема-передачи и после завершения работы с портом.
Настало время для рассмотрения непосредственно операций
чтения-записи для порта. Как и для работы с файлами, используются
функции ReadFile и WriteFile. Вот их прототипы:
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumOfBytesToRead,
LPDWORD lpNumOfBytesRead,
LPOVERLAPPED lpOverlapped
BOOL WriteFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumOfBytesToWrite,
LPDWORD lpNumOfBytesWritten,
LPOVERLAPPED lpOverlapped
Рассмотрим назначение параметров этих функций:
- hFile — описатель открытого файла коммуникационного
порта; - lpBuffer — адрес буфера. Для операции записи данные из
этого буфера будут передаваться в порт. Для операции чтения в этот
буфер будут помещаться принятые из линии данные; - nNumOfBytesToRead, nNumOfBytesToWrite — число ожидаемых
к приему или предназначенных для передачи байт; - nNumOfBytesRead, nNumOfBytesWritten — число фактически
принятых или переданных байт. Если принято или передано меньше
данных, чем запрошено, то для дискового файла это свидетельствует
об ошибке, а для коммуникационного порта — совсем не обязательно.
Причина в тайм-аутах. - LpOverlapped — адрес структуры OVERLAPPED, используемой
для асинхронных операций.
В случае нормального завершения функции возвращают значение,
отличное от нуля, в случае ошибки — нуль.
Приведу пример операции чтения и записи:
DWORD numbytes, numbytes_ok, temp;
COMSTAT ComState;
OVERLAPPED Overlap;
numbytes = 6;
ClearCommError(handle, &temp, &ComState);
// если temp не равно нулю, значит — порт в состоянии
ошибки
if(!temp) WriteFile(handle, buf_in, numbytes,
&numbytes_ok, &Overlap);
ClearCommError(handle, &temp, &ComState);
if(!temp) ReadFile(handle, buf_in, numbytes, &numbytes_ok,
&Overlap);
// в переменной numbytes_ok содержится реальное число
переданных-
// принятых байт
В этом примере мы использовали две неизвестные нам ранее
структуры COMSTAT и OVERLAPPED, а также функцию ClearCommError. Для
нашего случая связи “по трем проводам” структуру OVERLAPPED можно не
рассматривать (просто использовать, как в примере). Прототип функции
ClearCommError имеет вид:
BOOL ClearCommError(
HANDLE hFile,
LPDWORD lpErrors,
LPCOMSTAT lpStat
Эта функция сбрасывает признак ошибки порта (если таковая имела
место) и возвращает информацию о состоянии порта в структуре
COMSTAT:
typedef struct _COMSTAT
DWORD fCtsHold:1;
DWORD fDsrHold:1;
DWORD fRlsdHold:1;
DWORD fXoffHold:1;
DWORD fXoffSent:1;
DWORD fEof:1;
DWORD fTxim:1;
DWORD fReserved:25;
DWORD cbInQue;
DWORD cbOutQue;
> COMSTAT, *LPCOMSTAT;
Нам могут пригодиться два поля этой структуры:
- CbInQue — число символов в приемном буфере. Эти символы
приняты из линии, но еще не считаны функцией ReadFile; - CbOutQue — число символов в передающем буфере. Эти
символы еще не переданы в линию.
Остальные поля данной структуры содержат информацию об
ошибках.
И наконец, после завершения работы с портом его следует закрыть.
Закрытие объекта в Win32 выполняет функция CloseHandle:
BOOL CloseHandle(
HANDLE hObject
На нашем сайте вы можете найти полный текст класса для работы с
последовательным портом в асинхронном режиме “по трем проводам”, а
также пример программы с использованием этого класса. Все это
написано под Builder С++, но, поскольку используются только функции
API Win32, текст программы легко изменить под любой компилятор С++.
Возможно также, что класс написан не совсем “по правилам” — прошу
извинить, автор не является “правильным” программистом и пишет так,
как ему удобно J .
Если у вас возникли вопросы по поводу использования функций, рассмотренных выше, вы всегда сможете обратиться к справочной информации по Win32. А если возникнет необходимость более полно использовать последовательные порты (например, использовать различные управляющие сигналы) прочтите статью Олега Титова Работа с коммуникационными портами (COM и LPT) в программах для Win32
Читайте также: