Autor |
Beitrag |
boondockduckling
Hält's aus hier
Beiträge: 4
|
Verfasst: Mo 14.01.08 14:56
morgen
ich bin etwas am verzweifeln. Ich versuche eine 16-Bit Datenausgabe über den LPT an einen Schieberegister zu verwirklichen. (Für neugierige: Ist der Schieberegister eines MAX7221 ICs)
Die Ausgabe läuft über eine "io.dll" (->google) mit dieser Prozedur:
Delphi-Quelltext 1:
| procedure PortOut(Port : Word; Data : Byte); stdcall; external 'io.dll'; |
Das funktioniert auch definitiv!
Meine Schaltung hängt am LPT-Pin 1,2,3.
1: Clock
2: Load
3: Data
nachtrag: p.s. pin1 ist datenpin0(wert 1), pin2 datenpin1(wert 2) und pin3 datenpin2(wert 4)
Der Schieberegister wird beschrieben indem man Load auf Low setzt und die 16Bit folge über Clock und Data übergibt. D.h. möchte man eine logische 1 übergeben setzt man 1+3 auf High, bei einer logischen 0 setzt man nur 1 auf High. Anschließend wird alles wieder auf Low gesetzt und zum nächsten Bit übergegangen. Nach dem 16.Bit wird Load wider auf High gesetzt und der Schieberegister ist beschrieben.
Das Problem: "Manuell" klappt es!! Ich habe mir 3 checkboxen erstellt, je eine für einen Pin. D.h. ich kann Pin1-3 in allen Kombinationen auf High/Low setzen.
Testweise übergebe ich diese Bitfolge: [0000 1010 0000 0000]
Wenn ich das manuell mache, also über die 3 Checkboxen einzelnd die Bits setze, klappt es. Ich bekomme es aber einfach nicht fertig das in eine Prozedur zu packen die das für mich übernimmt....
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| Pin2 auf Low -> Pin1 auf High -> Pin1 auf Low //1 (log. 0) -> Pin1 auf High -> Pin1 auf Low //2 (log. 0) -> Pin1 auf High -> Pin1 auf Low //3 (log. 0) -> Pin1 auf High -> Pin1 auf Low //4 (log. 0)
-> Pin1+Pin3 auf High -> Pin1+3 auf Low //5 (log. 1) -> Pin1 auf High -> Pin1 auf Low //6 (log. 0) -> Pin1+Pin3 auf High -> Pin1+3 auf Low //7 (log. 1) -> Pin1 auf High -> Pin1 auf Low //8 (log. 0)
-> Pin1 auf High -> Pin1 auf Low //9 (log. 0) -> Pin1 auf High -> Pin1 auf Low //10(log. 0) -> Pin1 auf High -> Pin1 auf Low //11(log. 0) -> Pin1 auf High -> Pin1 auf Low //12(log. 0)
-> Pin1 auf High -> Pin1 auf Low //13(log. 0) -> Pin1 auf High -> Pin1 auf Low //14(log. 0) -> Pin1 auf High -> Pin1 auf Low //15(log. 0) -> Pin1 auf High -> Pin1 auf Low //16(log. 0)
-> Pin2 auf High |
Wie gesagt wenn ich das manuell über die Checkboxen mache funktioniert es
Und mit folgendem, total dämlichen code, muss es doch funktionieren? Ich habe im prinzip genau das hingeschrieben was ich manuell mit den Checkboxen mache.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65:
| procedure TForm1.Button8Click(Sender: TObject); var d:integer; begin d:=100; PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,5); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,5); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,1); delay(d);
PortOut($378,0); delay(d); PortOut($378,2); delay(d);
end; |
Hier noch der Delay-Code. Tut aber eigentlich nichts zur Sache.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure Delay(Milliseconds: Integer); var Tick: DWord; Event: THandle; begin Event := CreateEvent(nil, False, False, nil); try Tick := GetTickCount + DWord(Milliseconds); while (Milliseconds > 0) and (MsgWaitForMultipleObjects(1, Event, False, Milliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do begin Application.ProcessMessages; if Application.Terminated then Exit; Milliseconds := Tick - GetTickcount; end; finally CloseHandle(Event); end; end; |
Moderiert von Narses: Delphi-Tags hinzugefügt und Tiepvelher im Titel korrigiert
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 14.01.08 20:12
Moin und  im Forum!
Bei so einem Ladevorgang sollte man üblicherweise dieses Timingverhalten produzieren:
Quelltext 1: 2: 3: 4: 5:
| /Load -\__________________________________/-
Data __/---\_________/---\_________/---\___
Clock ___/-\____/-\____/-\____/-\____/-\____ | Bist du sicher, dass dein Timing die Definitionen für das Data- und Clock-Timing einhält?
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
oldmax
      
Beiträge: 380
D3 Prof, D4 Prof
|
Verfasst: Mi 16.01.08 07:11
Hi
Nun ja, vielleicht hilft ja das....
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
| Var Testwert : Word; Ablage : Word; ZW : Word;
Testwert :=$2321 Ablage:= Testwert; ZW:=$0002; PortOut($378,ZW); delay(d); For i:=1 to 16 do begin ZW:=$0002; ZW:=Ablage and $0001 ZW:=ZW or $0002 PortOut($378,ZW); delay(d); ZW:=ZW or $0004; PortOut($378,ZW); delay(d); ZW:=ZW and $FFFB; PortOut($378,ZW); delay(d); ASM LD AH,Ablage SHR AH, 1 Ld Ablage,AH end; end; ZW:=$0000; PortOut($378,ZW); delay(d); |
Dabei ist zu beachten, das das Data- Bit immer Bit 0 ist. Dem entsprechend muß LPT Bit 0 angepaßt sein, die anderen beiden Bits sind eventuell zu tauschen. Ich hab leider die Hardwarebeschaltung vom LPT nicht im Kopf.
Sollte das Data -Bit nicht auf LPT-Bit 0 geschaltet sein, so kann man durch eine ASM nach dem Doppelstern die Ausgabe anpassen
Delphi-Quelltext 1: 2: 3: 4: 5:
| ASM Ld AH,ZW SHL AH,n Ld ZW,AH end; | Danach werden die Load- und Clock-Bits entsprechend gesetzt
übrigends, die SHR Funktion kommt einem
Wert:=Trunc(Wert/2);
gleich, die SHL Funktion einem
Delphi-Quelltext
Mit diesen Zeilen dürfte dein Word serialisiert sein.
_________________ Zier dich nich so, ich krieg dich schon....
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Mi 16.01.08 10:42
Hallo,
laut Datenblatt pdfserv.maxim-ic.com.../MAX7219-MAX7221.pdf Seite 6 timing sollte
1. Die Uhr erst 25 ns nach der Auswahl des Chips (ChipSelect) starten
2. die Daten mindestens 25 ns (t DS time DataSetup ) vor der steigenden Flanke des Clock-Signals stabil sein.
Zitat: |
CS Fall to SCLK Rise Setup Time (MAX7221 only) tCSS 25 ns
DIN Setup Time tDS 25 ns
DIN Hold Time tDH 0 ns.. |
Da Clock min 50 ns auf Low und 50 ns auf High sein muss
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| Also erst Chip auswählen.(Alles auf low CS,Data,Clk)
wiederhole 16 mal : Datenleitung auf nächstes Datenbit setzten min. 50 ns warten Clk von low auf High (Daten werden mit steigender Flanke übernommen deshalb tDH= 0 ) min.50 ns warten Clk von High auf low Chip abwählen CS auf High |
Bei meinem PC kann ich maximal mit 20 Mhz direkt auf den Port zugreifen (Win98 Turbo Pascal). Das sind schon 50 ns pro Zugriff.
Es ist die Frage,ob ein delay(??) für 50 ns Verzögerung dann überhaupt nötig sind.
So wie es oldmax angegeben hat, sieht es schon sehr passend aus.
Es gibt ja auch Beispiele von MAXIM pdfserv.maxim-ic.com/en/an/AN2782.pdf
WIn Nt/XP.etc www.maxim-ic.com/ima.../2782/MAX7219-NT.exe
oder Win98..WinMe www.maxim-ic.com/ima.../2782/MAX7219-21.EXE
Gruß Horst
|
|
oldmax
      
Beiträge: 380
D3 Prof, D4 Prof
|
Verfasst: Mi 16.01.08 11:08
hi
Ich brauch doch so langsam eine Brille. Das Load Signal hat es mit heut wirklich angetan.. .Es muß natürlich während der Übertragung von High nach Low und danach wieder auf High gelegt werden. Sorry, mein Fehler.
Gruß oldmax
_________________ Zier dich nich so, ich krieg dich schon....
|
|
boondockduckling 
Hält's aus hier
Beiträge: 4
|
Verfasst: Mi 16.01.08 12:04
hi
vielen dank soweit
also erstmal ja ich hatte das Timingverhalten nicht beachtet. Ich habe von jemand anders einen ähnlichen Code wie den von oldmax bekommen. Nach anfänglichen Problemen hat es jetzt aber funktioniert.
@Horst_H
Das Programm von Maxim kenne ich, es hat mir soweit auch viel geholfen.
Ich geb hier mal den funktionierenden Code dazu, ist von Muetze1 aus Delphipraxis, falls mal jemand über die Suche hierher gelangt.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47:
| procedure Tform1.WriteWord(const APort: Word; const AData: Word); const CLOCK = 1; LOAD = 2; DATA = 4; var d: integer; i: integer; lData: Word; lPortData: Byte; lBit: boolean; begin d:=10;
lData := AData;
Portout(APort, LOAD); Delay(d); Portout(APort, 0);
for i := 0 to 15 do begin lBit := ( lData and $8000 ) <> 0; lData := lData shl 1; if lBit then lPortData := DATA else lPortData := 0;
Portout(APort, 0); delay(d); Portout(APort, lPortData); delay(d); Portout(APort, lPortData or CLOCK); delay(d); Portout(APort, lPortData); end;
Portout(APort, LOAD); end; |
|
|
Horst_H
      
Beiträge: 1654
Erhaltene Danke: 244
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Mi 16.01.08 13:25
Hallo,
Du schreibst im DelphiPraxis-Forum , dass du bis 5 ms delay herunter gehen kannst.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| Portout(APort, 0); delay(d); Portout(APort, lPortData); delay(d); Portout(APort, lPortData or CLOCK); delay(d); Portout(APort, lPortData); |
Das ist immer noch mächtig langsam.Minimal 15 ms pro Bit also ca 4 Word's pro Sekunde.
Wie schon geschrieben, werden die Daten im Augenblick des Wechsels des Clocksignals von Low auf High übernommen.
Deshalb ist
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| For ... begin .... Portout(APort, lPortData ); delay(d); Portout(APort, lPortData or CLOCK); delay(d); end; Portout(APort, LOAD); |
sicherlich schon ausreichend und schonmal 50% schneller, aber weit von den Möglichkeiten der Hardware entfernt.
Ich vermute, dass Du im BIOS den Parallelport noch auf EPP oder ECP umstellen musst, damit es schneller gehen kann.
Halt,Stopp Du bekommst ja nur Zeitscheiben zugewiesen, die Du in deinem delay abgibst. Dein Programm bekommt also nur alle paar Millisekunden wieder Zugriff.
Ich würde es einfach mal komplett ohne Delay versuchen, also nicht einmal delay(0) .
Gruß Horst
|
|
boondockduckling 
Hält's aus hier
Beiträge: 4
|
Verfasst: Mi 16.01.08 14:39
Ja das mit den 5ms stimmt so nicht ganz. Bei dem jetzigen Code sind es 8ms. Bei meinem ersten Test waren es noch 5ms. So oder so ... beides langsam.
Und richtig, die Delay Prozedur begrenzt das ganze nicht meine Hardware.
Wenn ich aber Delay auf 0 schalte passiert garnichts.
Bevor ich den MAX7221 verwendet habe hatte ich zwei LED-Matrizen direkt über Schieberegister im Multiplexingmodus angesprochen. D.h. einen 8-Bit Register für die 7 Reihen und zwei 8-Bit Register für die 10 Zeilen (zwei Matrizen in Reihe).
Vereinfacht funktioniert das so: Man schreibt die jeweiligen Daten in den Reihenregister und aktiviert die Zeile durch den Zeilenregister. Dann werden in den Reihenregister die Daten für die nächste Zeile geschrieben und diese aktiviert. Dies 10 Mal hintereinander und dann gehts wieder bei der ersten Zeile los. Durch eine entsprechende Geschwindigkeit ergibt sich ein Bild.
Weswegen ich zu Beginn meiner Probleme so verwirrt war ist die Tatsache dass ich das Ansteuern dieser Schieberegister problemlos hinbekommen habe. Einzig habe ich nie verstanden warum meine ausgegebenen Bits um 1 Bit versetzt im Schieberegister aufgenommen werden. Das habe ich nicht weiter beachtet und schlicht die Ausgabe angepasst.
Diese Schaltung hängt direkt am LPT und kommt seltsamerweise mit einem Delay von 1ms aus. Und zwar pro komplettem Displaydurchlauf insgesamt! Ich glaube selbst der Delay von 1ms ist nicht nötig, aber ansonsten hängt sich das Programm auf.
In der Zeit werden 10*7 Bit in den Register für die Reihen geschrieben und 10*1 Bit in den Zeilen-Register. Also 80 Bit.
Die tatsächliche dauer der 1ms entspricht wohl kaum einer echten Millisekunde aber trotzdem funktioniert es wesentlich schneller also momentan bei dem MAX.
Der alte Aufbau ist halt leider a) unpraktisch (6 Datenleitungen, je länger das Display desto langsamer wird der Multiplexingbetrieb) und b) abhängig von der Prozessorauslastung. D.h. die anzeige flackert manchmal oder hängt kurz wenn ich meinen PC auslaste.
Was ich damit aber eigentlich ausdrücken will... eine Hardwaremäßige Begrenzung liegt hier nicht vor.
Ein Problem ist vielleicht die Störanfälligkeit der Übertragung: Während es bei meiner alten Variante egal ist ob jedes Bit korrekt übertragen wird (bei einer "theoretischen" Bildwiederholrate von 1000Hz sieht man ein paar Falsche Bits nicht), braucht der MAX bei jeder Übertragung korrekte Bit-Folgen oder er spinnt rum. (manchmal hängt er sich auch auf wenn zu viel Mist ankommt.)
|
|
Waldheini
      
Beiträge: 32
Win 98SE, XP
D5 St., K3 Prof
|
Verfasst: Mi 16.01.08 21:18
Hi,
kann es sein, das die Probleme mit falscher Beschaltung des LPT-Ports zusammenhängen?
Zitat: |
Meine Schaltung hängt am LPT-Pin 1,2,3.
1: Clock
2: Load
3: Data
nachtrag: p.s. pin1 ist datenpin0(wert 1), pin2 datenpin1(wert 2) und pin3 datenpin2(wert 4)
|
Soweit ich weiß ist Pin 1 Strobe (bei Low-Pegel sind die Daten D0-D7 gültig und können übernommen werden), D0-D7 sind die Pins 2-9.
|
|
boondockduckling 
Hält's aus hier
Beiträge: 4
|
Verfasst: Mi 16.01.08 21:27
och hoppla...
ich hab mich nur falsch ausgedrückt, es müsste heißen LPT-Datenpin1,2,3.
Also die Schaltung selbst hängt an Pin 2,3,4.
Immer diese Details
P.s. es funktioniert aber soweit.... nur langsam ist es.
|
|
oldmax
      
Beiträge: 380
D3 Prof, D4 Prof
|
Verfasst: Do 17.01.08 13:41
Hi
Mal eine Frage, sind dir Applicationen bekannt, wo die Übertragung schneller geht ? Dann kann es sein, das du das Timing der Signale nicht optimal beachtest. Es ist oft so, das sich Signalpegel nicht mit der Zuweisung an den Port sofort und schlagartig ändern, sondern eine Anstiegsflanke haben. Bei langen Leitungen kommen noch induktive und kapazitive Einflüsse hinzu, so das du dies einkalkulieren solltest. Deine Delayzeit ist aber nicht unbedingt das Problem. Wenn du Clock und Data-Signal gleichzeitig aufschaltest, ist es egal, wieviel Dalay, da ist nach wie vor die Anstiegszeit und evtl. hast du auch da schon ein paar Fehlübertragungen. Versuch doch mal folgendes:
Zuerst legst du das Load-Bit auf und sorgst dafür, das es auch immer mit übertragen wird, solange ein Datensatz gesendet wird. Dann schaltest du das Datenbit auf und erst danach setzt du ein Clock. Nun kann eine kurze Delay-Zeit probiert werden. Dann nimmst du Clock wieder weg und beginnst mit dem nächsten Daten- Bit.
nunn zu deiner Frage, ob man beliebig viele Bits hintereinander hängen kann. (hab ich mal aus DP mitgebracht)
Wenn du deine Bitfolge in einen String packst ('01001110110.....'), so kannst du jedes einzelne Zeichen von Length(Bitstr)-i holen und senden. Da ist die Idee mit den Constanten gar nicht so übel...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| Procedure Init_Max; Const Not_LoadBit = 1; Var Ausgabe: Byte; Begin Ausgabe:=0; Ausgabe:=Ausgabe or Not_Loadbit; PortOut($378,Ausgabe ); end; |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| Procedure Sendedaten(Bitfolge : String); Const Databit =4; Clockbit =2; NoClock = $FD; Var Ausgabe : Byte; i : Integer; begin Ausgabe:=0; For i:=0 to Length(Bitfolge)-1 do begin Ausgabe:=0; PortOut($378,Ausgabe ); If BitFolge[Length(Bitfolge)-i]='1' then Ausgabe:=Ausgabe or DataBit; PortOut($378,Ausgabe ); Ausgabe:=Ausgabe or ClockBit; PortOut($378,Ausgabe ); Ausgabe:=Ausgabe And NoClock; PortOut($378,Ausgabe ); end; end; |
Wenn du die Werte in Word-Variablen hast, z.B. in einem Array of Word, dann kannt du dir eine Function basteln, die aus einem Word einen String macht, entsprechend der Bitfolge
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| Function TMyForm.WordToStr( Wert : Word): String; Var Ausg : String; Calc : Word; Begin Ausg:=''; Calc:=Wert; Repeat if Calc/2 = Trunc(Calc/2) then Ausg:='0'+Ausg else Ausg:='1'+Ausg; Calc:=Trunc(Calc/2); until Calc=0; While Lenght(Ausg) <16 then Ausg:='0'+Ausg; Result:=Ausg; end; |
Deinen Sendestring setzt du zusammen über
Delphi-Quelltext 1: 2: 3: 4:
| Sendestring:=''; For i :=1 to AnzSendeworte do Sendestring:=Sendestring+WordToStr( WerteArray[AnzSendeworte+1-i]); For i :=1 to AnzSendeworte do Sendestring:=WordToStr( WerteArray[i])+Sendestring; | und wenn du fertig bist, schiebst du die Procedure Init_max nach.
So ungefähr würd ich es versuchen.
Gruß oldmax
_________________ Zier dich nich so, ich krieg dich schon....
|
|
|