Визуальный компонент-монитор COM-порта

Сегодня мы попробуем создать визуальный компонент для работы с разного рода считывателями, подключаемыми по COM-порту (правильное название интерфейса – RS232). Наша цель — получать последовательность байт, которую отправляет устройство при считывании.

Начнем с создания нового проекта типа Delphi Component:
image
В следующем окне выберем TEdit в качестве родительского компонента.
image
Напоследок, дадим звучное имя нашему будущему компоненту – TRS232Edit и поместим его в набор MyComponents палитры компонентов (RS 232 — наименование стандарта).
image
После нажатия Finish назовем модуль компонента uRS232Edit.pas и сохраним его. Среда разработки автоматически сформирует такой шаблон:

unit uRS232EANEdit;
interface
uses
SysUtils, Classes, Controls, StdCtrls;

type
TRS232Edit = class(TEdit)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('MyComponents', [TRS232Edit]);
end;

end.


Объявим структуру для хранения 20-ти байтов с порта (больше и не надо :))

type
TBuffer = array[0..20] of byte;


Начинаем закладывать функционал. Для начала объявим в секции private класса TRS232Edit переменные, в которых будем хранить параметры соединения с портом.

cComPort : integer;   // номер порта
cBaud : integer;  // скорость передачи (бод)
cParity : integer; // режим проверки четности
cCountBit : integer;  //число бит данных
cStopBit : integer;  //число стоповых бит


Ещё нам понадобятся

CommHandle : integer;  //хэндл COM-порта
DCB : TDCB;  //структура для хранения параметров соединения с портом
Ovr : TOverlapped; //структура для корректности асинхронных процессов
Stat : TComStat;  //  структура для хранения состояния порта
CommThread : THandle;  //хэндл потока, обрабатывающего события порта
function DigitHex(aValue: Integer): Char;
function GetAsHexagonal(aValue: Integer): String;  //преобразование в 16-ричный код
function DecodeBarCode(buf : TBuffer; bufsize : integer) : string;
procedure PortInit;
procedure SetZero;


и в секции public

BarCode : string; //будет выводиться в свойство Text
constructor Create(AOwner:Tcomponent);override;
destructor Free;
procedure Init(comport, baud, parity, countbit, stopbit : integer);


Инициализировать соединение с портом будем вызовом метода Init. В нем присываиваются парамерты внутренним переменным, выставляются начальные значения и вызывается метод непосредственно коннекта.

procedure TRS232EANEdit.Init(comport, baud, parity, countbit, stopbit : integer);
begin
cComPort := comport;
cBaud := baud;
cParity := parity;
cCountBit := countbit;
cStopBit := stopbit;
SetZero;
PortInit;
end;


Наибольший интерес здесь представляет метод PortInit — разберем его детально

procedure TRS232EANEdit.PortInit;
var
ThreadID: dword ;
begin
//открытие порта и получение его хэндла
CommHandle:= CreateFile(cComPort,GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,0);
//ставим маску - "по пришествии определенного символа"
SetCommMask(CommHandle,EV_RXFLAG);
//получаем текущие настройки соединения в DCB
GetCommState(CommHandle, DCB);
//выставляем наши значения
DCB.BaudRate:=cBaud;
DCB.Parity:=cParity;
DCB.ByteSize:=cCountBit;
DCB.StopBits:=cStopBit;
DCB.EvtChar:=chr(13); // будем ждать прихода байта 0x0D

//применение новых значений
SetCommState(CommHandle,DCB);
/* создаем параллельный поток, где вертеться процедура приема строки. Третий параметр - указатель на класс нашего компонента. BeginThread - обертка вокруг CreateThread. @ReadComm - указатель на функцию приема строки */

CommThread := BeginThread(nil,0,@ReadComm,Self,0,ThreadID);
end;


Прием данных происходит в процедуре ReadComm

procedure ReadComm(s : Pointer);
var
Resive : TBuffer;
a : TRS232EANEdit;
begin
a := s; // s - указатель на объект нашего компонента
while true do
begin
a.TransMask:=0;
WaitCommEvent(a.CommHandle,a.TransMask,@a.Ovr);
if (a.TransMask and EV_RXFLAG)=EV_RXFLAG then //проверяем нужное событие
begin
ClearCommError(a.CommHandle,a.Errs,@a.Stat);
ReadFile(a.CommHandle, Resive, a.Stat.cbInQue, a.Stat.cbInQue, @a.Ovr);//читаем
a.Text := a.DecodeBarCode(Resive, 20);  //в поле появляется штрих-код
Application.ProcessMessages;
end;
end;
end;


Всё. Компилим, устанавливаем. Чтобы считываение запустилось, в тестовом приложении достаточно приписать что-то вроде

RS232Edit1.Init(1, 9600, 0, 8, 1)
+3
29 мая 2011, 13:57
7
aspanin 7,5

комментарии (30)

–4
kekekeks #
Вау. А я и не знал, что на Делфи всё ещё кто-то пишет вне ВУЗов с устаревшей на 15 лет программой обучения.
+1
danilissimus #
>анимэ на аватарке
>http://hivemind.me
Да шо ты говоришь то!
+1
aspanin #
–4
kekekeks #
Самое забавное, что таблица только подтверждает мною сказанное. Язык ушёл из топа, доля продолжает падать, используется в основном там, где есть тонны legacy-кода, перспективы развития не прослеживаются вообще.
+3
aspanin #
Самое главное, таблица только противоречит Вами сказанному: на Делфи все-таки пишут. Не нравится язык — не пишите.
0
mark_ablov #
Ассемблер и Ада имеют кучу зелёных стрелочек.
Не думаю что этот топ так уж объективен :)
0
aspanin #
Дайте какой-нибудь другой топ
+2
ertaquo #
AIMP, QIP, R&Q, The Bat!, Download Master, Inno Setup написаны на Delphi. Они устарели на 15 лет?
+1
Oxide #
Total Commander самое главное.
+2
Evgin #
ertaquo и Oxide расширили мой кругозор =) Спасибки.
Насчет 15ти лет — не устарели!!!

ps Пользуюсь, 4 из 7 представленных программ =)
–2
kekekeks #
Не использовал ни одной из них уже много лет. Наверное, потому что эти годы живу без windows.
+1
ertaquo #
Игрушка Hedgewars, архиватор Peazip и клон Total Commander — Double Commander написаны на Free Pascal. Более-менее знаменитых программ под линукс назвать не могу, потому что под ним паскаль и его диалекты не особо распространены. Под маками они еще меньше используются, так что для них назвать не могу ни одной.
Что Delphi, что паскаль вполне живы и до сих пор много где используются. Например, если мне надо что-то на скорую руку и с графическим интерфейсом слепить, я скорее всего возьму Delphi. Как вариант — C#, но его я довольно плохо знаю и он требует .NET. В Delphi довольно легко использовать сторонние компоненты, а написано их немало — на www.torry.net/ больше 10 тысяч всяких полезностей.
+1
abyss #
Ещё виндовый клиент Skype, KMPlayer, FinalBuilder, PyScripter, BS Player
0
aspanin #
KMP, имхо, наиболее функциональный плеер
0
nolka #
мне очень нравится r&q, но он практически не развивается, и по сравнению с конкурентами выглядит устаревшим :(
+2
Evgin #
На Делфях пишут, пишут и пишут хорошо =)
–2
kekekeks #
Я не говорю, что на них нельзя хорошо писать. Писать хорошо можно хоть на брейнфаке. У языка объективно есть тонны проблем, главная из которых — ограниченность одной платформой. Даже софт писаный на Визуальном Основном с успехом компилится и работает на Mac и Linux. Не говоря уже о разных мобилках.
0
abyss #
Скоро и на дельфи можно будет компилить программы для Mac и Linux.
Только, боюсь, как и любое кроссплатформенное, будет выглядеть ненативно, т.е. на мой взгляд, средненький плюс в наличии кроссплатформенности.
0
kekekeks #
Да есть тот же Delphi.NET. Потом эти сборки заставить прожевать Mono — то ещё веселье. А ещё у меня есть сомнения, что борланд (или кто там сейчас владеет) осилит создание нормального компилятора под ARM.
+1
abyss #
Delphi.NET давно мёртв, ему на смену пришёл Delphi Prism.
Embarcadero сейчас акцентируются на создании 64-битного компилятора (выйдет в сентябре) и Linux/Mac (может тогда же будет доступен, но сомневаюсь).
ARM? Думаю ждать пока не стоит, хотя и не уверен что очень надо.
Опять же, если разбрасываться во все стороны, то ничего не успеешь, не майкрософт, не хватит ресурсов. Хотя последняя дельфи у меня работает на порядок стабильнее студии 2010.
0
pasha_golub #
Я связан договором о неразглашении, но выглядеть будет нативно и пиздато. Я уже видел. :)
0
abyss #
Супер!
Я правильно понял, что в новой версии будут полные и стабильные реализации c поддержкой IDE и прочего и 64 битов и Linux/Mac?
И ещё маленький вопрос: FireMonkey будет заменой VCL или они будут парарельно в дельфи или ещё как? Не получится ли, что понадобится переписывать программы.
0
pasha_golub #
Да, 32 и 64 бита, Винда и Мак… Линупса нету в списке. Обезьянка будет не заменой. Обезьянка — это библиотека для построения кроссплатформенных ГУЕв. То есть, если интересует только Винда, оставляем VCL. Если нацелились на все подряд, переделываем через FireMonkey.
0
ertaquo #
Free Pascal и IDE Lazarus. Они вполне кроссплатформенны. FPC поддерживает диалект Delphi. Минус FPC — недостаточная оптимизация, что ведет к увеличению размера программы. Но если писать не демки в 10 килобайт, а какую-нибудь более-менее серьезную программу, не сильно зависящую от ОС (то бишь не использующую специфические функции ОС), то все будет пучком.
+2
kekekeks #
Ну вы сравнили делфи с его VCL и фрипаскаль. Код на паскале можно и GCC компилить при желании, VCL от этого там не появится.
0
ertaquo #
В Lazarus есть набор классов, сходный с VCL. Недостающие можно довольно легко портировать или переписать.
+1
naum #
К сожалению, Lazarus очень сильно проигрывает любой версии Delphi в плане RTL/VCL: количество ошибок, стабильность в целом, функциональные возможности. Для крупных проектов он просто неюзабелен.
0
ncix #
Лазарус до чих пор напоминает какое-то школьное поделие. Напихали рюшек и финтифлюшек, а баги поправить — руки не дошли.
+5
AnatolyB #
Объявим структуру для хранения 20-ти байтов с порта (больше и не надо :))

type
TBuffer = array[0..20] of byte;

В этой структуре 21 байт.

function DecodeBarCode(buf: TBuffer; bufsize: integer): string;

Лучше описать, как const buf: TBuffer, незачем передавать буфер по значению.

Resive: TBuffer;

Слово пишется, как Receive.
0
aspanin #
Да, 21))) Спасибо

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.