newbie / pins ansteuern und zeitdauer messen

Dies ist das deutsche Forum für alle Themen um den IO-Warrior. Beiträge bitte nur in Deutsch.

Moderator: Guido Körber

Post Reply
xilin
Posts: 8
Joined: Tue Mar 20, 2007 11:15 am

newbie / pins ansteuern und zeitdauer messen

Post by xilin »

hallo leute,

zunächst muss ich mal sagen, ich bin absolut neu hier im forum.
zu meinem problem:

ich bin durch mein studium auf den io-warrior gestoßen.
meine spezifiaktionen:
device: io-warrior56
OS: windows xp professional
programmierumgebung: delphi 2005

meine aufgabenstellung ist es nun, ein programm zu schreiben, das folgendes macht:
- pin 1 einschalten und wieder ausschalten
- pin 2 einschalten und wieder ausschalten
- pin 3 einschalten und wieder ausschalten
...
- die zeit von jedem schritt messen und aufsummieren
- eine durchschnittszeit für die schaltzeit von einem pin errechnen und diese dann ausgeben


delphi kannte ich noch aus der schule, aber ich muss sagen, ich habe nicht mehr viel ahnung davon.
ich habe auch schon die diversen pdfs gelesen, die es hier auf der seite gibt und auch auf der beigelegten cd sind.

ich habe schon einiges zustande gebracht, ich hoffe, das meine grammatik einigermaßen i.o. ist, komme aber bei der ansteuerung der einzelnen pins nicht mehr weiter, weil mir das mit den reports (report.value, report.bytes, ...) nicht ganz klar ist.

hier mein bisheriger programmcode:

Code: Select all

neuer code siehe antwort weiter unten

ich möchte jeden bitten, fehler, anregungen oder ähnliches zu posten, ich bin für jede antwort sehr dankbar.

außerdem habe ich noch das problem, dass ich das programm nicht starten kann, ich hoffe mir kann da auch jemand weiterhelfen.

mfg[/code]
Last edited by xilin on Tue Mar 20, 2007 4:41 pm, edited 2 times in total.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Fangen wir mal sicherheitshalber ganz vorne an:
Als erstes iowkit.dll nach Windows\system32 kopieren, damit die DLL auch immer gefunden wird.

iowkit.pas ist doch schon in die Unit eingebunden, also die Bereiche "//reports deklarationen" und "//funktionen und prozeduren deklaration" loeschen. Das wird ja von iowkit.pas zur Verfuegung gestellt.

Start und Ende sollten in FormCreate bzw. FormDestroy verlegt werden. Es macht nicht viel Sinn die Lade- und Initialisierungszeiten der DLL zu messen. Entsprechend fliegen die Aufrufe aus den ButtonClick-Events.

Button1Click ist ok.

In Button2Click muss es "if Number = 0 then" heissen.

In Button4Click muss es "report2: IOWKIT56_IO_REPORT" heissen! Der Typ PIOWKIT56_IO_REPORT ist ein Zeiger auf eine Report-Struktur. Das @ im IowKitRead-Aufruf liefert den benoetigten Zeiger auf die Struktur.
Die Zeile "report2.ReportID:=0;" kann entfallen, denn die ReportID wird wie die anderen Bytes gelesen.
Der Aufruf von IowKitRead() kommt natuerlich erst zurueck wenn sich etwas an den Pins aendert (Knopf auf der Platine druecken). Es fehlt der Ende-Aufruf (der entfaellt aber bei der Umarbeitung).

Button3Click ist voellig falsch. Ein IOWKIT56_IO_REPORT enthaelt gar kein Element Value.

Code: Select all

procedure TForm1.Button3Click(Sender: TObject);
var
  // ein record, nicht ein Zeiger auf ein record
  report: IOWKIT56_IO_REPORT;
  sent: ULONG;
  i: Integer;
begin
  Start;
  // die ReportID hat nichts mit der Pipe oder einem mode zu tun, immer 0 fuer die IO-Pins
  report.ReportID := 0;
  // die Bytes des Reports auf $FF initialisieren
  // das zieht alle Pins auf low (Achtung, die LED geht an!)
  for I := Low(report.Bytes) to High(report.Bytes) do
    report.Bytes[i] := $00;
  // alle Pins werden auf einmal geschrieben
  sent := IowKitWrite(IOW, IOW_PORTS_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
  Ende;
end;
Das sollte besser gehen.
xilin
Posts: 8
Joined: Tue Mar 20, 2007 11:15 am

Post by xilin »

hey robert,
vielen dank für deine kompetente und vor allem schnelle antwort.
so kann ich gleich probieren und basteln, ohne dass ich tage warten muss.

so, hier noch mal mein überarbeiteter code:

Code: Select all

siehe weiter unten!
ich hoffe so geht es nun einigermaßen.

ich habe aber vorerst mal noch eine frage zu button3:
werden da nicht alle pins nacheinander auf 0 geschaltet und erst dann die info an den IOW geschickt? müsste da nicht eine klammer hin, sodass er es dann nach jedem schalten schickt?
ich habe allerdings noch nicht ganz verstanden, wie das mit dem report.bytes funktioniert, ich schreibe einen wert rein, welche werte kann das annehmen und werden dann die kompletten bytes(ports) oder die einzelnen bits(pins) geschlatet?

mfg
Last edited by xilin on Tue Mar 20, 2007 6:06 pm, edited 1 time in total.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Nette Idee in FormCreate, aber das ist ein bischen gefaehrlich. Hat jemand den IOWarrior unauffindbar verschleppt, dann muss man das Programm totschiessen.

Die Bytes des Reports werden alle auf einmal an die IO-Pins geschrieben. Jedes Bit in den Bytes steht fuer einen IO-Pin. Je 8 IO-Pins werden Port genannt. Das ist aber nur eine kuenstliche Zusammenfassung (zumindest beim IOWarrior).

Will man einen einzelnen Pin schalten, so muss man das korrespondierende Bit in Report.Bytes auf 1 oder 0 setzen. Bitarithmetik ist angesagt.
Unbenutzte/unbeschaltete Pins setzt man auf 1, also unbenutzte Ports auf $FF.

Es empfiehlt sich vielleicht die JVCL von http://jvcl.sf.net zu installieren. Haufenweise nuetzliche Komponenten. Wichtig ist hierbei das die JCL auch dabei ist.
Hat man JCL und JVCL installiert, so genuegt es JclLogic in die uses-Liste aufzunehmen und man hat ein Sortiment von Bitmanipulationsfunktionen zur Verfuegung.
Das ist jetzt vielleicht ein bischen sehr viel Overkill, aber Hauptsache es hilft.
Nicht durch die JVCL-Komponenten ablenken lassen, sonst melden Sie sich erst naechstes Jahr zurueck :-)

Sollten Sie die HID-Komponente aus unserem SDK installiert haben, so muss diese vor der Installation der JVCL deinstalliert werden. Die Komponente ist auch in der JVCL enthalten und es wuerde zu einem Konflikt kommen.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Noch ein bischen allgemeines Funktionsprinzip.
Die Pins der IOWarrior sind nicht Ausgang oder Eingang, sondern immer beides.

Das mechanische Modell dazu ist das der IOWarrior den Pin in Ruhelage mit einer Feder hochzieht. Gibt man eine 0 aus, so zieht der IOWarrior von innen am Pin und es wird die Federkraft ueberwunden und der Pin nach unten gezogen. Gleiches kann man von aussen mit einer externen Schaltung machen. Da das Herunterziehen die Federkraft ueberwinden muss, wird zusaetzliche Energie verbraucht. Unbeschaltete oder unbenutzte Pins bleiben daher besser auf 1.
xilin
Posts: 8
Joined: Tue Mar 20, 2007 11:15 am

Post by xilin »

also robert, ich muss sagen, deine hilfen sind spitze und auch wirklich schnell!!!

hier nochmal mein aktueller code:

Code: Select all

neuer code unten!

das programm startet soweit, aber ich bekomme eine fehlermeldung wenn ich auf den open-button klicke.
war ircendein EAccesViolation oder Exception. hab ich leider ausgeschaltet, nun erscheint nur noch:
Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000
ich denke mal, dass da mit dem öffnen des IOW irgendwas nicht funktioniert?

weitere anregungen, ideen oder verbesserungsvorschläge sind jederzeit willkommen!

mfg
Last edited by xilin on Mon Apr 16, 2007 12:11 pm, edited 1 time in total.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Ich bin jetzt zuhause. Antwort gibts erst wieder morgen.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Der Absturz tritt bei mir nicht auf. Ist das moeglicherweise von einer Iteration des Testprogramms bei der LoadIowKitAPI noch nicht aufgerufen wurde?
Vor LoadIowKitAPI ist die DLL noch nicht geladen und alle IowKit-Funktionen ind noch nicht erreichbar und crashen in dieser Art. Das liegt daran das ich mich bei Delphi fuer das dynamische, explizite Laden der DLL entschieden habe. Das benoetigt einen funktionsaufruf, aber ist dafuer flexibler.

Hier die Source wie ich sie gerade getestet habe.

Code: Select all

unit unit1;

interface

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

type
//allgemeine deklarationen
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Label2: TLabel;
    procedure Button3Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
  public
    IOWarrior: IOWKIT_HANDLE;
    number: ULONG;
    return: ULONG;
    send: ULONG;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//............................................................................
//prozedur zum erstellen des programms

procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadIowKitAPI; //laden der API
  IOWarrior := IowKitOpenDevice;
  if not Assigned(IOWarrior) then //überprüfen, ob gerät angeschlossen
    FatalAppExit(0, 'No IOWarrior detected. Please connect one and start again.');
end;

//............................................................................
//prozedur, die die anzahl der aktuell aktiven devices ausgibt

procedure TForm1.Button1Click(Sender: TObject);
begin
  number := IowKitGetNumDevs;
  Label2.Caption := 'current: ' + IntToStr(number) + ' IOWarriors';
end;

//............................................................................
//prozedur, die signal auf pins gibt

procedure TForm1.Button2Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
  i: Integer;
begin
  report.ReportID := 0; //setzen der reportID
  for i := Low(report.Bytes) to High(report.Bytes) do //count auf jeden pin mit schreiben auf pin §00
    report.Bytes[i] := $00;
  send := IowKitWrite(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
  Label2.Caption := Format('%d Bytes written', [send]);
end;

//...........................................................................
//prozedur zum auslesen der ports

procedure TForm1.Button3Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
begin
  return := IowKitRead(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
  Label2.Caption := Format('%d Bytes read', [return]);
end;

//............................................................................
//prozedur die beim beenden API und geräte schließt

procedure TForm1.FormDestroy(Sender: TObject);
begin
  IowKitCloseDevice(IOWarrior);
  UnloadIowKitAPI;
end;

end.
Funktioniert einwandfrei. Nach dem Write bleibt allerdings das Read stecken. Das liegt daran das der Pin fuer den Knopf auf dem Starterkit wie alle anderen auf 0 gezogen wurde und daher kann der Knopf keine Aenderung mehr am Pin verursachen kann.

IowKitOpenDevice soll durchaus in FormCreate bleiben. Nur die Idee so lange zu versuchen einen IOWarrior zu finden bis einer vorhanden ist, ist problematisch. Ist der IOWarrior verschwunden (es gibt immer jemanden der ihn wegschleppt: Chef, Kollege, Kind, Hund, Putzfrau), dann bricht die Schleife nicht ab.
xilin
Posts: 8
Joined: Tue Mar 20, 2007 11:15 am

Post by xilin »

hallo leute,

so, nach einiger pause bin ich wieder am arbeiten und habe folgenden code entworfen, ist ziemlich ähnlich dem alten:

Code: Select all

siehe unten
jetzt habe ich wieder ein problem. ich kann das programm starten, funktioniert alles wunderbar.
aber wenn ich eine button klicke passiert gar nichts, bzw. es kommt bei den write-buttons die meldung: "zugriffsverletzung bei adresse 00000000. lesen von adresse 00000000"
was ist das, kann mir jemand weiterhelfen?
wird der warrior nicht geöffnet oder so?
Last edited by xilin on Mon Apr 16, 2007 4:54 pm, edited 1 time in total.
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Sieht soweit gesund aus. Koennen sie mir das ganze Delphi-Projekt direkt zusenden? marquardt at codemercs dot com
xilin
Posts: 8
Joined: Tue Mar 20, 2007 11:15 am

Post by xilin »

hey robert, du bist in sachen service einfach unschlagbar
das projekt schick ich dir gleich zu

ps: DU kannst auch gerne DU zu mir sagen ;-)
Robert Marquardt
Posts: 543
Joined: Mon Dec 01, 2003 6:09 pm

Post by Robert Marquardt »

Email angekommen, aber Anhang vergessen.
xilin
Posts: 8
Joined: Tue Mar 20, 2007 11:15 am

Post by xilin »

sorry, war mein fehler, ich hoffe jetzt passt alles. habe gerade eine neue mail
geschickt
xilin
Posts: 8
Joined: Tue Mar 20, 2007 11:15 am

Post by xilin »

so, ich hab nochmal einiges hinzugefügt,
funktioniert auch alles prima, nur die zeit stoppen für die schaltvorgänge ist etwas problematisch, da ich mich da nicht auskenne und keine anderen befehle als gettickcount kenne.
mir kommt es dabei vor, als ob der befehl einfach zu ungenau wäre, da es sich nur um einige ms handelt (vermute ich)

hier mein code:

Code: Select all

unit unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Math,
  iowkit, ExtCtrls;

type
//allgemeine deklarationen
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Label2: TLabel;
    Label1: TLabel;
    Button5: TButton;
    Button4: TButton;
    Edit1: TEdit;
    Label3: TLabel;
    Button6: TButton;
    Edit2: TEdit;
    Label4: TLabel;
    Edit3: TEdit;
    Button7: TButton;
    Timer1: TTimer;
    Label5: TLabel;
    procedure Button7Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  public
    IOWarrior: IOWKIT_HANDLE;
    number, return, send: ULONG;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//............................................................................
//prozedur zum erstellen des programms

procedure TForm1.FormCreate(Sender: TObject);
begin
  begin
    LoadIowKitAPI; //laden der API
    IOWarrior := IowKitOpenDevice;
    if not Assigned(IOWarrior) then //überprüfen, ob gerät angeschlossen
      FatalAppExit(0, 'No IOWarrior detected. Please connect one and start again.');
  end;

end;

//............................................................................
//prozedur, die die anzahl der aktuell aktiven devices ausgibt

procedure TForm1.Button1Click(Sender: TObject);
begin
  number := IowKitGetNumDevs;
  if number = 0 then
    Label2.Caption := 'no device connected'
  else
    Label2.Caption := 'current: ' + IntToStr(number) + ' io-warriors';
end;

//............................................................................
//prozedur, die signal "1" auf pins gibt

procedure TForm1.Button2Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
  i: Integer;
begin
  report.ReportID := 0; //setzen der reportID
  for i := Low(report.Bytes) to High(report.Bytes) do //count auf jeden pin mit schreiben von §FF
    report.Bytes[i] := $FF;
  send := IowKitWrite(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
end;

//...........................................................................
//prozedur, die signal "0" auf pins gibt

procedure TForm1.Button5Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
  i: Integer;
begin
  report.ReportID := 0; //setzen der reportID
  for i := Low(report.Bytes) to High(report.Bytes) do //count auf jeden pin mit schreiben von §00
    report.Bytes[i] := $00;
  send := IowKitWrite(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
end;

//...........................................................................
//prozedur zum auslesen der ports

procedure TForm1.Button3Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
begin
  label1.Caption := 'reading...';
  label1.Update;
  return := IowKitRead(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
  label1.Caption := Format('%d Bytes read', [return]);
end;

//...........................................................................
//prozedur zum schreiben von "1" auf einen eingegebenen port
procedure TForm1.Button4Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
  i, port: Integer;
begin
  port:=StrToInt(Edit1.Text);
  if (port>=0) and (port<=6)
    then
    begin
      report.ReportID := 0;                     //setzen der reportID
      report.Bytes[port]:=$FF;                   //schreiben von 1 auf "port"
      send := IowKitWrite(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
      label3.Caption:='wrote "0" to port ' + Edit1.Text;
    end
    else ShowMessage('port must be a number between 0 and 6')

end;

//............................................................................
//prozedur zum schreiben von "1" auf eingegebenen pin
procedure TForm1.Button6Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
  i, port, pin: Integer;
  a: Extended;
  b:String;
begin
  port:=StrToInt(Edit2.Text);
  pin:=StrToInt(Edit3.Text);
  if (port>=0) and (port<=6) and (pin>=0) and (pin<=7)
    then
    begin
      report.ReportID := 0;          //setzen der reportID
      if pin<4
        then a:=Power(2, pin)
        else a:=Power(2, pin) - (pin-3)*6;
      b:=FloatToStr(a);
      report.Bytes[port]:=$b;       //schreiben von 1 auf "port" und "pin"
      send := IowKitWrite(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
      label3.Caption:='wrote "0" to port ' + Edit1.Text;
    end
    else ShowMessage('port only: 0-6, pin only: 0-7')

end;

//............................................................................
//prozedur die "1"/"0" auf alle pins nacheinander schreibt
procedure TForm1.Button7Click(Sender: TObject);
var
  report: IOWKIT56_IO_REPORT;
  i, port: Integer;
  start, ende, zeit: TDateTime;

begin
  report.ReportID := 0;
  report.Bytes[0]:=$00;                     //setzen der reportID
  start:=GetTickCount;
  repeat
    report.Bytes[0]:=report.Bytes[0] + $01;
    send := IowKitWrite(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
  until report.Bytes[0]=$FF;
  repeat
    report.Bytes[0]:=report.Bytes[0] - $01;
    send := IowKitWrite(IOWarrior, IOW_PIPE_IO_PINS, @report, IOWKIT56_IO_REPORT_SIZE);
  until report.Bytes[0]=$00;
  ende:=GetTickCount;
  zeit:=ende-start;
  label5.Caption:=TimeToStr(zeit);

end;

//............................................................................
//prozedur die beim beenden API und geräte schließt

procedure TForm1.FormDestroy(Sender: TObject);
begin
  IowKitCloseDevice(IOWarrior);
  UnloadIowKitAPI;
end;

end.
zeit stoppen ist bei button 7, ideen werden gerne entgegengenommen.
außerdem habe ich versucht bei button 6 einzelne pins einzuschalten, funktioniert aber nur bedingt. die schwierigkeit sehe ich darin, dass ich die zahl des angesprochenen pins in dezimal eingebe, sie dann in hexadezimal umwandeln muss um sie in den report zu schreiben und die pins am warrior im prinzip aber sich wie dualzahlen verhalten (halt 1 oder 0). wer da ideen hat, sind auch gerne willkommen, ich habe mir schon einige gedanken gemacht, aber bisher war keine lösung dabei.

vielen dank
Post Reply