AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Wie kann ich mit Delphi Daten vom USB-Controller abfragen?
Thema durchsuchen
Ansicht
Themen-Optionen

Wie kann ich mit Delphi Daten vom USB-Controller abfragen?

Offene Frage von "KRM"
Ein Thema von KRM · begonnen am 14. Apr 2007 · letzter Beitrag vom 14. Apr 2007
Antwort Antwort
KRM

Registriert seit: 6. Feb 2007
Ort: Kölle am Rhing
24 Beiträge
 
Turbo Delphi für Win32
 
#1

Wie kann ich mit Delphi Daten vom USB-Controller abfragen?

  Alt 14. Apr 2007, 09:29
Ok, ich hoffe, dass ich hier die richtige Rubrik getroffen habe...

Ich brauche eure Hilfe, weil ich wahrscheinlich den Wald vor lauter Bäumen nicht mehr sehe o_O...

Ih bastel an einem System mit einem Microcontroller, der IR-Daten empfängt und diese via USB an einen PC überträgt.
Auf dem PC läuft ein Delphiprogramm...

Die Treiber und alles sind vorhanden und es funktioniert in soweit, dass ich vom dem Delphi-Programm aus eine Abfrage über bestimmte Daten, wie z.B. die Firmwareversion machen kann, der Microcontroller diese beantwortet und das Delphi-Programm es anzeigt.

Nun ist es aber so, dass die IR-Daten, die ich übermitteln muss, nicht direkt auf Anhieb verfügbar sind...

D.h. ich habe also vor einen Button zu drücken, der im Microcontroller das Empfangen von IR-Daten scharf schaltet (funktioniert auch)...
Aber wenn er Daten empfangen hat, muss das Delphi-Programm das irgendwie mitbekommen...

Eine Systembeschreibung als Bild (erklärt es vllt noch verständlicher) hänge ich an

Nach der USB-Spezifikation ist es so, dass der Hostcontroller im PC ständig seine Schäfchen abfragt, ob neue Daten vorhanden sind... D.h. ein USB-Gerät kann keinen direkten Interrupt auslösen...

Beispiel: Eine USB-Maus wird mehrere hundert Male in der Sekunde abgefragt, ob sie neue Daten hat, da sie nicht schreien kann "EY, der User berührt mich!"...
Im Hintergrund muss dann irgendwo dieser Treiber laufen, der dann auf neue Daten reagiert und sie graphisch umsetzt...
Aber er weiß ja nie, WANN der Benutzer die Maus bewegen wird...


Wie kann ich denn nun mit Delphi auf den Host-Controller zugreifen um meine Daten abzufragen?
Mit der Treiber DLL?
Mit irgendeiner Windows Datei?
Muss ich in einer Schleife immer wieder via USB den Controller selbst abfragen?

Zum Anfang würde es mir reichen, dass das Delphi-Programm solange in einer Schleife wartet, bis der Controller Daten liefert und dann sagt "Neue Daten empfangen. Daten: ..."
Vllt müsste ich im Hintergrund dann nur einen Timer laufen lassen, falls eine Minute nichts empfangen wurde, dass er den ganzen Kram abbricht...

Btw: Gibt es in Delphi eine fertige Timer-Funktion, die man im Hintergrund laufen lassen kann und die einen Interrupt im Programm auslöst? Oder muss ich sowas mit einer while-Schleife umsetzen?


INFOS:

Die USB-DLL basiert auf http://www.sixca.com/delphi/article/microchip_usb.html
Genauer auf die von Sprut: http://www.sprut.de/electronic/pic/8...sb/usb_dll.htm

Auf http://sprut.de/electronic/pic/8bit/...50/usb2550.htm ist das bisher verwendete Delphi-Programm beschrieben!
Ich habe einfach noch ein Button dazu gebaut, dass momentan eben nur einen Code sendet, der das Starten des Microcontroller aktiviert.
Bei Sprut ist auch die Funktion SendReceivePacket erklärt, die zur USB-Kommunikation verwendet wird.


Code Beispiel: Auslesen der Firmware im Microcontroller
Delphi-Quellcode:
procedure TForm1.Button3Click(Sender: TObject);
var
   selection : DWORD;
   send_buf : PBYTE;
   receive_buf : PBYTE;
   RecvLength : DWORD;
   CurrentCMD : BYTE;
begin
  // Read Firmware version
  //instance ist warscheinlich 0, kann aber auch einen anderen Wert haben
  selection:=0;

  // sind USB-Devices vorhanden?
  if (_MPUSBGetDeviceCount(vid_pid)=0) then
  begin
    Memo1.lines.add('- Device not connected');
    exit;
  end;

  //pipes anfordern
  //für die instance=0
  //es kann aber passieren, da´ss instance<>0 !!
  //da ist noch nacharbeit nötig
  myOutPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_WRITE,0);
  myInPipe:= _MPUSBOpen(selection,vid_pid,out_pipe,MP_READ,0);
  //habe ich pipes bekommen?
  if ((myOutPipe = INVALID_HANDLE_VALUE) or (myInPipe = INVALID_HANDLE_VALUE)) then
  begin
    Memo1.lines.add('USB Error');
    exit;
  end;

  //Firmwareversion auslesen
  send_buf[0]:=READ_VERSION; [b]// READ_VERSION: Eine hexadezimale Konstante, die vom PIC interpretiert werden kann,
                                // worauf er in recieve_buf[3] und [2] seine Antwort hinein schreibt. (Ausgabe = 2.0)[/b]
  RecvLength:=4; [b]// Anzahl zu empfangener Bytes[/b]

  // HIER DAS IST DIE SCHLÜSSELFUNKTION ZUR ÜBERTRAGUNG ÜBER USB
  if(SendReceivePacket(send_buf,1,receive_buf,RecvLength,100,100) = 1) then begin
    if(receive_buf[0] = READ_VERSION) then begin
      Memo1.lines.add('Firmware version : '+ IntToStr(receive_buf[3])+'.'+IntToStr(receive_buf[2]));
    end;
  end
  else
  begin
    Memo1.lines.add('USB Error');
  end;

  _MPUSBClose(myOutPipe);
  _MPUSBClose(myInPipe);
  myInPipe:= INVALID_HANDLE_VALUE;
  myOutPipe:=INVALID_HANDLE_VALUE;
end; //Firmwareversion auslesen
Meine Funktion gibt einfach eine andere Konstante (READ_IR) über den USB und verlangt keine Antwortbytes (RecvLength:=0, wodurch im Microcontroller einfach nur eine Funktion gestartet wird.




Wenn ihr mehr wissen braucht, einfach fragen!





P.S.
Wenn sich nun einer fragt, was ich vom ihm will: Natürlich verlange ich keine komplette Lösung, wie ich das Problem lösen kann, aber über Anregungen würde ich mich freuen...
Ich beherrsche in Delphi nur Basics, also bin kein Delphi-Guru...
Aber ich denke ich bin lernfähig ...

DANKE im Voraus...
Miniaturansicht angehängter Grafiken
unbenannt_154.jpg  
  Mit Zitat antworten Zitat
Benutzerbild von Corpsman
Corpsman

Registriert seit: 8. Nov 2005
Ort: nähe Stuttgart
981 Beiträge
 
Delphi XE2 Professional
 
#2

Re: Wie kann ich mit Delphi Daten vom USB-Controller abfrage

  Alt 14. Apr 2007, 10:39
Also einen Timer gibt es in Delphi

nennt Sich TTimer und ist in der KarteiKarte System ( zumindest in D5 )
Uwe
My Sitewww.Corpsman.de

My marble madness clone Balanced ( ca. 70,0 mb ) aktuell ver 2.01
  Mit Zitat antworten Zitat
Benutzerbild von Daniel B
Daniel B

Registriert seit: 27. Okt 2005
Ort: Dachau
453 Beiträge
 
Delphi 2007 Professional
 
#3

Re: Wie kann ich mit Delphi Daten vom USB-Controller abfrage

  Alt 14. Apr 2007, 10:54
Kannst Du den PIC einen Buffer verpassen, vielleicht 4000Bytes, der die ganzen Werte zwischenspeichert und du bedienst dich aus dem Buffer alle, sagen wir 20ms?
Servus...
  Mit Zitat antworten Zitat
KRM

Registriert seit: 6. Feb 2007
Ort: Kölle am Rhing
24 Beiträge
 
Turbo Delphi für Win32
 
#4

Re: Wie kann ich mit Delphi Daten vom USB-Controller abfrage

  Alt 14. Apr 2007, 12:33
@Daniel B:

Der PIC hat einen 64 Byte großen Puffer, daran kann ich leider nichts einstellen... ...

@Corpsman:

Danke, ich werde die Information im Hinterkopf behalten...



---


Inzwischen habe ich ein wenig weiter gearbeitet...
Ich habe auf die Funktionen

_MPUSBWrite und
_MPUSBRead

für de USB-Kommunikation zurück gegriffen...
Gesendet wird mein Codewort READ_IR und der Pic reagiert darauf (mit einer leuchtenden LED)
Dann habe ich eine While-Schleife dahinter gesetzt, die prüft, ob Daten angekommen sind...
Und hey, das Programm springt nur raus, wenn auch welche gekommen sind.
(Habe es getestet, in dem ich im PIC ein Delay eingebaut hat, dass erst nach einer Weile 2 Datenpackete in die Buffer schreibt, die vom Delphi-Programm ausgelesen werden -> receive_buf)

Jedenfalls, jetzt wollte ich einen Timout einbauen, der in einem TLABEL oder einem TEDIT-Feld angezeigt wird.
ABER
Der macht das nicht...

Guggst du:

Delphi-Quellcode:
  
//Rumtesten
  send_buf[0]:=READ_IR; // Wird vom Microcontroller erkannt und er schaltet seine Interrupts ein
  RecvLength:=4; // Anzahl der erwarteten Bytes
  ExpectedReceiveLength:= RecvLength;

  if(_MPUSBWrite(myOutPipe,send_buf,1,SentDataLength,100)<> 0) then begin
    Memo1.lines.add('gesendet'); // wird ausgegeben, PIC reagiert
    receive_buf[2] := 0; // Voreinstellung, damit er nicht vorzeitig aus der Schleife gekickt wird
    TimeCounter := 10; // 10 Sekunden Timeout
                                     // wenn der µC in den Buffer schreibt, ist der Wert 52 soweit erst mal fest
    while((receive_buf[2] <> 52) AND (TimeCounter > 0)) do begin
                                     
      // Habe ich etwas empfangen? Nein = 0, dann "warte"
      if(_MPUSBRead(myInPipe,receive_buf,ExpectedReceiveLength,RecvLength,100)=0) then
      begin
        Memo1.Lines.Add("Warte": IntToStr(TimeCounter)); // Ausgabe des Timers im Memofeld
        Label2.Caption := IntToStr(TimeCounter); // Ein Label, in dem der Timer angezeigt werden soll
        sleep(900); // 100ms werden schon in der _MPUSBRead-Funktion gewartet
        TimeCounter:=TimeCounter-1;
      end
      else
        Memo1.lines.add('Empfangen'); // funktioniert auch, wenn der PIC seine Daten gesendet hat
    end;
    if TimeCounter = 0 then
      Memo1.lines.add('TIMEOUT!'); // funktioniert auch, wenn der Timer abgelaufen ist
    Memo1.lines.add('Firmware version : '+ IntToStr(receive_buf[3])+'.'+IntToStr(receive_buf[2]));
  end;

Die Zeit im Memofeld wird angezeigt, aber nicht im Label o_O...
Und auch, wenn ich das Label durch ein TEdit ersetze und die Zuweisung

Edit1.Text := IntToStr(TimeCounter); einbaue geht es nicht... -_-...

Jedoch, wenn "TIMEOUT!" ausgegeben wurde, setzt er das Label auf "1" o_O...
WARUM macht der das?
Und warum macht er nicht das, was er machen soll?


Jemand eine Idee?

Ich habe den Sleep-Befehl auch schon mal entfernt -> Ging auch nicht...




Im Anhang ein Screenshot der GUI
Miniaturansicht angehängter Grafiken
gui_163.jpg  
  Mit Zitat antworten Zitat
Reinhard Kern

Registriert seit: 22. Okt 2006
772 Beiträge
 
#5

Re: Wie kann ich mit Delphi Daten vom USB-Controller abfrage

  Alt 14. Apr 2007, 14:59
Hallo,

zur Kommunikation mit einem Mikrocontroller gibt es natürlich unabsehbar viele Möglichkeiten, und einige zig davon habe ich auch schon realisiert, daher ist meine Meinung:

Wenn du schon in der glücklichen Lage bist, das Protokoll auf beiden Seiten beeinflussen zu können, dann ist die übersichtlichste und sauberste Lösung, IMMER eine Antwort zu fordern. Ich würde also Anfragen über USB senden, die der Chip immer beantworten muss, entweder mit Daten oder mit der Antwort "habe gerade keine Daten". Das ist weitaus einfacher als mit Interrupts bzw. Events zu arbeiten - möglich ist das schon, schliesslich können ja die Serial-Adapter auch Events auslösen bei Datenempfang. So aber gibt es nur die einfache Transaktion Senden -> Antwort auswerten.

Daten im Chip zwischenzuspeichern, wie von jemandem empfohlen, ist nicht nur eine gute Idee, sondern eigentlich selbstverständlich.

Man kann die Übertragung optimieren, indem man nach Datenempfang sofort wieder anfragt, nach "keine Daten" erst nach längerer Pause, dann werden zwischengespeicherte Daten schnell übertragen, der Bus aber nicht mehr las nötig belastet.

Gruss Reinhard
  Mit Zitat antworten Zitat
Robert Marquardt
(Gast)

n/a Beiträge
 
#6

Re: Wie kann ich mit Delphi Daten vom USB-Controller abfrage

  Alt 14. Apr 2007, 15:12
Der Hostcontroller ist fuer Programme nicht zugaenglich und das ist auch gut so. Das Polling findet in Hardware statt und daher ist auf Anwendungsebene davon garnichts zu sehen. Ein USB-Geraet schickt Daten wenn es welche zu schicken hat. In diesem Fall sicherlich wenn man auf der IR-Fernbedienung einen Knopf drueckt. Das API bietet doch eine Funktion zum Lesen von Daten mit Timeout. Da startet man einen Thread der auf die Daten wartet und mit dem Timeout wacht der Thread periodisch auf, damit man ihn vorzeitig beenden kann auch wenn keine Daten kommen.
So mache ich es in meiner HID-Komponente und es funktioniert hervorragend.
  Mit Zitat antworten Zitat
Benutzerbild von fkerber
fkerber
(CodeLib-Manager)

Registriert seit: 9. Jul 2003
Ort: Ensdorf
6.723 Beiträge
 
Delphi XE Professional
 
#7

Re: Wie kann ich mit Delphi Daten vom USB-Controller abfrage

  Alt 14. Apr 2007, 15:24
Hi!

Zitat von KRM:
Die Zeit im Memofeld wird angezeigt, aber nicht im Label o_O...
Und auch, wenn ich das Label durch ein TEdit ersetze und die Zuweisung

Delphi-Quellcode: markieren
Edit1.Text := IntToStr(TimeCounter);



einbaue geht es nicht... -_-...

Jedoch, wenn "TIMEOUT!" ausgegeben wurde, setzt er das Label auf "1" o_O...
WARUM macht der das?
Und warum macht er nicht das, was er machen soll?


Jemand eine Idee?
Schau mal, ob dir ein Application.Processmessages weiterhelfen kann!
Ansonsten schaumal hier: DelayDelay - das ist besser geeignet als ein sleep!


Ciao, Frederic
Frederic Kerber
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz