Jump to content
Sign in to follow this  
Patz

Pause i Delphi

Recommended Posts

Først av alt, jeg er totalt amatør på dette, begynte såvidt å lese om Delphi i går.

 

Jeg tenkte jeg skulle lage et enkelt program for å styre stepmotorer fra paralellporten, og har til nå fått dette: (bruker inpout32.dll)

 

procedure TForm1.FormCreate(Sender: TObject);
label
 start;
begin
start:

 Out32($378,3);
 Out32($378,5);
 Out32($378,9);
 Out32($378,17);
 GOTO start;

end;

end.

 

Men jeg trenger en pause på f.eks 7ms mellom hver gang den sender ny verdi til paralellporten:

 

procedure TForm1.FormCreate(Sender: TObject);
label
 start;
begin
start:

 Out32($378,3);
 PAUSE 7ms
 Out32($378,5);
 PAUSE 7ms
 Out32($378,9);
 PAUSE 7ms
 Out32($378,17);
 PAUSE 7ms
 GOTO start;

end;

end. 

 

Hva er "kommandoen" for dette?

Edited by Patz

Share this post


Link to post

Du kan prøve ut timer componeten.

set interval på 7 - så sender den en handling hver 7ende ms.

for at den skal virke så må også enabled settes til true

 

hvis det er forskjelige verdier som sendes kan man bruke en variabel som økes med 1 hver gang en verdie er sendt og når man er kommet gjenomm alle så settes variabelen til 1 - og alt begynner på nytt

 

procedure TForm1.Timer1Timer(Sender: TObject);

begin

inc(teller)

if teller > 10 teller =1

 

case teller of

1:out(verdi1)

2:out(verdi2)

3:out(verdi3)

o.s.v.

 

 

end;

 

end;

 

variabelen teller må defineress i begynelsen av programet ditt

 

var

teller:integer;

Edited by elg-elg123

Share this post


Link to post

Har prøvd ut denne metoden nå, men det er et problem med den:

var
teller: integer;
variabel: cardinal;

function Inp32(wAddr:word):byte; stdcall; external 'inpout32.dll';
function Out32(wAddr:word;bOut:byte):byte; stdcall; external 'inpout32.dll';
procedure TForm1.Timer1Timer(Sender: TObject);

begin
variabel := 10;
Timer1.interval := variabel;
if teller = 4 then
teller := 1;
inc(teller);

case teller of
1:out32($378,6);

2:out32($378,3);

3:out32($378,9);

4:out32($378,12);

end;

end;

end.

Tror årsaken er denne:

Når teller = 1 så klarer ikke programmet å sende out32($378,6) før teller er kommet til 2.

 

Når teller = 0 så blir det en ekstra pause på 1ms mellon out32($378,12) og out32($378,6), noe som får motoren til å ga ujevnt (og saktere) ved høy fart (lite interval)

 

Noen ideèr?

Share this post


Link to post

ut ifra caseoperasjonen din så tolker jeg det slik at teller kun skal være fra 1-4? et potensielt problem er dersom teller =< 0 eller teller >=5, i det første tilfellet så vil caseoperasjonen bomme på x antall kjøringer, i det siste så vil den aldri(?) kjøre flere ganger. en bedre kontroll må til

 

initialiserer du teller før denne kodesnutten? du inkremeterer den før case, hadde vært penere å initialisere først, så inkremetere teller etter case.

 

en annen ting er at både teller og variabel (finn på et bedre navn?) er globale variabler, spørs om det hadde vært bedre med lokale variabler for prosedyren, evt. som argument for prosedyren dersom de blir brukt utenfor også.

Share this post


Link to post

Heisann. Føler at jeg må komme med noen tips her.

 

TTimer er uaktuell å bruke for applikasjoner som krever den nøyaktigheten du henviser til. Generelt sett vil dette knapt fungere i Windows på en Intel prosessor, nettop fordi prosessoren ikke er i stand til å utføre det du vil og at Windows ikke er et ekte MutliTaskin system.

 

Men som for alle regler finnes det unntak. Vi har spill som har høye krav og disse har spesielle timere i programkoden som tilfredstiller de høye kravene.

 

Måten å få til dette på er å lage en egen komponent derivert av TThread og bruke Sleep(1).

 

Du kan bruke GetTickCount() for å se hvor mange CPU cycles det går mellom hver operasjon. Hvis du googler litt vil du også finne endel eksempler på ThreadSafe timere som er adskillig bedre enn TTimer.

 

---

 

/pF

Share this post


Link to post
Ser at hele programmet "låser" seg under sleep, finnes det noe alternativ til dette som gjør at programmet fortsatt svarer?

5305162[/snapback]

 

Det låser seg fordi du har en uheldig og evigvarende løkk der.

 

Bruk heller noe sånt som

Repeat
 Out32($378,3);
 Sleep (7);
 Out32($378,5);
 Sleep (7);
 Out32($378,9);
 Sleep (7);
 Out32($378,17);
 Sleep (7);
 [B]Application.ProcessMessages;[/B]
Until Ferdig;

 

Ferdig kan (må) være en global variabel, eller tilhøre objektet.

Ferdig er i utgangspunktet satt til False, men endres f.eks. av å klikke på en knapp der du setter den til True.

 

Avhengig av hvor kjapp motoren er til å reagere, må du i verste fall bruke

Application.ProcessMessages;

for hver Out32.

 

Application.ProcessMessages gjør at programmet fanger opp et klikk på en stopp-knapp. Med bare en Application.ProcessMessages kan det hende at du må vente i noen sekunder før programmet reagerer.

 

Jeg regner med at stepmotoren ikke er så veldig tidskritisk heller, at du trenger spesialtimere til dette. Det er vel neppe et F-16 jagerfly som skal kontrolleres..

Share this post


Link to post

Har funnet en annen komponent som heter Sleeper, den fungerer mye bedre.

Legger ved hele programmet slik det er til dags dato.

unit Step;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, ComCtrls, ExtCtrls, Sleeper;

type
 TForm1 = class(TForm)
   EditInput: TEdit;
   EditPause: TEdit;
   ProgressBar1: TProgressBar;
   Headline: TLabel;
   UpDown1: TUpDown;
   ButtonClock: TButton;
   LabelM: TLabel;
   Sleeper: TSleeper;
   ButtonAntiClock: TButton;
   LabelFinished: TLabel;
   ButtonEmergency: TButton;
   procedure ButtonAntiClockClick(Sender: TObject);

   procedure ButtonClockClick(Sender: TObject);
   procedure ButtonEmergencyClick(Sender: TObject);






 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

// LABELDEKLARASJONER
//procedure TForm1.FormCreate(Sender: TObject);
//begin

//end;



function Inp32(wAddr:word):byte; stdcall; external 'inpout32.dll';
function Out32(wAddr:word;bOut:byte):byte; stdcall; external 'inpout32.dll';

//BEGYNNELSE: ROTER MED KLOKKE

procedure TForm1.ButtonClockClick(Sender: TObject);

var
 i, r, f, s: integer;  //I=input r=repeats f=FOR variabel s=sleep
 m: extended; //m=millimeter  s=sleep (ms)


begin

 i := StrToInt(EditInput.Text);
 m := i * 1.5; //1,5mm pr. runde på fres
 r := i * 50; // 200 (1 rotasjon) / 4 (4 step) = 50
 s := StrToInt(EditPause.Text);


begin

 for f := r downto 1 do //Gjennomfør variabel r


begin

  ProgressBar1.Position := (f);
 ProgressBar1.Position := f; //Progressbar følger FOR loop

 ProgressBar1.Max := r; //F er på starten = R
 ProgressBar1.Min := 1; //F teller ned til 1
 LabelFinished.Caption := 'AKTIV';
 Sleeper.SleepFor(s); //Sleep (s);
 Out32($378,12);   //Singlestep: 1
 Sleeper.SleepFor(s); //Sleep (s);
 Out32($378,9);   //Singlestep: 2
 Sleeper.SleepFor(s); //Sleep (s);
 Out32($378,3);  //Singlestep: 4
 Sleeper.SleepFor(s); //Sleep (s);
 Out32($378,6);  //Singlestep 8
end;
LabelFinished.Caption := 'VENT';
Sleeper.SleepFor(800);
Out32($378,0);


LabelFinished.Caption := 'PROSEDYRE GJENNOMFØRT, KLAR FOR NYE PULSER';

end;
end;



//BEGYNNELSE: ROTER MOT KLOKKE

procedure TForm1.ButtonAntiClockClick(Sender: TObject);

var
 i, r, f, s: integer;  //I=input r=repeats f=FOR variabel s=sleep
 m: extended; //m=millimeter  s=sleep (ms)


begin

 i := StrToInt(EditInput.Text);
 m := i * 1.5; //1,5mm pr. runde på fres
 r := i * 50; // 200 (1 rotasjon) / 4 (4 step) = 50
 s := StrToInt(EditPause.Text);
 // LabelM.Caption := m;


begin

 for f := r downto 1 do //Gjennomfør variabel r

begin

  ProgressBar1.Position := (f);
ProgressBar1.Position := f; //Progressbar følger FOR loop

 ProgressBar1.Max := r; //F er på starten = R
 ProgressBar1.Min := 1; //F teller ned til 1
 
 LabelFinished.Caption := 'AKTIV';
 Sleeper.SleepFor(s); //Sleep (s)
 Out32($378,6);   //Singlestep: 1
 Sleeper.SleepFor(s); //Sleep (s)
 Out32($378,3);   //Singlestep: 2
 Sleeper.SleepFor(s); //Sleep (s)
 Out32($378,9);  //Singlestep: 4
 Sleeper.SleepFor(s); //Sleep (s)
 Out32($378,12);  //Singlestep 8
end;
LabelFinished.Caption := 'VENT';
Sleeper.SleepFor(800);
Out32($378,0);
LabelFinished.Caption := 'PROSEDYRE GJENNOMFØRT, KLAR FOR NYE PULSER';

end;
end;





//Written by Pat, http://pat.selfip.com



procedure TForm1.ButtonEmergencyClick(Sender: TObject);
begin
Out32($378,0);
Halt;
end;

end.

Det er da litt kritisk at motoren faktisk gjennomfører alle step den blir bedt om, da det er en metall-fres som skal kontrolleres.

Application.ProcessMessages brukes altså dersom jeg skal stoppe programmet? (trøtt nå, skal se videre på det i morgen.)

 

EDIT: Leif

Edited by Patz

Share this post


Link to post

Application.ProsessMessages brukes ikke i og for seg til å avbrryte programmet, det må du gjøre med andre midler, f.eks. ved å klikke på en avslutningsknapp eller en tast på tastaturet.

 

Men opprinnelig hadde du motorkontrollen i en evigvarende løkke som det ikke var nubbtjangs å bryte inn i. Når du legger til Application.ProsessMessages så skjer dette: Windows får tid til å behandle andre hendelser (messages) i ditt program, hvis du museklikker på en knapp i ditt program, vil Windows klare å fange opp museklikket uten å være 100 % opptatt med løkka di. En Application.ProsessMessages gjør at Windows stopper opp et lite millisekund og spør seg selv "har det skjedd noe rundt omkring, enten i dette programmet eller i andre programmer, som jeg må være oppmerksom på?" Hvis ingenting har skjedd, så fortsetter løkka di en runde til, hvis det er kommet en message fra en knapp eller noe annet, vil windows behandle den, f.eks. sette en variabel til true, slik som i eksemplet mitt.

 

Jeg skjønner at det er litt kritisk hva stepmotoren driver med, så dette må du prøve ut i praksis for å se effekten av nøyaktigheten. Hvor langt "avbruddet" med en Application.ProsessMessages egentlig blir i praksis vil avhenge fra PC til PC, hvor kjappe de er.

Share this post


Link to post

Application.ProcessMessages() er enda mer intensiv og ødeleggende for en applikasjon enn Sleep().

 

En morsom illustrasjon:

 

...

procedure WndProc(Msg: TMessage); override;

...

 

TForm1.WndProc(Msg: TMessage);

begin

inherited;

Application.ProcessMessages;

end;

 

...

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...