Главная » Delphi » Прием и передача данных с помощью компонента AsyncFree

0

Один из самых удачных и профессионально сделанных компонентов для СОМ-порта (а я их перепробовал достаточно много), на мой взгляд. — свободно распространяемый AsyncFree некоего Петра Вониса (Pelr Vones). судя по e-mail, из Чехии. Компонент доступен бесплатно, с исходными кодами и скачанный архив включает в себя, в том числе, и файлы DPK, что упрощает процедуру установки до предела — нужно просто щелкнуть мышью на том из этих файлов, который соответствует имеющейся у вас версии Delphi, и компонент установится самостоятельно, без утомительных процедур ручной инсталляции. Хотя к самому компоненту приложена ссылка на (отличный, кстати) сайт Delphree Open Source Initiative (http://delphree.clexpert.com), однако на нем вы найдете только старую версию AsyncFree под Delphi 5, а скачивать последние версии лучше отсюда: http://sourceforge.nct/project /showfiles.php?group_id=20226. Все эти адреса я привожу на всякий случай, потому что архив с компонентом есть на диске (в папке Glava21\AsyncFree). Все его возможности я вам не покажу — это нереально, да и большинство из них вряд ли пригодится, на его основе мы сейчас просто сделаем вариант той же самой программы COMproba.

Перенесем проект из папки Glava3\2 в папку Glava3\3. Считаем, что компонент установлен и находится в палитре компонентов на вкладке AsyncFree. На самом деле там образуется много компонентов, и нам требуется самый первый из них под названием AfComPort. Установим его на форму. Из перечня переменных удалим все, что касается файлов, потоков и т. д., добавив лишь еще один флаг и переменную tall целого типа:

var

Forml: TForml; xb:byte;

ab: arrayil..1024] of byte; st,steam:string; ttime,tola:TDateTime; FlagCQM:boolean=False; FlagSend:boolean=False; tall:integer;

Начнем с того, что перепишем процедуру inicow:

procedure IniCOM; var i, err :integer; begin

FlagCCM:=False;

Forml.Label7.Caption: =’COM? *;

(инициализация COM – номер в строке stcom}

Forml.AfComPortl.Close; (закрываем старый COM, если Был}

val(stcom[length(stcom)],i,err) ;

if err=0 then Forml.AfComPortl.ComNumber:=i else exit;

{номер порта] Forml.AfComPortl.BaudRate:=br9600; {скорость 9600} try

Forml.AfComPortl.Open; except

if not Forml.AfComPortl,Active then {если не открылся) begin

st:=stcom+’ does not be present or occupied.'; Application.MessageBox{Pchar(st),’Error’,MB_OK); exit Iвыход из процедуры – неудача) end; end;

ab[l]:=ord(‘A’); (будем посылать ршициализацию модема) ab[2]:=ord(‘T’); ab[3]:=13;ICR) ab[4]:=10; (LF)

for i:=l to 4 do Forml.AfComPortl.WriteData(ab[i],1);

{ответ не сразу:I

Forml.Timer1.Enabled:=True;

tall:=0;

while tall<l do application.ProcessMessages; (пауза ale) Forml.Timerl.Enabled:=False;

st:=Forml.AfComPortl.ReadString; (ответ модема 10 знаков)

if pos(‘OK’,st)<>0 then {модем}

begin

st:=stcom+’ занят модемом'; Forml.Timeг1.Enabled:=False;

Application.MessageBox(Pchar(st),’Error’,MB_OK); exit;

end else {все нормально, открываем COM} begin

Forml.Label7.Caption:=stcom+’ 9600′;

st:=’{очищаем строку для вывода) FlagCOM:=True; end; end;

Как видим, процедура создания порта много понятнее, чем в том случае — все через привычную установку свойств компонента. FiagcoM теперь играет у нас роль индикатора— доступен порт или нет. При определении модема здесь применен хитрый способ задания паузы — вместо обычного оператора sleep, который тормозит программу, мы использовали таймер. Чтобы это сработало, в процедуре onTimer при этом достаточно добавить строку inc(tall) (далее мы покажем эту процедуру полностью).

Как только мы обратились к процедуре AfCornPortl.Open, у нас немедленно будет создан параллельный поток и весь прием пойдет через него. Поэтому, чтобы при определении модема принятые байты не обрабатывались, надо не забыть добавить в процедуру приема выход по условию FiagC0M=False.

Для создания этой процедуры удаляем процедуры ReadComPort И ReceiveCOM. Вместо них обычным способом — через инспектор объектов — создадим обработчик события AfComPort IDataRecived3.

prooedure TForml.AfComPortlDataRecived(Sender: TObject;

Count: Integer); {чтение очередного байта по сообщению wmCOMPORTI vat i:integer; begin

if FlagCOM=False then exit; {если модем еще не опрошен)

if count<>0 then {если что-то принято)

begin

{если порт существует)

ttime:=Time; {фиксируем время прихода байта) if MilliSecondsBetween(told,ttime)>500 then

{если больше полсекунды, очищаем строку)

st:=’1;

AfComPortl.ReadData(ab,count); {читаем буфер) for i:=l to count do st:=st+hexb(ab[i])+’ ‘;

if Forml.Memol.Lines.Count>65000 then Forml.Memol.Lines.Clear; {больше 64К строк нельзя)

Fonnl.Memol.Lines.Add(st); (выводим a Memo) told:=ttime; /для сравнения в следующий раз) if (SecoridsBetween(told,ttime)<1) and FlagSend then /если это была посыпка)

begin

FlagSend:=False; st:-”; {очищаем строку} Timerl.Enabled:=False; (выключаем таймер) end; end; end;

Как видим, она почти не отличается от ReceivecOM. На самом деле условие countoo не требуется, оно введено просто ради порядка. Осталось только переписать остальные процедуры, они изменятся в сторону упрощения:

procedure TForml.ButtonlClick(Sender: TObject);

begin (запрос/

if F1agCOM= Fa1se then exit;

(если порт еще не инициализирован – выход)

AfComPortl.PurgeRX; {очищаем буфер на всякий случай/

xb:=$A2;

AfComPortl.WriteData(xb,1); {посылаем команду) st: =’Послано: ‘fhexb(xb);

Forml.Memol.Lines.Add(st); {записали в Memo) st:=’1; {очистили строку) told:=Time; (зафиксировали момент посылки) FlagSend:=True; {обозначаем посылку! Timerl.Enabled:^True; {запускаем таймер) end;

procedure TForml.FormCreate(Sender: TObject); begin

/инициализацию C0M1 при запуска)

stcom:=’COMl';

IniCOM;

end;

procedure TForml.CcmboBoxlSeLect(Sender: TObject); begin

stcom:=ComboBoxl.Text; /устанавливаем порт COM!,2,3,4)

IniCOM;

end;

procedure TFcrml.TimerlTimer(Sender: TObject); begin I таймер на ошибку) ttime:=Time; inc(tall);

if FlagCOM=False then exit;(запрос модема) if SeccndsBetween(told,ttime)>1 then

lесли через мае секунды ничего нет)

begin

Timerl.Enabled:=False; FlagSend:=False ;

Application.MessageBox(‘Устройство не обнаружено’,’Error’,MB_OK); end; end;

procedure TForml.FormDestroytSender: TObject); begin

AfComPcrtl.Close; Iзакрыпte порта I end;

Из этого текста мы видим, что программа не стала существенно проще с точки зрения объема кода, но зато особенности реализации различных механизмов вроде "оверлапинга" тут знать не требуется. Так что выбирайте сами.

Источник: Ревнч Ю. В.  Нестандартные приемы программирования на Delphi. — СПб.: БХВ-Петербург, 2005. — 560 е.: ил.

По теме:

  • Комментарии