COM порт (RS-232) Асинхронный обмен данными.

В этой статье мы рассмотрим пример асинхронного приема данных из СОМ порта средствами Delphi. То-есть опрос порта будет производиться непрерывно, до тех пор пока мы его не остановим, а прочитанную информацию она будет записывать в Memo. Чтобы процедура опроса не “подвешивала” наше приложение, мы организуем прослушивание порта в отдельном потоке. Поэтому прежде чем Вам начать практиковаться по настоящей статье, автор предполагает что читатель уже знаком с темой потоков в Delphi. Пример конечно примитивен, поскольку демонстрирует лишь минимум функций, которые можно реализовать для связи по трем проводкам (GND, RX и TX), но эта простота вовсе не снижает интереса к нашей с Вами теме. По скольку дает “живое” представление о принципе асинхронного чтения, да еще и на “сквозном” примере.

Исходник: скачать

Приступим:

1)  Поместим на форму следующие компоненты; Listbox – 1шт, Button – 4шт и компонент Memo – 1шт. Расставим их примерно как на рисунке ниже:
Для чего? Мы с Вами напишем программу с помощью которой  нажав кнопку – “Сканировать”, сможем увидеть доступные COM порты в нашем ListBoxе.  Кликнув по выделенному порту двойным щелчком мыши, мы к нему подключимся. После подключения нам станет доступна опция чтения, которая после того как мы нажмем на кнопку – “Начать чтение”, запустится и будет крутиться в отдельном потоке цикл прослушивания порта, и по мере обнаружения информации в буфере, будет помещать ее в компонент Memo. Ну и собственно на любом этапе работы программы, мы сможем очистить содержимое приема или вовсе разорвать связь с текущим портом, чтобы переключиться на любой другой свободный COM порт, ну или вовсе завершить работу нашего приложения. И так поехали дальше…
2) Объявим глобально следующие переменные:
Свойство Enabled у Button2 и Button3 установим в false, свойство ReadOnly компонента Memo установим в true;
В событии OnClick Button1 пропишем код для пересчета существующих портов и помещения их в наш ListBox:
3) B событии OnDblClick нашего ListBoxа запускаем и настраиваем выбранный порт
 

Что мы тут сделали?

Во-первых открыли порт для асинхронной работы: – File_Flag_Overlapped. Во-вторых настроили скорость обмена (9600 бод), количество бит в посылке (8), контроль четности (NoParity), указали количество стоповых бит (OneStopBit). Также мы настроили таймауты и размеры буферов порта, но по большому счету, для нашего примера можно обойтись и без них (если их не указывать и не настраивать, система все настроит автоматически), но раз уже мы их настроили, то пусть будут. В-третьих, мы установили маску – EV_RXchar – ожидание прихода байта. Это необходимо для нашего потока чтения. Смысл какой? В отдельном потоке, который мы сейчас создадим будет крутиться цикл, для которого приход байта в порт (Mask and EV_RXchar) <>0 – будет сигналом для чтения состояния порта, получения количества этих байт и если это количество не равно 0, (If Btr.Size<>0) то запуску чтения содержимого в
переменную буфера ReadFile(ComFile, Buffer, SizeOf(Buffer), Temp, @OverRead); и дальнейшую обработку этой переменной:
Form1.Memo1.Lines.Text:=Form1.Memo1.Lines.Text+(String(buffer)); {Загружаем в Memo содержимое буфера;}
Buffer:=”; //Очищаем переменную буфера; 
В общем как то так… Ну что создаем поток?
4) Создавать поток будем без помощи мастера, для этого прямо в нашем листинге после раздела:

Объявим наш поток:

В раздел глобальных переменных добавим переменную для нашего потока

Выделяем  procedure execute; override; жмем Ctrl+Shift+C и в теле появившейся главной процедуры запишем:

Для реализации процедуры чтения, выделяем procedure OutToMemo; в разделе объявления нашего потока, жмем Ctrl+Shift+C и в теле появившейся процедуры запишем:
 
5) Теперь задействуем запуск только что нами созданной процедуры чтения, для этого дважды
кликаем на Button3 и в появившейся процедуре записываем:
для возможности разорвать соединение  дважды
кликаем на Button2 и в появившейся процедуре запишем:
для очистки содержимого Memo  дважды кликаем на Button4 и в появившейся процедуре запишем:
 
теперь в процедуре FormClose закрытия приложения запишем:

Ну вот как бы и все, теперь наш проект готов к запуску, но прежде настроим аппаратную часть.
Для этого нам потребуется любая программка – терминал для отправки данных, 2 COM порта на материнке, если таковые отсутствуют, тогда 2 конвертера USB>COM. Я например использую 2 вот таких переходничка и соединяю их тремя проводками по следующей схеме:

RXD одного конвертера соединяем с TXD другого и наоборот, плюс массу одного конвертера соединяем с массой другого. Если Вы будете использовать штатные COM порты на матплате то нужно будет соединить их нульмодемным кабелем.

Один переходничок у меня в системе определился как COM3, второй как COM4. Запускаем наше приложение, подключаемся к порту COM3 и нажимаем нашу кнопку начала чтения, на этом “прослушивание” порта началось. Теперь запускаем программку терминал, для примера я использую  COM Port Toolkit 4.0 После запуска терминал нужно настроить – выбрать порт для подключения (в моем случае это COM4) и установить настройки DСB (скорость, количество бит информации, контроль четности, количество стоповых бит) такие же как у нашей программки:

Далее заходим в пункт меню “Сообщение” – “Отправить” и через его интерфейс пробуем отправлять различный текст, можно из файла, можно просто какие нибудь одиночные слова
или символы,
в общем если Вы все выполняли последовательно и внимательно, то в Mемо нашей программы будет отображаться все, что Вы будете отправлять из терминала.