Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi 16-Bit Folge über LPT ausgeben (https://www.delphipraxis.net/106644-16-bit-folge-ueber-lpt-ausgeben.html)

BoondockDuckling 14. Jan 2008 13:28


16-Bit Folge über LPT ausgeben
 
morgen

ich bin irgendwie zu doof eine 16-Bit folge über 3 Pins des LPTs an einen Schieberegister zu übergeben.

Seltsamerweise bin ich nur zu doof das in eine Prozeudur zu packen denn durch "manuellelles schalten" der LPT-Pins bekomme ich es hin.

Folgendes: Der MAX7221 wird wie ein Schieberegister angesteuert. Er besitzt einen Data, einen Load und einen Clock Eingang.
Um die internen Register zu beschreiben wird eine 16-Bit-Folge geschrieben. Dazu setzt man Load auf low und übergibt zu jeweiligen zustände (logische 0 und 1) an Data und schreibt diese per Clock in den Register. Z.b. um eine 1 zu übergeben wird Data und Clock gleichzeitig High gesetzt, um eine 0 zu schreiben wird nur Clock auf high gesetzt. Nach ende der 16 Bit wird Load wieder high gesetzt.

Bei mir ist
LPT-Pin1: Clock
LPT-Pin2: Load
LPT-Pin3: Data

nachtrag: p.s. pin1 ist datenpin0(wert 1), pin2 datenpin1(wert 2) und pin3 datenpin2(wert 4)

Ich habe mir drei Checkboxen erstellt mit denen ich die Pins1-3 beliebig in allen Kombinationen schalten kann. Das funktioniert auch, so kann ich die 16 Bit manuell in den Schieberegister schreiben.
Ich bin schlichtweg zu doof das in eine Prozedur zu packen die das automatisch macht.

Beispielsweise soll folgende Bitfolge übergeben werden: 0000 1010 0000 0000

Manuell sieht das so aus:
Code:
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


Da dachte ich mir: Kein problem, schreibe ich das einfach mal eins zu eins in eine Prozedur:
(Die port-kontrolle funlktionier über "io.dll" -> google!! Die Prozedur delay ist eine, wie zu erwarten, delay-Prozedur. Die tut jetzt zwar nichts zur sache, habe sie unten aber mal mit eingefügt.)

Delphi-Quellcode:
procedure TForm1.Button8Click(Sender: TObject);
var d:integer;
begin
 d:=100; //millisekunden
 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;
Delphi-Quellcode:
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;



Leute, schlagt mich. Was zur ...... mache ich denn falsch??? Das ist doch nicht das erste mal dass ich einen Schieberegister beschreibe... :evil:

Muetze1 14. Jan 2008 13:40

Re: 16-Bit Folge über LPT ausgeben
 
Delphi-Quellcode:
procedure WriteWord(const APort: Word; const AData: Word);
const
  CLOCK = 1;
  LOAD = 2;
  DATA = 4;
var
  i: integer;
  lData: Word;
  lPortData: Byte;
  lBit: boolean;
begin
  lData := AData;

  // Wenn LOAD definitv auf high ist beim reinspringen in diese Proc, dann können die ersten beiden Zeilen weg...
  //PortIO(APort, LOAD);
  //Delay(20);
  PortIO(APort, 0);

  for i := 0 to 15 do
  begin
      // Bit ermitteln
    lBit := ( lData and $8000 ) <> 0;  // falls es dann gespiegelt ist, dann halt lBit := ( lData and 1 ) <> 0 und unten shr statt shl
    lData := lData shl 1;
   
    lPortData := CLOCK;
    if lBit then
      lPortData := lPortData or DATA;
   
    PortIO(APort, lPortData);
    Delay(20);
    PortIO(APort, lPortData and not CLOCK);
    Delay(20);
  end;

  PortIO(APort, LOAD);
end;
Ungetestet und hier im Beitragseditor getippelt...

tr909 14. Jan 2008 13:47

Re: 16-Bit Folge über LPT ausgeben
 
probier doch mal (nur ne Vermutung) :
Delphi-Quellcode:
 
procedure TForm1.Button8Click(Sender: TObject);
var
  output : word;
begin
  word := 2560; //0000 1010 0000 000 in dezimal
  PortOut($378,output); // oder PortOut ($378,$A00);
end;

Gruß
tr909

Muetze1 14. Jan 2008 13:50

Re: 16-Bit Folge über LPT ausgeben
 
Das bringt doch nichts, da er seriell shiften muss.

tr909 14. Jan 2008 13:56

Re: 16-Bit Folge über LPT ausgeben
 
hmm. stimmt. Muss ich überlesen haben.

Gruß
tr909

Reinhard Kern 14. Jan 2008 14:42

Re: 16-Bit Folge über LPT ausgeben
 
Zitat:

Zitat von tr909
probier doch mal (nur ne Vermutung) :
Delphi-Quellcode:
 
procedure TForm1.Button8Click(Sender: TObject);
var
  output : word;
begin
  word := 2560; //0000 1010 0000 000 in dezimal
  PortOut($378,output); // oder PortOut ($378,$A00);
end;

Gruß
tr909

Hallo,

interessanter Versuch - aber LPT ist 8 bit breit und wird es immer bleiben.

Gruss Reinhard

BoondockDuckling 14. Jan 2008 14:44

Re: 16-Bit Folge über LPT ausgeben
 
hey. danke soweit schon


@Muetze1
mit deinem Code passiert zwar etwas aber nicht das was passieren soll.
(kleine Erklärung: die Bitfolge 0000 1010 0000 0000 setzt die Leuchtintensität einer LED-Matrix, die am IC hängt, auf Minimal. Desshalb habe ich diese Bitfolge als Testfolge genommen. Stattdessen verschwindet aber einfach eine Zeile der Matrix. Das wird wohl eine Fehlinterpretation des ICs sein.)

Wenn ich, wie von dir angegeben, die Folge spiegel passiert garnichts mehr.


Ich habe nur ein relatives Delphi-Grundwissen und habe auch einige Minuten gebraucht deinen Code zu verstehen (und bin begeistern wie intelligent man sowas lösen kann :stupid: ).

Was z.b. bedeutet das hier:
lBit := ( lData and $8000 ) <> 0;
bzw. was hat die and $8000 und das <> 0 für eine Funktion?


Achja aufgerufen habe ich die Prozedur so: WriteWord($378,2560); ... das sollte ja stimmen.


@reinhard
naja der lpt hat ja so viele pins... da kann man ja mal durcheinanderkommen :drunken:


@tr909
ja wie schon gesagt tuts hier nix zur sache wieviel ausgänge der lpt hat denn die bitfolge wird an einem pin übergeben. die beiden anderen dienen nur zum schalten.

Muetze1 14. Jan 2008 15:04

Re: 16-Bit Folge über LPT ausgeben
 
Zitat:

Zitat von BoondockDuckling
mit deinem Code passiert zwar etwas aber nicht das was passieren soll.
(kleine Erklärung: die Bitfolge 0000 1010 0000 0000 setzt die Leuchtintensität einer LED-Matrix, die am IC hängt, auf Minimal. Desshalb habe ich diese Bitfolge als Testfolge genommen. Stattdessen verschwindet aber einfach eine Zeile der Matrix. Das wird wohl eine Fehlinterpretation des ICs sein.)

Schonmal den Delay auch wieder hochgesetzt?

Zitat:

Zitat von BoondockDuckling
Wenn ich, wie von dir angegeben, die Folge spiegel passiert garnichts mehr.

Beachtet auch shl durch shr zu ersetzen in der Zeile danach?

Zitat:

Zitat von BoondockDuckling
Was z.b. bedeutet das hier:
lBit := ( lData and $8000 ) <> 0;
bzw. was hat die and $8000 und das <> 0 für eine Funktion?

Es wird ein binäres UND durchgeführt. Wenn du einen Wert x binär mit einem Wert Y "ver-und-est", dann sind im Ergebnis alle die Bits gesetzt, welche im Wert X gesetzt sind UND dies auch im Wert Y sind. $8000 ist der hexadezimale Wert, welches nur das Bit 15 gesetzt hat. Somit kann nach dem UND mit $8000 entweder 0 oder $8000 rauskommen. Ersteres ist das Ergebnis, wenn lData an Bit 15 eine 0 (nicht gesetzt) hat und ein $8000 kommt heraus, wenn Bit 15 gesetzt ist.

Ich hätte also auch schreiben können:
Delphi-Quellcode:
lBit := ( lData and $8000 ) = $8000;
Dadurch, dass die Bitmaske von $8000 nur ein Bit (Bit 15) von Wert lData "durchlässt", kann halt nur $8000 oder 0 rauskommen. Und um nicht nochmal $8000 zu schreiben, habe ich einfach geschrieben <> 0.

Zitat:

Zitat von BoondockDuckling
Achja aufgerufen habe ich die Prozedur so: WriteWord($378,2560); ... das sollte ja stimmen.

Klar, sollte so passen.

BoondockDuckling 14. Jan 2008 15:27

Re: 16-Bit Folge über LPT ausgeben
 
Ja am Delay habe ich auch schon etwas rumgespielt. Ändert aber nichts. (Sollte es ja eigentlich auch nicht)


shl habe ich natürlich auch in shr geändert.

Danke auch für die Erklärung, ich denke das habe ich soweit verstanden.

Sehe ich das richtig dass durch lData := lData shl 1; die bitfolge um eine Stelle vorschoben wird sodass Bit 14 zu Bit 15 wird und so beim nächsten Durchlauf der for-schleife wieder entsprechend bei lBit := ( lData and $8000 ) <> 0; ausgelesen wird?


Fragt sich jetzt eigentlich wo das Problem ist... es muss doch so funktionieren.

Muetze1 14. Jan 2008 16:17

Re: 16-Bit Folge über LPT ausgeben
 
Zitat:

Zitat von BoondockDuckling
Sehe ich das richtig dass durch lData := lData shl 1; die bitfolge um eine Stelle vorschoben wird sodass Bit 14 zu Bit 15 wird und so beim nächsten Durchlauf der for-schleife wieder entsprechend bei lBit := ( lData and $8000 ) <> 0; ausgelesen wird?

Ganz genau. Bitweises Shiften und es passiert genau das von dir beschriebene. Von daher ist die umgekehrte Ausgabe nichts anderes als Bit 0 abfragen und nach rechts schiften, so dass alle Bits nacheinander durch das Bit 0 gehen.

Die Bits die beim Shiften "rüberfallen" sind weg - im Gegensatz zum rotieren (ror, rol), dort würden die rausfallenden Bits wieder auf der jeweils anderen Seite wieder reinrutschen. Delphi bietet dafür aber keine Operatoren an, somit nur so als Information.

BoondockDuckling 14. Jan 2008 19:19

Re: 16-Bit Folge über LPT ausgeben
 
sohooooo ....
das Problem wäre gefunden. Beim Übertragung der Bits muss ein Timing eingehalten werden.

Code:
/Load -\__________________________________/-

Data  __/---\_________/---\_________/---\___

Clock ___/-\____/-\____/-\____/-\____/-\____

Relativ stümperhaft habe ich das in meinem Code mal so eingebaut:

Delphi-Quellcode:
 PortOut($378,0); delay(d);
 PortOut($378,4); delay(d);
 PortOut($378,5); delay(d);
 PortOut($378,4); delay(d);
 PortOut($378,0); delay(d);
klappt sogar bis zu einem Delay von 5ms.


Wie könnte man das denn noch in deinen Code einbauen?

Muetze1 14. Jan 2008 21:28

Re: 16-Bit Folge über LPT ausgeben
 
Delphi-Quellcode:
procedure WriteWord(const APort: Word; const AData: Word);
const
  CLOCK = 1;
  LOAD = 2;
  DATA = 4;
var
  i: integer;
  lData: Word;
  lPortData: Byte;
  lBit: boolean;
begin
  lData := AData;

  PortIO(APort, 0); // LOAD löschen

  for i := 0 to 15 do
  begin
      // Bit ermitteln
    lBit := ( lData and $8000 ) <> 0;
    lData := lData shl 1;
   
    if lBit then
      lPortData := DATA
    else
      lPortData := 0;
    PortIO(APort, lPortData); // Data setzen
    delay(5);                 // kann vllt. weg
    PortIO(APort, lPortData or CLOCK);  // CLOCK zusätzlich setzen
    delay(5);
    PortIO(APort, lPortData); // CLOCK wieder löschen

      // trotz des Timings können folgende beiden Zeile wahrscheinlich weg...
    delay(5);  
    PortIO(APort, 0);         // DATA löschen
  end;

  PortIO(APort, LOAD);
end;
Wieder nur aus dem Beitragseditor...

BoondockDuckling 15. Jan 2008 13:51

Re: 16-Bit Folge über LPT ausgeben
 
danke
ich werds heute abend mal testen :)

oldmax 16. Jan 2008 08:50

Re: 16-Bit Folge über LPT ausgeben
 
Hi
Ich habe dir bereits im DF geantwortet, aber hier mal zum Verständnis:
Bei SHR muß Bit 0 maskiert werden also And $0001
Dann mal zur beschaltung:
Zitat:

Bei mir ist
LPT-Pin1: Clock
LPT-Pin2: Load
LPT-Pin3: Data

nachtrag: p.s. pin1 ist datenpin0(wert 1), pin2 datenpin1(wert 2) und pin3 datenpin2(wert 4)
Wenn Pin 3 der Data-Pin ist muß anschließend ein SHL 2, das heißt , das maskierte Bit 0 auf Bit 2 geschoben werden. Anschließend sind die Pins Clock mit Or $0001 und Or $0002 hinzuzufügen. Entsprechend dem Impulsdiagramm. Dabei ist zu beachten, das das Load Bit vor der Übertragung bereits einmal ausgegeben werden muß (Maskiert mit $0002) dann wird das Datenbit gesetzt und ! das Load Bit. Anschließend ein Clock- Bit und das Datenbit und das LoadBit. Danach wieder Datenbit und Loadbit und zum Schluß nur ein Loadbit, bzw. wieder von vorn mit dem einmal nach rechts geschobenen Originalwort.
Es ist halt wichtig, das man sich merkt, bei der Maskierung des Datenbits gehen die Load und Clockbits erst mal verloren und müssen entsprechend wieder hinzugefügt werden.
Gruß oldmax

@Muetze: Sorry, hab das grüne nicht gelesen und das Impulsdiagramm vom DF im Kkopf gehabt... daher bin ich etwas über die Signallage gestolpert. Dein Code dürfte ok sein.

BoondockDuckling 16. Jan 2008 11:15

Re: 16-Bit Folge über LPT ausgeben
 
Und aus Abend wurde Morgen ...bzw. Mittag


Good News Everyone ... Es funktioniert :)


Ich unter einer Delayzeit von 8ms funktioniert es aber nicht mehr gescheit. Dann treten bei der Übertragung öfters Fehler auf. Das Problem habe ich mit der Software von Maxim aber auch. In deren Programm muss ich manchmal auch mehrfach Senden bis es richtig übertragen wird. Könnte an der Kabellänge liegen.

Etwas doof ist dass das Schreiben einer Matrix, also dem 5*7 Display, 2,5Sekunden dauert. (Kommt aber ja hin. Pro Schreibvorgang sind es knapp 400ms an Delayzeiten. Auf 5 Zeilen müsste es min. 2 Sekunden dauern.)



@oldmax
so ganz sicher bin ich mir jetzt nicht ob ich dir folgen kann. Im Prinzip wird das was du erklärst doch in dem Code von Muetze durchgeführt oder versteh ich jetzt etwas falsch?

oldmax 16. Jan 2008 11:48

Re: 16-Bit Folge über LPT ausgeben
 
Hi
Ja, ich hab mal wieder nicht vollständig gelesen und nachvollzogen...irgendwie hatte ich auch die Signallage anders im Kopf, daher das Chaos... :oops:
Ich lös halt solche Bitbearbeitung gern über ASM...
Gruß oldmax

BoondockDuckling 16. Jan 2008 19:16

Re: 16-Bit Folge über LPT ausgeben
 
soweit so schön

jetzt hätte ich noch zwei Fragen:

1. Gibt es eine einfach Möglichkeit mehrere Word-Variabeln in eine Zusammenzufassen. Nicht addieren sondern so als ob man die Binärzahlen hintereinander schreibt. Hierbei kommt es auf die Reihenfolge an und es müssen 16Bit sein, also die Nullen vor einer Folge müssen auch beachtet werden.

Beispiel: Das + hier bedeutet "hintereinander"
Code:
 
-    | Hexadezimal | Integer     | Binär
1:  |      A01    |      2561    |                     0000 1010 0000 0001 
2:  |      37F   |       895    |                     0000 0011 0111 1111 
1+2: | 1400837F   | 335577983    | 0000 1010 0000 0001 0000 0011 0111 1111 
2+1: |  37F0A01    |  58657281    | 0000 0011 0111 1111 0000 1010 0000 0001

2. Wie kann ich herausfinden wie viele 16-Bit Folgen vorhanden sind?
Theoretisch können zwei Folgen ja so aussehen: 10000000000000001 und wäre Hexadezimal eine 1001 bzw. als Integer eine 4097. Wäre ja was ganz anderes als Hexadezimal FFFFFFFF, also von der binären Länge der Folge.


Ich könnte mir da jetzt irgendwas zusammenbasteln das zwar funktioniert, aber es gibt ja sicherlich intelligentere Wege als mit irgendwelchen Schleifen etc zu hantieren. (wäre jetzt meine Überlegung)



Nachtrag: ach ich sehe gerade der variablentyp word geht ja nur bis 16Bit... also kann man ja keine zwei word variabeln zusammenfassen.

Um das vielleicht nochmals genauer zu erklären. Man kann mehrer der MAX-ICs kaskadieren, muss dann aber entsprechend viele 16-Bit Folgen schreiben um eine Aktion durchzuführen.

Muetze1 16. Jan 2008 19:58

Re: 16-Bit Folge über LPT ausgeben
 
Zitat:

Zitat von BoondockDuckling
1. Gibt es eine einfach Möglichkeit mehrere Word-Variabeln in eine Zusammenzufassen. Nicht addieren sondern so als ob man die Binärzahlen hintereinander schreibt. Hierbei kommt es auf die Reihenfolge an und es müssen 16Bit sein, also die Nullen vor einer Folge müssen auch beachtet werden.

Beispiel: Das + hier bedeutet "hintereinander"
Code:
 
-    | Hexadezimal | Integer     | Binär
1:  |      A01    |      2561    |                     0000 1010 0000 0001 
2:  |      37F   |       895    |                     0000 0011 0111 1111 
1+2: | 1400837F   | 335577983    | 0000 1010 0000 0001 0000 0011 0111 1111 
2+1: |  37F0A01    |  58657281    | 0000 0011 0111 1111 0000 1010 0000 0001

1. Deine Hexadezimalzahl von dem Beispiel mit 1+2 ist mehr als falsch. Es müsste 0A01037F sein.
2. Ein LongWord ist 32 Bit gross, somit 2x 16 Bit
3. Aber wozu? Rufe meine Funktion nacheinander mit den 16 Bit Werten auf, bis du alle 16 Bit Werte ausgegeben hast.

Zitat:

Zitat von BoondockDuckling
2. Wie kann ich herausfinden wie viele 16-Bit Folgen vorhanden sind?
Theoretisch können zwei Folgen ja so aussehen: 10000000000000001 und wäre Hexadezimal eine 1001 bzw. als Integer eine 4097. Wäre ja was ganz anderes als Hexadezimal FFFFFFFF, also von der binären Länge der Folge.

Gar nicht. Der Speicher ist voller Bits und Bytes. Wer nicht weiß was wie zu interpretieren ist und was bedeutet, könntest du nicht ohne weiteres grundlegend Code und Daten unterscheiden. Es gibt keine Möglichkeit dies zu ermitteln.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:16 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz