Hilfestellung - 7 Segmentanzeige

Meteorblitz

Level-1
Beiträge
4
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich bin am verzweifeln und brauche eine Hilfestellung. In der Berufsschule sollten wir mit Codesys 2.3.9 eine 4 Stellige 7-Segmentanzeige ansteuern.
Wir sollen dazu die einzelnen Segmente über eine Umwandlung von INT_to_BCD verwenden.
Ich habe mir über eine Tabelle erstellt und ausgewertet, welche Segmente angesteuert werden müssen, um die jeweiligen Zahlen zwischen 0-9
anzuzeigen. Die einzelnen Segmente habe ich dann über Vergleicher abgefragt, sodass immer nur die passenden Zahlen angezeigt werden.

Mein Problem ist aber, dass ich keine Ahnung habe, wie ich jetzt die Zehnerstellen ansteuern soll und das die Anzeige für die Einerstellen weiterfunktioniert,
weil ich mit dem Equal Baustein gearbeitet habe.
 
Ist die 7-Segmentanzeige je Stelle (Ziffer) an jeweils 4 oder 7 oder 8 Digitalausgänge der SPS angeschlossen? Hast du eine Zeichnung oder genauere Beschreibung der Aufgabe?

Wenn die Verwendung von INT_TO_BCD vorgegeben ist, dann wird wohl jede Ziffernstelle an 4 Ausgänge angeschlossen sein, und die 7-Segmentanzeige hat integrierte BCD-zu-7-Segment-Decoder je Ziffer. Du brauchst dann nicht im Programm in die 7 Segmente umkodieren.

Codesys INT_TO_BCD wandelt Dezimalwerte 0..99 in die BCD-Darstellung 16#00 bis 16#99
Wenn der Eingangswert größer als 99 ist, dann liefert INT_TO_BCD als Fehlerhinweis den Wert 16#FF

Wenn Du eine 4-stellige Dezimalzahl ausgeben sollst, dann müsstest Du vor dem INT_TO_BCD den Eingangswert in "Häppchen" von höchstens 2 Dezimalziffern (0..9 oder 00..99) zerlegen. Das geht, indem man den Eingangswert durch 10 oder 100 dividiert und vom Ergebnis den Divisionsrest nimmt. Dafür gibt es die Operation MOD. Die höheren Ziffern erhält man, indem man diese zuerst zur Einer-Stelle verschiebt, indem man durch 10 oder 100 oder ... dividiert.

Bei 4 Ausgängen je Ziffer könntest Du das Byte was bei INT_TO_BCD entsteht, direkt an das Ausgangsbyte ausgeben (wenn die 7-Segment-Anzeige geschickt angeschlossen ist). Das machst Du zweimal: einmal für die unteren 2 Ziffern (Einer + Zehner) und einmal für die höheren 2 Ziffern (Hunderter + Tausender).

Bei 7 (oder 8 ) Ausgängen je Ziffer sollst Du wohl tatsächlich das Decodieren der 7 Segmente machen. Da macht das INT_TO_BCD allerdings wenig Sinn, weil man da besser kommt, wenn man jede Ziffer einzeln in die 7 Segmente umkodiert. Das Zerlegen in einzelne Ziffern bzw. Abspalten der niedrigsten Ziffer macht man mit Division durch 10 und nimmt den Divisionsrest (wieder MOD). Das ergibt 0..9. Dann noch INT_TO_BCD verwenden ist überflüssig, weil das wieder 0..9 ergibt.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
1. Die einzelnen Segmente habe ich dann über Vergleicher abgefragt, sodass immer nur die passenden Zahlen angezeigt werden.

2. Mein Problem ist aber, dass ich keine Ahnung habe, wie ich jetzt die Zehnerstellen ansteuern soll und das die Anzeige für die Einerstellen weiterfunktioniert
Zu 1.:
Du fragst die einzelnen Segmente ab? Und bildest die passenden Zahlen? Umgekehrt würde vielleicht ein Schuh draus. Du müsstest eine WahrheitsTabelle mit 4 Eingängen (die Ziffer) und 7 Ausgängen (die 7 Segmente) haben.

Zu 2.:
Zu den diversen Fragen, die Harald schon gestellt hat, kommt noch eine hinzu:
Hat die Anzeige Eingänge, über die man ein Abspeichern der vier Stellen einzeln ansteuern kann?
 
Zuletzt bearbeitet:
Hallo ihr beiden und danke für eure Antworten,

Für einen Kunden ist ein baustein zur Ansteuerung einer Segmentanzeige zu erstellen.
Der Baustein soll in ein SPS Programm nach IEC61131-3 integriert werden können.
Die Eingangsvariable soll hierbei vom Typ Integer sein. Ausgangssetig sollen direkt die einzelnen Segmente a bis g angesprochen werden.
Hinweis: Nutzen Sie bei der Programmierung nach Möglichkeit bereits vorhandene Funktionen und Funktionsblöcke wie z.B. die INT_TO_BCD Funktion.

Die Aufgabe wird in Codesys 2.3.9. visualisiert und simuliert, es wird also keine Hardware verwendet.Ich hatte bei mir im Programm z.B. das Segment_A der Einerstelle darüber angesteuert, dass diese immer dann 1 ist, wenn meine BCD Zahl "EQ" zur angegebenen Zahl ist:

Wenn BCD_Zahl "EQUAL" zu 0 ist dann ist Segment_a =1
Wenn BCD_Zahl "EQUAL" zu 2 ist dann ist Segment_a =1
etc. Diese Vergleicher sind dann alle auf einen OR Baustein zusammengeführt.
Das obere Segment in der Mitte einer Segmentanzeige ist ja z.B. prinzipiell immer an, nur bei den Zahlen 1 und 4 nicht. Wie aber erwähnt, könnte ich nach diesem Verfahren nur eine Anzeige ansteuern und nicht mehrere. Ich müsste also mein Vorgehen grundsätzlich
überdenken.
 
1. Ausgangssetig sollen direkt die einzelnen Segmente a bis g angesprochen werden.

2. Wie aber erwähnt, könnte ich nach diesem Verfahren nur eine Anzeige ansteuern und nicht mehrere.
Zu 1.:
Du musst also tatsächlich 28 (4x7) Ausgänge ansteuern.

Zu 2.:
Es wurmt Dich anscheinend, dass Du 4-mal die gleiche Mimik programmieren müsstest, angewendet auf 4 verschiedene Quellen und 4 verschiedene Ziele.
Du könntest diese Mimik in einem FB realisieren und ihn 4-mal aufrufen, wobei jedesmal anders parametriert.
Für sich wiederholende Aufgaben könnte man auch eine ProgrammSchleife in Erwägung ziehen, aber das bietet sich hier nicht wirklich an.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hinweis: Nutzen Sie bei der Programmierung nach Möglichkeit bereits vorhandene Funktionen und Funktionsblöcke wie z.B. die INT_TO_BCD Funktion.
INT_TO_BCD ist also nicht zwingend vorgeschrieben. :D

Die Aufgabe wird in Codesys 2.3.9. visualisiert und simuliert
Visualisiert mit einer grafischen Visu? Dann brauchst Du die 28 Segmente gar nicht als 28 einzelne Bit-Ausgänge. Sondern 4 (notfalls nur 1) Variablen für die Visu, also 1 Variable je Ziffer.

( Für die Visualierung könnte man die 7-Segment-Dekodierung weglassen bzw. direkt in der Visu machen, indem jede Ziffer aus einer Liste/Array von 10 vorgefertigten Bildern angezeigt wird. :cool: )

Oder für jede Ziffer ein Byte vorsehen, wo jedes Segment einem Bit zugeordnet ist, und die Visu animiert 28 Segmente durch Abfrage des zugehörigen Bits:
Einer_Segment_a: Byte_E Bit0
Einer_Segment_b: Byte_E Bit1
...
Einer_Segment_g: Byte_E Bit6
Zehner_Segment_a: Byte_Z Bit0
...
Tausender_Segment_g: Byte_T Bit6


Insgesamt werden 4 * 7 = 28 Segmente benötigt.

Nun kann man simpel aber aufwändig für jedes Segment eine Verknüpfung der 16 BCD-Bits programmieren entsprechend der Wahrheitstabelle für 7-Segmentdekoder = 28 Verknüpfungen (so wird ein 7-Segment-Decoder in Elektronik realisiert)
Code:
Einer_Segment_a := E1 OR (E2 AND E0) OR E3 OR (NOT(E2) AND NOT(E0));
oder
Einer_Segment_a := NOT( NOT(E3) AND NOT(E2) AND NOT(E1) AND E0) OR (NOT(E3) AND E2 AND NOT(E1) AND NOT(E0) );
...
Tausender_Segment_g := ...
Man kann auch aufwändig für jedes Segment eine Verknüpfung von Vergleichen (=, <>, >=, <=, ...) progammieren = 28 Verknüpfungen
Code:
Einer_Segment_a := NOT (E = 1 OR E = 4); //oder: E <> 1 AND E <> 4
...
Tausender_Segment_g := NOT(T = 0 OR T = 1 OR T = 7); //oder: T <> 0 AND T <> 1 AND T <> 7
Oder mit der CASE-Anweisung direkt das 7-Segment-Bitmuster an das Visu-Byte zuweisen je nach Wert der Ziffer = 4 CASE-Konstrukte je 10 Fälle.

Oder die 7-Segment-Bitmuster vorberechnet in einer Tabelle (ARRAY OF BYTE) hinterlegen und 4 mal mit dem Wert der Ziffer als Index das zugehörige Bitmuster aus der Tabelle lesen. (siehe Beispielcode unten)

Wie aber erwähnt, könnte ich nach diesem Verfahren nur eine Anzeige ansteuern und nicht mehrere. Ich müsste also mein Vorgehen grundsätzlich
überdenken.
Damit sich großer Code-Aufwand für 4 Ziffern nicht vervierfacht gegenüber der Lösung für eine Ziffer, kann man eine Function für eine Ziffer schreiben und viermal aufrufen, oder mit Stellen-Arrays und Programmschleife arbeiten. Besser: eine Lösung verwenden, wo der Code für eine Ziffer so kurz ist, daß eine Vervierfachung immer noch kürzer als Schleifen ist, ein umschreiben zu Schleife also nicht lohnt.

Für alle Lösungen gemeinsam braucht man die Isolierung/Zerlegung der Eingangszahl in einzelne Dezimalziffern.
Hierfür kann man nun INT_TO_BCD verwenden (ist aber in Codesys relativ umständlich, siehe Beitrag #2). Besser finde ich die Ziffernzerlegung mit MOD (ebenfalls siehe Beitrag #2).

Codebeispiel mit vorberechneter 7-Segment-Bitmuster-Tabelle (ungetestet)
Code:
VAR_INPUT
  v : INT;           //Eingangswert, davon werden die niederwertigsten 4 Ziffern decodiert
END_VAR
VAR_OUTPUT
  Ziffer_E : BYTE ;  //7-Segment-Bitmuster Einer-Stelle: a=Bit0 .. g=Bit6
  Ziffer_Z : BYTE ;  //7-Segment-Bitmuster Zehner-Stelle
  Ziffer_H : BYTE ;  //7-Segment-Bitmuster Hunderter-Stelle
  Ziffer_T : BYTE ;  //7-Segment-Bitmuster Tausender-Stelle
END_VAR
VAR
  Bitmuster : ARRAY[0..9] OF BYTE := ( 16#3F, 16#06, 16#5B, 16#4F, 16#66, 
                                       16#6D, 16#7D, 16#07, 16#7F, 16#6F );
END_VAR

Ziffer_E := Bitmuster[v MOD 10];
Ziffer_Z := Bitmuster[(v / 10) MOD 10];
Ziffer_H := Bitmuster[(v / 100) MOD 10];
Ziffer_T := Bitmuster[(v / 1000) MOD 10];
Ausgangssetig sollen direkt die einzelnen Segmente a bis g angesprochen werden.
Wenn Du 28 BOOL-Variablen brauchst, dann kannst Du die Bytes noch aufdröseln:
Code:
E_Segment_a := Ziffer_E.0;
...
E_Segment_g := Ziffer_E.6;
Z_Segment_a := Ziffer_Z.0;
...
T_Segment_g := Ziffer_T.6;

Harald
 
Wenn Du eine 4-stellige Dezimalzahl ausgeben sollst, dann müsstest Du vor dem INT_TO_BCD den Eingangswert in "Häppchen" von höchstens 2 Dezimalziffern (0..9 oder 00..99) zerlegen. Das geht, indem man den Eingangswert durch 10 oder 100 dividiert und vom Ergebnis den Divisionsrest nimmt. Dafür gibt es die Operation MOD. Die höheren Ziffern erhält man, indem man diese zuerst zur Einer-Stelle verschiebt, indem man durch 10 oder 100 oder ... dividiert.

Bei 4 Ausgängen je Ziffer könntest Du das Byte was bei INT_TO_BCD entsteht, direkt an das Ausgangsbyte ausgeben (wenn die 7-Segment-Anzeige geschickt angeschlossen ist). Das machst Du zweimal: einmal für die unteren 2 Ziffern (Einer + Zehner) und einmal für die höheren 2 Ziffern (Hunderter + Tausender).


Harald

Mit diesen Informationen konnte ich die Aufgabe endlich lösen. Ich habe ein BYTE für die Tausender- und Hunderterstelle und ein BYTE für die Zehner- und Einerstelle verwendet. Für die Tausender/Hunderter Stelle habe ich meinen Eingangswert durch 100 dividiert. Für die Zehner und Einerstelle habe ich die MOD Funktion verwendet. Vielen Dank für die Hilfestellung :)
 
Zurück
Oben