вторник, 27 января 2015 г.

Обмен сообщениями через COM порт

   В одной из статей написанных ранее, мы уже касались работы с COM портом, зажигая и гася светодиод из написанного нами приложения. В этот раз рассмотрим создание простенького терминала, который в дальнейшем, Вы сможете самостоятельно усовершенствовать и доработать как Вам захочется. Фишка в том, что написанную нами программку, можно установить на два ПК, и соединив их нуль-модемным кабелем отправлять друг другу сообщения.
То есть текст написанный на ПК-1, будет отображаться на ПК-2 и наоборот).
   Работать с COM портом в DELPHI можно как с помощью API функций непосредственно, что малость сложнее и дольше, либо посредством специальных библиотек или компонентов, что значительно ускоряет процесс . Это вовсе не говорит о том, что API я в дальнейшем касаться совсем не буду, позже мы рассмотрим аналогичные вещи и с применением API, (благодаря чему сможем более глубоко рассмотреть принципы передачи данных через COM). Но не все сразу.
   Для работы с портом в этом примере, нам необходимо будет найти и скачать c интернета бесплатно распространяемый компонент  AsyncFree и установить его в Delphi. Устанавливается он просто, содержимое скачанной папки, копируете в папку lib, у меня например это находится здесь: C:\Program Files\Borland\Delphi7\Lib далее находите файл AsyncFreeD7.dpk (если у вас 7 версия Delphi), запускаете, компилируете и у Вас на панели инструментов появляется вкладка под названием AcyncFree c рядом компонентов:


Перезапускаете Delphi, создаете новый проект и помещаете компоненты на форму:


1) 4 кнопки Button, 1 - Edit, 1- AfComPort, 1 - AfPortComboBox, 1 - AfDadaTerminal; 1 - AfDataDispatcher, 1 - StatusBar, 1 - Timer и 2 компонента label

2) Далее настраиваем наши компоненты:
  • В свойстве: DataProvider компонента AfDataDispatcher1, должно стоять: - AfComPort1;
  • В свойствах компонента AfComPort1: 
          - AutoOpen - устанавливаем - false;
          - BaudRate - устанавливаем - br9600;
          - Databits - устанавливаем - br8;
          - Parity - устанавливаем - paNone;
          - StopBits - устанавливаем - sbNone;

          остальное пусть будет, по умолчанию.
  • В свойстве Dispatcher компонента AfDadaTerminal1, должно стоять: AfDataDispatcher1;
  • В свойство Enabled всех Button, и AfDadaTerminal1 - устанавливаем в False;
  • Далее очищаем свойство Caption, компонента Label2, и располагаем его напротив компонента Label1 (в него будем выводить, указанный в ник в настройках профиля);
  • Свойство - Caption всех остальных компонентов, которые его поддерживают, заполняем как на скрине выше;
В разделе var объявляем глобальные переменные:

var
  a:String; //пользователь
  t:TDateTime;

3) Свойство Enabled, кнопки Button1 ставим в false и создаем на ней обработчик событий OnClick, где пишем следующее:

procedure TForm1.Button1Click(Sender: TObject); // Открываем выбранный порт;

begin

AfComPort1.Open; //Открываем выбранный порт;
if   AfComPort1.Active=true then //Если сом порт активирован;
begin
AfPortComboBox1.Enabled:=False; //При запуске деактивируем комбобокс;
Button1.Enabled:=False; //Кнопку "пуск", делаем неактивной;
Button2.Enabled:=True;  //Кнопку "стоп" активируем;
Button3.Enabled:=True;  //Кнопку "отправить данные" активируем;
Button4.Enabled:=True;  //Кнопку "настройки" активируем;
Edit1.Enabled:=True;    //Активируем поле для ввода данных;
AfDataTerminal1.Enabled:=True;  //Активируем окно терминала;
ShowMessage('Терминал запущен успешно!)');

end;
end;

4) Свойство Enabled, кнопки Button2 ставим в false, создаем на ней обработчик событий OnClick, и записываем:

procedure TForm1.Button2Click(Sender: TObject); // Закрытие порта;

begin

AfComPort1.Close; //Закрываем порт;
Button1.Enabled:=False; //Деактивирует кнопку - Старт;
Button2.Enabled:=False; //Деактивируем кнопку - Стоп;
Button3.Enabled:=False; //Деактивируем кнопку - Отправить;
Button4.Enabled:=False; //Деактивируем кнопку - Настройки;
AfPortComboBox1.Enabled:=True; //Активируем - AfPortComboBox1
Edit1.Enabled:=False; //Деактивируем поле для ввода;
AfDataTerminal1.Enabled:=False; //Деактивируем окно терминала;

end;

5) Кликаем на StatusBar создаем три строчки:

 


я допустим, ширину поля - 0 установил в 70, чтоб поместилась, моя надпись, поле 1 - 568, т.к. ширина формы у меня - 759, а поле 2 - 50, чтобы поместились дата и время). В общем не принципиально, просто сделайте так, чтобы все поместилось и было красиво). Теперь 
создадим обработчик событий на таймере:

procedure TForm1.Timer1Timer(Sender: TObject);

var t:TDateTime;
begin
t:=now;
StatusBar1.Panels[2].Text:=DateTimeToStr(t);
end;



6) Создаем OnClick обработчик событий на Button3 и пишем:

procedure TForm1.Button3Click(Sender: TObject); //Отправляем данные в порт;

begin

AfComPort1.WriteString((Label2.Caption+': ')+(Edit1.Text)+('; ')+(StatusBar1.Panels[2].Text)+#13+#10);
AfComPort1.ReadString;
AfComPort1.PurgeRx; // Очищаем порт;
Edit1.Text:=''; //Очищаем Edit;
end;

7) Добавляем вторую форму в наш проект, сделать это можно следующим образом:




после чего, сохраняете ее в папке с проектом, и оформляем примерно так:


и создаем обработчик событий на кнопке, нашей новой форме:

procedure TForm2.Button1Click(Sender: TObject);
begin
Form2.Close;
end;


8) Создаем OnClick обработчик событий на Button4 и прописываем:

procedure TForm1.Button4Click(Sender: TObject);

begin

Form2.ShowModal;
Form1.Label2.Caption:=Form2.Edit1.Text;
Form2.Close;

end;

9) Создаем onCreate обработчик событий на главной форме где пишем:

procedure TForm1.FormCreate(Sender: TObject); { Активируем AfPortComboBox1, со списком портов }
begin
AfPortComboBox1.Itemindex:=0;
end;

тут же создаем обработчик OnClose:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

AfComPort1.PurgeRx; // Очищаем порт;
AfComPort1.Close;  //Закрываем порт;
Button1.Enabled:=False;  //Деактивируем Пуск и Стоп
Button2.Enabled:=False;
Button3.Enabled:=False;
Button4.Enabled:=False;
AfPortComboBox1.Enabled:=True; //ComboBox делаем активным;

end;

и OnKeyPress:

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if key =#13 then Button3.Click; //Отправляем данные, при нажатии клавиши Enter;
end;

10) В разделе Private нашего листинга, cоздаем процедуру, закрытия нашей программы по-нажатию на клавишу Esc:

procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;

выделяем, жмем Ctrl+Shift+C, и в появившейся заготовке пишем:

procedure TForm1.CMDialogKey(var Message: TCMDialogKey); //закрываем форму на esc
begin
with Message do if (CharCode=VK_ESCAPE) and (KeyDataToShiftState(KeyData)=[]) then
begin
if fsModal in FormState then
begin ModalResult := mrCancel;
end
else
Result := Integer(PostMessage(Handle, WM_CLOSE, 0, 0));
if Result <> 0 then
Exit;
end;
inherited;
end; 

11) Событие OnChange компонента AfPortComboBox1, заполняем:

procedure TForm1.AfPortComboBox1Change(Sender: TObject);
begin
if  AfPortComboBox1.ComNumber >0 then {Если порты удалось обнаружить, активируем кнопку Пуск;}
begin
Button1.Enabled:=true;
end;
end;

12) Наконец, переходим к компоненту AfComPort1 и создаем событие OnDataRecived:

procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);

begin
AfDataTerminal1.WriteString(AfComPort1.ReadString);
end;

   Ну вот пожалуй и все). Написано много, но если бы мы использовали API, то кода было бы раза в 2 больше... подключаем нуль-модемный кабель (мама/мама) к нашему ПК или ноутбуку (через конвертер USB/COM), замыкаем контакты 2 и 3 прямо на разъеме кабеля и запускаем нашу программку. В комбобоксе выбираем определившийся порт, нажимаем кнопку Пуск. После чего если порт существует и не занят, система выдаст  соответствующее сообщение, что все успешно. Далее в настройках вбиваем свой ник, например - "Вася" в Edit что нибудь пишем - например - "Привет дружище!!!" и нажимаем клавишу Enter на клавиатуре. На экране нашего монитора должно появиться примерно следующее:


  Если у Вас все получилось, тогда смело, можно соединять нашим кабелем 2 ПК, можно через конвертеры USB/COM, (если COM порты на машинах отсутствуют), запускать программу на обоих машинах и приступать к обмену сообщениями). Как я уже упоминал выше, мы написали много, и в нашем случае нельзя абстрагироваться от вероятности допущения ошибок, если вдруг их обнаружите, просьба отписаться в комментах, буду очень признателен. Ну и на всякий "пожарный" случай, выкладываю исходник с проектом нашей программы)
Скачать исходник




2 комментария:

Примечание. Отправлять комментарии могут только участники этого блога.