Pull to refresh

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

Reading time3 min
Views26K
Сегодня мы попробуем создать визуальный компонент для работы с разного рода считывателями, подключаемыми по 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)
Tags:
Hubs:
Total votes 27: ↑15 and ↓12+3
Comments30

Articles