Avatar billede js_delphi Nybegynder
10. maj 2011 - 14:23 Der er 14 kommentarer og
1 løsning

Hvordan detekteres stigende/faldende flanke smartest?

Hej,

jeg har ofte brug for at udfoere en kodestump idet en bit skifter fra false til true eller fra true til false.
Kodestumpen skal kun udfoeres idet skiftet har fundet sted, og skal derfor ikke udfoeres igen, hvis bit'en stadigvaek er true, naar programmmet kommer til dette sted i min kode igen.

Hidtil har jeg brugt en global variabel til at "huske" status paa bit'en, og saa sammenlignet denne vaerdi med den aktuelle.
F.eks.:

//Global variabel som "husker"
BitOld: Boolean;

//Timer1Timer event
if (BitOld <> BitActual) then //Et skift er sket!
begin
  Kodestump

  BitOld := BitActual; //Opdater
end;

Findes der en smartere maade at goere dette paa, saa man undgaar den globale variabel?
Avatar billede a_nor Nybegynder
10. maj 2011 - 16:01 #1
Har du kontrol over "det" der skifter BitActual ?
Avatar billede martinlind Nybegynder
10. maj 2011 - 16:40 #2
hvis det kun er en bit, kunne du jo bruge bitactual og så "flytte" lidt rundt på dine bits, huske den gl. værdi i bit2 og aktuelle i bit1, eller du kn lave et lille obj som du bruger i stedet for en boolean type.

alternativt kunne du også sætte dig ud og nyde solen og slukke computeren :-)
Avatar billede martinlind Nybegynder
10. maj 2011 - 16:40 #3
sagde manden der svarede....
Avatar billede js_delphi Nybegynder
10. maj 2011 - 16:44 #4
>>#1
BitActual bliver laest fra en ekstern styring, som mit program kommunikerer med.
Avatar billede kroning Nybegynder
10. maj 2011 - 17:17 #5
Prøv at kikke på property
Avatar billede js_delphi Nybegynder
10. maj 2011 - 18:21 #6
Hvad er der med property?
Avatar billede kroning Nybegynder
10. maj 2011 - 19:04 #7
Jeg bruger ofte property når når jeg har en del kode der skal udføres når en variabel ændres, det virker lidt smartere end blot at definere en global variabel.
Avatar billede a_nor Nybegynder
10. maj 2011 - 19:37 #8
Hvis ikke du kan få din "kommunikation" til at sende et interrupt, er der nok ingen vej uden timer-løsningen.
Avatar billede hrc Mester
10. maj 2011 - 22:10 #9
Du kan eventuelt bruge TBits som er en klasse der kan rumme en hel stribe bits. Så behøver du ikke lave nye boolske variable hver gang du føjer noget til. Statusværdien kan gemmes i registringsdatabasen (single-user) eller i en database (multi-user). ... eller i en fil sammen med exe-filen.

Jeg bryggede lige denne lille klasse sammen. Det der fylder mest (ca 60%) er, at værdierne kan gemmes til en fil via en stream og læses derfra på samme måde. Har taget det med for at vise hvor let det kan gemmes i en fil, registreringsdatabase eller et blob-felt i en database. Det er muligt TReader og TWriter ikke er smartest, men jeg bruger dem meget.

Hvis en bit sættes så tjekker den med den eksisterende værdi og hvis den er forskellig fyrer den et event af.

Jeg har også et lille testprogram hvis du er interesseret.

unit UBitclass;

interface

uses
  SysUtils, Classes;

type
  TOnBitChangeEvent = procedure(const aBitNo: integer; const aNewValue: boolean) of object;

  TBitActions = class
  private
    fBits: TBits;
    fOnBitChange: TOnBitChangeEvent;
    function GetBit(const aIndex: integer): boolean;
    procedure SetBit(const aIndex: integer; const Value: boolean);
  public
    constructor Create(const aSize: integer = 16);
    destructor Destroy; override;
    property OnBitChange: TOnBitChangeEvent read fOnBitChange write fOnBitChange;
    property Bit[const aIndex: integer]: boolean read GetBit write SetBit; default;
    procedure LoadFromStream(aStream: TStream);
    procedure SaveToStream(aStream: TStream);
    procedure LoadFromFile(const aFilename: string);
    procedure SaveToFile(const aFilename: string);
  end;

implementation

{ TBitActions }

constructor TBitActions.Create(const aSize: integer);
begin
  inherited Create;
  fBits := TBits.Create;
  fBits.Size := aSize;
  fOnBitChange := nil;
end;

destructor TBitActions.Destroy;
begin
  try
    fBits.Free;
  finally
    inherited;
  end;
end;

function TBitActions.GetBit(const aIndex: integer): boolean;
begin
  result := fBits[aIndex];
end;

procedure TBitActions.SetBit(const aIndex: integer; const Value: boolean);
var
  OldValue: boolean;
begin
  OldValue := fBits[aIndex];
  if OldValue <> Value then
  begin
    fBits[aIndex] := Value;
    if assigned(fOnBitChange) then
      fOnBitChange(aIndex,Value);
  end;
end;

// Gem- og hent-procedurerne kommer her.

procedure TBitActions.LoadFromFile(const aFilename: string);
var
  fs: TFileStream;
begin
  fs := TFileStream.Create(aFilename,fmCreate);
  try
    LoadFromStream(fs);
  finally
    fs.Free;
  end;
end;

procedure TBitActions.LoadFromStream(aStream: TStream);
var
  i: integer;
  Reader: TReader;
begin
  Reader := Treader.Create(aStream,100);
  try
    fBits.Size := Reader.ReadInteger;
    for i := 0 to fBits.Size - 1 do
      fBits[i] := Reader.ReadBoolean;
    Reader.FlushBuffer;
  finally
    Reader.Free;
  end;
end;

procedure TBitActions.SaveToFile(const aFilename: string);
var
  fs: TFileStream;
begin
  fs := TFileStream.Create(aFilename,fmOpenRead);
  try
    SaveToStream(fs);
  finally
    fs.Free;
  end;
end;

procedure TBitActions.SaveToStream(aStream: TStream);
var
  i: integer;
  Writer: TWriter;
begin
  Writer := TWriter.Create(aStream,100);
  try
    Writer.WriteInteger(fBits.Size);
    for i := 0 to fBits.Size - 1 do
      Writer.WriteBoolean(fBits[i]);
    Writer.FlushBuffer;
  finally
    Writer.Free;
  end;
end;

end.
Avatar billede hrc Mester
10. maj 2011 - 22:14 #10
Ahh. Det fylder ikke ret meget. Her er pas-filen. Dfm'en kan du sikkert gætte dig til:

unit FMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, UBitClass;

type
  TfrmMain = class(TForm)
    eBit: TEdit;
    chbValue: TCheckBox;
    btnSet: TButton;
    lbStatus: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure BitChanged(const aBitNo: integer; const aNewValue: boolean);
    procedure btnSetClick(Sender: TObject);
  private
    fBits: TBitActions;
  public
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.BitChanged(const aBitNo: integer; const aNewValue: boolean);
begin
  lbStatus.Items.Add(format('Bit: %.2d: value: %s',[aBitNo,BoolToStr(aNewValue,true)]));
  //  case aBitNo of
  //    0 :;
  //    1 :;
  //    2 :;
  //  end;
end;

procedure TfrmMain.btnSetClick(Sender: TObject);
begin // Nok dumt at bruge StrToIntDef; sætter bit 0 ved fejl
  fBits[StrToIntDef(eBit.Text,0)] := chbValue.Checked;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  fBits := TBitActions.Create;
  fBits.OnBitChange := BitChanged;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  fBits.Free;
end;

end.
Avatar billede js_delphi Nybegynder
25. juli 2011 - 09:13 #11
Hej, og undskyld den lange ventetid!

Bare lige for at fremme forstaaelsen:
Jeg har ikke brug for at erstatte min timer med events.
Min timer indeholder kode, som poller den eksterne styring med timerens interval (f.eks. hver 100ms).

//Timer1Timer event
  LaesVaerdierFraEksternStyring(og gem vaerdien her -> BitActual);

  if (BitOld <> BitActual) then //Et skift er sket!
  begin
    //Kode

  BitOld := BitActual; //Opdater
end;

Denne maade at polle paa er jeg egentlig godt tilfreds med.
Det, jeg ikke er helt tilfreds med, er maaden at detektere aendringer i de laeste vaerdier.

>>martinlind
Den datatype som laeses, er en boolean, saa ved at bruge en anden datatype som "mellemlagring", skal jeg loebende lave konvertering. Det tror jeg ikke bliver mere overskueligt end min eksisterende loesning med den globale variabel.

>>kroning
Mener du at definere den global variabel som en property i stedet, og saa bruge property'en internt i samme klasse, som den er defineret?
Jeg undgaar normalt at kalde en (ekstern) property internt.

>>hrc
Er det ikke for langsomt at gemme den sidste vaerdi i en fil eller registry, naar man taenker paa, at den skal laeses f.eks. hver 100ms?
En udfordring er ogsaa, at jeg skal detektere flanker i flere forskellige klasser. Saa skal jeg vel have en instans af TBits for hver klasse? Det tror jeg bliver for meget af det gode.
Interessant klasse den TBits ioevrigt :-)
Avatar billede hrc Mester
26. juli 2011 - 08:15 #12
Hvad er flanker? Du kunne også gøre (her) TBits-objektet globalt og referere til det fra alle dine klasser. Hvad har du så opnået i forhold til dine globale variable? Ikke ret meget, men det er dog bedre med et globalt objekt, for skal man gemme nye værdier, så er det nemt at tilføje dem til klassen fremfor istedet for at oprette endnu en ny global variabel. Man kan også tilknytte relevant logik til klassen.

Jeg bruger selv et global opsætningsobjekt der indeholder programmets opsætningsoplysninger. Ved programstart læses alle ind og værdier gemmes kun når de ændres. Jeg gemmer i en tabel så det er kun den enkelte record der opdateres. Hvis du gemmer oplysningerne i registry eller lignende, så kan man måske gøre det samme, men "normalen" er at man gemmer en klump data. Måske kan man overveje at gemme denne klump data ved programafslut (som eks. IE gør det), eller gøre det når Application.OnIdle trigges (med tjek på om data er ændret så der ikke gemmes unødigt).
Avatar billede js_delphi Nybegynder
07. januar 2012 - 19:08 #13
En stigende flanke opstaar, naar en boolean skifter fra false til true.
En faldende flanke opstaar, naar en boolean skifter fra true til false.

Det er disse skift, jeg skal kunne detektere.

Jeg er blevet ved min oprindelige maade at loese dette paa, men takker for den laererige feedback, som jeg sikkert kan bruge i andre sammenhaenge!

Laeg svar martinlind og hrc, og tak til alle andre :)
Avatar billede hrc Mester
07. januar 2012 - 19:21 #14
Svar
Avatar billede martinlind Nybegynder
24. januar 2012 - 18:25 #15
hvis det skal være rigtig OOP og som jeg skrev tidligere... kunne du jo lave et nyt "boolean" object og lave to properties på en værdi og en ændret som bliver sat hvis værdien er ændret i forhold til sidst ( altså bliver sat på dine flanker :-) )
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester