Архивы: по дате | по разделам | по авторам

Обмен данными через COM-порт в Windows

Архив
автор : Юрий Ревич   13.10.1998

 

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

Представляемый сегодня "Уголок программиста" в скором времени тоже разделит судьбу "Утюгов" и будет полностью переведен на сайт еженедельника. Это вовсе не означает, что "Утюгам" и "Уголку" будет закрыт доступ к "бумажной" версии. Мы намерены печатать наиболее интересные широкому кругу читателей подборки из всех онлайновых рубрик, а в случае улучшения ситуации с доступными печатными площадями надеемся уместить на бумажные страницы все в полном объеме. "Уголок программиста" одновременно начинает свое существование здесь и на сайте, причем на сайте - в объеме, значительно большем, нежели в печати. Все заинтересованные читатели приглашаются к обсуждению опубликованного материала и могут предлагать свои хитрости и приемы программирования. Разумеется, можно задавать вопросы - наши авторы постараются на них ответить.

Сергей Леонов

Разработчики высокоуровневых языков программирования, очевидно, считают прием/передачу данных по протоколу RS232 через коммуникационный порт экзотической процедурой: мол, рядовому пользователю как бы и без надобности, а нерядовой - разберется самостоятельно. Потому ни в Turbo Pascal, ни в Delphi нет штатных средств обмена данными таким способом. Однако в последнее время, особенно в связи с распространением микропроцессорных устройств, такая задача встает в любительских программах все чаще - в силу простоты и дешевизны реализации последовательным портом оборудованы многие научные и инженерные приборы, разнообразные датчики и измерители.

Простота аппаратного исполнения (для обычной двусторонней связи требуется всего три провода) асинхронного коммуникационного порта ведет, однако, к некоторому усложнению необходимого программного обеспечения. Можно, конечно, попробовать послать байт на устройство COM1 средствами DOS, подобно тому, как это делается для LPT1 (оно же PRN), но успех вряд будет достигнут - как минимум, надо сначала настроить скорость обмена. Потому для DOS-программ это делается средствами BIOS или прямым программированием порта "по железу". А в Windows, к счастью, есть соответствующие функции API.

Для организации обмена нужно проделать следующие шаги:

  • получить дескриптор порта (handle - указатель, куда посылать все относящееся к порту);
  • получить адрес DCB - Data Control Block;
  • установить новые параметры DCB;
  • послать установленные параметры в порт;
  • приступить к чтению принимаемых данных или к передаче.

Рассмотрим все по порядку. Получить дескриптор можно с помощью универсальной функции CreateFile. Так как СОМ - устройство последовательное, то его можно рассматривать как файл, что и делается (и в DOS, между прочим, тоже). У этой функции множество применений (описание в Help, если распечатать, занимает страниц семь). Для нее требуется масса входных параметров, но большинство из них нам не нужны и приравниваются, в зависимости от типа, либо к 0, либо к величине nil (указатели, которые никуда не указывают). В нашем случае получается следующий синтаксис функции:

CreateFile (stcom, generic_read+generic_write, 0, nil, open_existing, 0, 0);

Здесь stcom - строка типа Pchar, в которой записано имя файла, в данном случае - просто 'COM1' или 'COM2', смотря какой порт нужен. Параметр generic_read+generic_write означает, что порт открывается как для вывода, так и для ввода. Open_existing означает проверку существования, и если объявленного порта нет, после вызова функции возникнет ошибка, которую можно проанализировать обычным методом Delphi: try ... except.

Получить адрес DCB можно, если применить функцию GetCommState (pCOM, pDCB); здесь pCOM - дескриптор порта, pDCB - возвращаемый адрес структуры DCB. Установить параметры порта в этой структуре можно непосредственно, но если вы обратитесь к ее описанию в Help, то бессонная ночь вам обеспечена. Поэтому проще сделать это с помощью вызова функции BuildCommDCB (stcom, pDCB), в которой stcom в данном случае содержит набор устанавливаемых параметров в виде строки (см. пример ниже). Установленные параметры посылаются в порт с помощью функции SetCommState (pCOM, pDCB). Все эти функции возвращают значение типа Boolean, которое равно True, если операция прошла успешно. Чтение из порта и запись в порт осуществляются с помощью симметричных функций ReadFile и WriteFile, также универсальных и потому содержащих ненужный нам параметр, который мы приравняем к nil:

Boolean ReadFile (pCOM, xb, 1, xn, nil);

Здесь xb - переменная любого целого типа, в которой возвращается прочитанное значение (для WriteFile в ней содержится, наоборот, записываемое), 1 - столько байт прочесть из xb (для СОМ-порта это, очевидно, всегда 1), xn - сколько байт действительно прочитано. Следующий программный фрагмент инициализирует порт СОМ1 и осуществляет прием данных до тех пор, пока не будет нажата любая клавиша на клавиатуре. Принимаемые данные преобразуются в строку и выводятся на экран через пробел в компоненте Label1 (с переводом строки через каждые 32 значения; разумеется, можно выводить в любой компонент, имеющий свойство text или caption, или еще куда-нибудь):

stcom:='COM1';
try
pCOM:= CreateFile (stcom, generic_read+generic_write, 0, nil, open_existing, 0, 0);
except <error>;
if GetCommState(pCOM,pDCB)
then stcom:='COM1: baud=9600 parity=N data=8 stop=1'
else <error>;
if BuildCommDCB(stcom,pDCB) then SetCommState(pCOM,pDCB)
else <error>;
while (MSG.Message <> wm_KeyDown) do
begin
bb:=ReadFile(pCOM,xb,1,xn,nil);
if not bb then break;
st:=st+' '+IntToStr(xb);
if length(st) mod 32=0
then st:=st+chr(10)+chr(13);
Label1.Caption:=st;
peekmessage(msg,Form1.Handle,0, 0,PM_REMOVE); {читаем сообщение из очереди, если есть - удаляем}
Application.ProcessMessages; {очищаем очередь сообщений - на всякий случай}
end;

Прежде чем подключать к компьютеру какие-либо устройства, следует сказать пару слов о технике безопасности. Если прибор беспаспортный или, тем более, самодельный, следует проверить следующее: а) напряжение на выходе порта прибора не должно превышать значений +/-15 В (минимум +/-3 В), и на экране осциллографа не должно наблюдаться заметных выбросов и "шпилек", превышающих эти значения, - в противном случае вы рискуете лишиться COM-порта (это особенно неприятно, если порт расположен на материнской плате; в сомнительных случаях лучше экспериментировать с дополнительной ISA-картой, оборудованной COM-портами; б) нужно убедиться, что выход прибора электрически развязан с сетью.

© ООО "Компьютерра-Онлайн", 1997-2021
При цитировании и использовании любых материалов ссылка на "Компьютерру" обязательна.