Разработчики высокоуровневых языков программирования, очевидно, считают
прием/передачу данных по протоколу 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 ;
if getcommstate(pcom,pdcb)
then stcom:='com1: baud=9600 parity=n data=8 stop=1'
else ;
if buildcommdcb(stcom,pdcb) then setcommstate(pcom,pdcb)
else ;
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-портами; б)
нужно убедиться, что выход прибора электрически развязан с сетью.
Автор: Юрий Ревич
|