Сегодня мы попробуем создать визуальный компонент для работы с разного рода считывателями, подключаемыми по COM-порту (правильное название интерфейса – RS232). Наша цель — получать последовательность байт, которую отправляет устройство при считывании.
Начнем с создания нового проекта типа Delphi Component:
В следующем окне выберем TEdit в качестве родительского компонента.
Напоследок, дадим звучное имя нашему будущему компоненту – TRS232Edit и поместим его в набор MyComponents палитры компонентов (RS 232 — наименование стандарта).
После нажатия Finish назовем модуль компонента uRS232Edit.pas и сохраним его. Среда разработки автоматически сформирует такой шаблон:
Объявим структуру для хранения 20-ти байтов с порта (больше и не надо :))
Начинаем закладывать функционал. Для начала объявим в секции private класса TRS232Edit переменные, в которых будем хранить параметры соединения с портом.
Ещё нам понадобятся
и в секции public
Инициализировать соединение с портом будем вызовом метода Init. В нем присываиваются парамерты внутренним переменным, выставляются начальные значения и вызывается метод непосредственно коннекта.
Наибольший интерес здесь представляет метод PortInit — разберем его детально
Прием данных происходит в процедуре ReadComm
Всё. Компилим, устанавливаем. Чтобы считываение запустилось, в тестовом приложении достаточно приписать что-то вроде
Начнем с создания нового проекта типа Delphi Component:
В следующем окне выберем TEdit в качестве родительского компонента.
Напоследок, дадим звучное имя нашему будущему компоненту – TRS232Edit и поместим его в набор MyComponents палитры компонентов (RS 232 — наименование стандарта).
После нажатия 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)