LPT SEND – пример взаимодействия органов управления и сигналов
Ранее, еще в проекте “PortCoding”, мы рассматривали взаимодействия органов управления в программе. Теперь Вы приобрели опыт, наверняка накомпилировав из рассмотренных исходников, уйму полезных по хозяйству программ, следуя актуальному и сейчас принципу – в хозяйстве всё пригодится. А сейчас рассмотрим более сложный пример взаимодействия органов управления и сигналов, используя и расширяя накопленный ранее опыт
Рассмотрим программу “LPT SEND”
Изучив данную программу и разобравшись как она работает, для Вас не будет препятствий в разработке гибких в настройке приложений, со сложным и многофункциональным интерфейсом управления.
Программа состоит из неплохого передатчика последовательных импульсов, и двух простых контрольных приёмников для изучения принципа работы устройства. Передатчик основан на программируемом цикле счётчика:
for i:= 1 to N do где N – это число указывающее счётчику сколько раз надо повторять цикл. Например такой код:
[pas]for i:= 1 to 10 dobegin
ButtonPin2;
end;[/pas]
– десять раз устанавливает / снимает логическую 1 на ножке Pin2 LPT разъёма. А именно: пять раз устанавливает 1 и пять раз 0 . Поэтому, если нам требуется отправить десять единиц (положительных импульсов), необходимо число циклов умножить на два : for i:= 1 to N*2 do где N = 10.
Таким способом, мы программируем передатчик, следовательно он работает безошибочно. Скорость передачи регулируем традиционно – задержкой Sleep(миллисекунд). Приёмники импульсов – только учебные и не отличаются точностью приёма, уж очень много факторов на них влияет. Но на низких скоростях работают вполне удовлетворительно, чего вполне достаточно для изучения алгоритма.
Если в передатчике включен режим “Авто” – происходит автоматическая (в основном, но иногда сбоит) коррекция ошибок приёма. В общем, можно соединить два компьютера и проверить на практике, установив соответствующие биты и др. настройки. Но, попрактиковаться можно и сразу, внутри программы, как настроено всё по умолчанию.
Алгоритм таков: когда передатчик начинает передачу, например числа 10, он отсчитывает импульсы по Pin14 с помощью команды ButtonPin14. Одновременно появляется контрольный сигнал (назовём его CLK) на Pin16. Тогда приёмник, с помощью уже известного нам, простейшего счётчика импульсов, считает эти посылки, одновременно подтверждая принятый сигнал лог.1 передачей импульса по Pin2 ( при практической реализации можете сменить на входной – в приёмном коде передатчика, естественно). Передатчик,если включен “Авто”, принимает эти импульсы во время передачи. По окончании передачи снимается сигнал CLK и Pin16 переводится в лог. ноль. При этом приёмник заканчивает отсчёт и включает таймер, который сбрасывает счетчики в ноль и фиксирует LOG. Передатчик также проверяет, соответствует ли, полученное число переданному, и если нет – уменьшает скорость, начинает передачу заново, и так до тех пор, пока скорость станет таковой, при которой число передаётся без ошибок.
Это простейший алгоритм, разработанный специально для изучения начинающими. Здесь всё зависит от системных ресурсов, и работа в win9x и winXP – существенно отличается. В целом, в программе имеется еще много сложных взаимосвязей, а времени у меня не имеется, поэтому скачайте готовый исходник и изучите, следуя комментариям, там еще много полезных настроек, которые с успехом Вы можете применять в своих программах, как разберётесь.
{————— Программа LPT SEND : смотрим код —————}
[pas]{Универсальный переключатель – используйте в своих программах}function TForm1.Bits : boolean ; //–отслеживает переключения бит
(1-2-4-8-16-32-64-128)
Var
d : boolean;
bit : byte;
begin
bit := StrToInt(ComboBox3.Text); //– переключатель бит (согласно отдельно
взятому Pin)
d := true; {and – не инвертируется }
d := d and ((bit) = ((bit) and Lpt.ReadPort(GetCurrentPort,GetCurrentRegister)))
;
{Предусмотр. автоматическая инверсия инверсных бит рег. контроля – это: Pin1,
Pin14, Pin17}
if (ComboBox2.Text = ‘КОНТРОЛЯ’) then
if (bit = 1) or (bit = 2) or (bit = 8)then d := not d ; //– "or" – значит "или"
{Предусмотр. автоматическая инверсия инверсных бит входного рег. – это: Pin11}
if (ComboBox2.Text = ‘ВХОДЫ’) then
if (bit = 128) then d := not d ;
{ если выбран инверсный режим – инвертируем вручную всё}
if CheckBox1.Checked = true then d := not d ;
Bits := d;
end;
function TForm1.CLK : boolean ; //– позволяет инвертировать сигнал CLK
Var
d : boolean;
b : integer;
begin
b := StrToInt(ComboBox5.Text); //– установка бита
d := true;
d := d and (b = (b and Lpt.ReadPort(GetCurrentPort,2))) ;
if CheckBox3.Checked = false then CLK := d else CLK := not d;
end;
procedure TForm1.Timer1Timer(Sender: TObject); //– таймер индикации
begin
SpeedButton1.Enabled := Bits; //– управляем контрольным светодиодом
(встроенный в SpeedButton1)
SpeedButton3.Enabled := CLK; //– управляем контрольным светодиодом CLK
if CLK = false then
begin
SpeedButton6.Enabled := (CLK xor Bits) or (CLK and Bits) ; //– зажигаем если
неправильно настроенны биты RX
end;
end;
{Добавлена полезная проц. PinInfo, информ. о структуре LPT регистров и соотв.Pin}
procedure TForm1.PinInfo ;
begin
if ComboBox2.Text = ‘ДАННЫХ’ then
begin
if ComboBox3.Text = ‘1’ then StaticText1.Caption := ‘ Bit 2* = 1 : Pin2’;
if ComboBox3.Text = ‘2’ then StaticText1.Caption := ‘ Bit 2* = 2 : Pin3’;
if ComboBox3.Text = ‘4’ then StaticText1.Caption := ‘ Bit 2* = 4 : Pin4’;
if ComboBox3.Text = ‘8’ then StaticText1.Caption := ‘ Bit 2* = 8 : Pin5′;
if ComboBox3.Text = ’16’ then StaticText1.Caption := ‘ Bit 2* = 16 : Pin6′;
if ComboBox3.Text = ’32’ then StaticText1.Caption := ‘ Bit 2* = 32 : Pin7′;
if ComboBox3.Text = ’64’ then StaticText1.Caption := ‘ Bit 2* = 64 : Pin8’;
if ComboBox3.Text = ‘128’then StaticText1.Caption := ‘ Bit 2* = 128 : Pin9’;
end;
if ComboBox2.Text = ‘КОНТРОЛЯ’ then
begin
if ComboBox3.Text = ‘1’ then StaticText1.Caption := ‘ Bit 2* = 1 : Pin1’
else
if ComboBox3.Text = ‘2’ then StaticText1.Caption := ‘ Bit 2* = 2 : Pin14’
else
if ComboBox3.Text = ‘4’ then StaticText1.Caption := ‘ Bit 2* = 4 : Pin16’
else
if ComboBox3.Text = ‘8’ then StaticText1.Caption := ‘ Bit 2* = 8 : Pin17’
else
StaticText1.Caption := ‘ Не поддерживает ‘ ;
end;
if ComboBox2.Text = ‘ВХОДЫ’ then
begin
if ComboBox3.Text = ‘8’ then StaticText1.Caption := ‘ Bit 2* = 8: Pin15′
else
if ComboBox3.Text = ’16’ then StaticText1.Caption := ‘ Bit 2* = 16: Pin13′
else
if ComboBox3.Text = ’32’ then StaticText1.Caption := ‘ Bit 2* = 32: Pin12′
else
if ComboBox3.Text = ’64’ then StaticText1.Caption := ‘ Bit 2* = 64: Pin10’
else
if ComboBox3.Text = ‘128’then StaticText1.Caption := ‘ Bit 2* = 128: Pin11’
else
StaticText1.Caption := ‘ Не поддерживает ‘ ;
end;
end;
procedure TForm1.ComboBox3Change(Sender: TObject);
begin
PinInfo; //– вызываем процедуру при переключении бит
end;
procedure TForm1.ComboBox2Change(Sender: TObject);
begin
PinInfo; //– вызываем процедуру при переключении регистров
end;
procedure TForm1.SpeedButton2Click(Sender: TObject); //– кнопка "передача"
begin
Edit1.Text := ‘0’; //– обновить индикатор
TX; //– включ. передачу
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); //– прерываем циклы
begin
StopRX := true;
StopTX := true;
end;
{Внешний высокоскоростной приёмник "RX2" (Запустите вторую копию программы )}
procedure TForm1.RX2; //– режим приёмника 2
Var
a : integer;
begin
Edit3.Text := ‘0’;
StopRX := false; //–флаг стоп / старт
While not StopRX do //–бесконечный цикл, пока флаг стоп не поднят:
begin
a := 0;
{ ————– Счётчик импульсов1 (Биты задаются Bits )————–}
if Edit3.Tag = 0 then //– TAG = 0 : метка начала отсчета
begin
if Bits = true then
begin //– собственно счётчик
a := a + 1; //– фиксируем импульс
Edit3.Text := IntToStr(StrToInt(Edit3.Text)+1); // — принимаем импульсы
end;
Edit3.Tag :=1; //– TAG = 1 : метка конца отсчета
if a = 1 then ButtonPin2; // — подтверждаем приём импульса, с помощью Рin2
end;
if Bits = false then Edit3.Tag := 0; //– разреш. отсчёт след. импульса
{ ————– Счётчик импульсов2 <CLK> (Pin16 )————————–}
if Edit4.Tag = 0 then
begin
if CLK = true then Edit4.Text := IntToStr(StrToInt(Edit4.Text)+1);
Edit4.Tag :=1;
end;
if CLK = false then Edit4.Tag := 0;
{ ————————————————————————–}
Sleep(TrackBar1.Position); //–приложение засыпает на заданный интервал
Application.ProcessMessages; //–Обработка всей очереди сообщений
end;
end;
procedure TForm1.SpeedButton4Click(Sender: TObject); //– кнопка "СТОП" передачи
Var
a,b : integer;
begin
if SpeedButton4.Tag = 0 then //– если кнопка не заблокирована тогда:
begin
a := StrToInt(Edit1.Text) ; //– преобразуем
b := StrToInt(Edit2.Text) ; //– преобразуем
StopTX := not StopTX; //– "СТОП" передачи
Edit2.Text := IntToStr(b-a); //– устан. оставш. число для послед. передачи
SpeedButton4.Tag := 1; //– заблокировать дальнейшее применения кнопки
end else MessageBeep(MB_ICONEXCLAMATION);
end;
procedure TForm1.Timer3Timer(Sender: TObject); //– таймер сброса и ведения LOG
begin
if CLK = false then //– добавляем лог
begin
RichEdit1.Lines.Add (FormatDateTime(‘hh:mm:ss’, time()) +’ Принят код ‘ +
Edit3.Text);
Edit3.Text := ‘0’;
Timer3.Enabled := false;
end;
end;
procedure TForm1.Edit4Change(Sender: TObject);
begin
Timer3.Enabled := true; //– таймер сброса и ведения LOG – включить
end;
procedure TForm1.TX; //– Передатчик последовательных импульсов Pin14
Var
a,b,c,d, i : integer;
begin
{ автоматич. конролир. настройки бит по умолчанию }
if CheckBox4.Checked = true then
begin
if Pin16 = true then ButtonPin16;
if Pin14 = false then ButtonPin14;
if Pin2 = true then ButtonPin2;
end;
{Собственно передатчик импульсов}
d := 0 ;
Timer2.Enabled := false ; //– отключ. таймер после автокоррекции
Edit1.Text := ‘0’; //– обновить индикатор
Edit6.Text := ‘0’; //– обновляем
SpeedButton4.Tag := 0; //– разрешаем кнопку "Стоп"
a := StrToInt(Edit1.Text) ; //– преобразуем
b := StrToInt(Edit2.Text) ; //– преобразуем
c := StrToInt(ComboBox4.Text); //– преобразуем
Gauge1.MaxValue := b; //– настраиваем индикатор передачи (в %)
Gauge1.ForeColor := clBlue; //– показ.
StopTX := false ; //– флаг стоп / старт
for i:= 1 to b*2 do //– цикл передачи (Внимание : задаётся Edit2 !)
begin
if StopTX = true then exit; //– если наж. "Стоп" – прекращаем передачу
ButtonPin14; //– начинаем передачу импульсов Pin14 (передача 1 / 0)
if Pin14 = true then a := a + 1; // — контроль (подсчёт) переданных данных
(лог. 1)
Edit1.Text:= IntToStr(a); //– выводим результ. подсчёта
Gauge1.Progress := a; //– показ. переданное в %
{Передаём сигнал управления CLK – лог. 1}
Lpt.WritePort (GetCurrentPort,2,(c or Lpt.ReadPort( (GetCurrentPort) ,2) ));
if a = b then //– если цикл пройден :
begin
{Снимаем сигнал управления CLK – xor лог. 1 = 0}
Lpt.WritePort (GetCurrentPort,2,(c xor Lpt.ReadPort( (GetCurrentPort) ,2) ));
Gauge1.ForeColor := clScrollBar; //– убираем отработ. проценты индикатора ТХ
end;
{Используем повтор передачи, снижая скорость автоматически если ошибка приёма}
if CheckBox2.Checked = true then //– вкл. автокоррекцию скорости передачи
begin
if Pin2 = true then //– считаем ипульсы подтверждения приёма
begin
Edit6.Text := IntToStr(StrToInt(Edit6.Text)+1); //– счётчик импульсов
d := StrToInt(Edit6.Text); //– преобразуем и присваиваем
end;
{Если цикл передачи окончен, сигнал упр. отключён}
if CLK = false then
if (d <> a) and( d <> b) then //– если данные не совпадают:
begin {Увеличиваем задержку – уменьшаем скорость ТХ посылок}
TrackBar2.Position := TrackBar2.Position + 15 ; //– на нужное значение
Label7.Caption := ‘Контроль Данные Бит CLK Управление Задержка : ‘+
IntToStr(TrackBar2.Position); //– выводим значение задержки
Timer2.Enabled := true; //– вкл. таймер повтора ТХ
end else
begin //– если данные совпали – отключаем систему
beep;
Edit6.Text := ‘0’;
if d = b then Timer2.Enabled := false;
end;
end;
Sleep(TrackBar2.Position); //–приложение засыпает на заданный интервал
Application.ProcessMessages; //–Обработка всей очереди сообщений
end;
end;
{Простой внутренний контрольный приёмник "RX1"}
procedure TForm1.Timer4Timer(Sender: TObject);
Var
a : integer;
begin
a := 0;
{ ————– Счётчик импульсов1 (Биты задаются Bits )————–}
if Edit3.Tag = 0 then //– TAG = 0 : метка начала отсчета
begin
if Bits = true then
begin //– собственно счётчик
a := a + 1; //– фиксируем импульс
Edit3.Text := IntToStr(StrToInt(Edit3.Text)+1); // — принимаем импульсы
end;
Edit3.Tag :=1; //– TAG = 1 : метка конца отсчета
if a = 1 then ButtonPin2; // — подтверждаем приём импульса, с помощью Рin2
end;
if Bits = false then Edit3.Tag := 0; //– разреш. отсчёт след. импульса
{ ————– Счётчик импульсов2 (CLK )—————————-}
if Edit4.Tag = 0 then
begin
if CLK = true then Edit4.Text := IntToStr(StrToInt(Edit4.Text)+1);
Edit4.Tag :=1;
end;
if CLK = false then Edit4.Tag := 0;
{ ———————————————————————}
end;
procedure TForm1.RadioButton1Click(Sender: TObject); //– переключатель RX1
begin
Timer4.Enabled := true;
StopRX := true;
Edit3.Text := ‘0’;
end;
procedure TForm1.RadioButton2Click(Sender: TObject); //– переключатель RX2
begin
Timer4.Enabled := false;
RX2;
Edit3.Text := ‘0’;
end;
procedure TForm1.RadioButton3Click(Sender: TObject); //– переключатель OFF
begin
Timer4.Enabled := false;
StopRX := true;
Edit3.Text := ‘0’;
end;
procedure TForm1.TrackBar1Change(Sender: TObject); //– показ задержки
begin
if TrackBar1.Position = 0 then Edit3.Color := clyellow else
Edit3.Color := clInfoBk;
Label6.Caption := ‘Задержка RX2 м.сек : ‘ + IntTOStr(TrackBar1.Position);
end;
procedure TForm1.SpeedButton5Click(Sender: TObject);
begin
RichEdit1.Lines.SaveToFile(‘RX_Lod.txt’); //– сохраняем в файл
end;
procedure TForm1.TrackBar2Change(Sender: TObject); //– показ. задержку
begin
Label7.Caption := ‘Контроль Данные Бит CLK Управление Задержка : ‘+
IntToStr(TrackBar2.Position);
end;
procedure TForm1.Timer2Timer(Sender: TObject); //– таймер повтора передачи
Var
b,d : integer;
begin
b := StrToInt(Edit2.Text) ; //– преобразуем
d := StrToInt(Edit6.Text) ; //– преобразуем
SpeedButton2.Click ;
if (d = b) then //– отключ. автоматически
Timer2.Enabled := false ;
end;
end.
end;[/pas]
Cкачайте этот пример – primer_xp06.zip(30 kb)
Cкачать готовую программу – LPT SEND : lptsend.zip (207 kb)