TIA UINT auf Größer vergleichen

Zuviel Werbung?
-> Hier kostenlos registrieren
@Heinilein: Kannst du deinen Code kurz erklären?

Wenn ich den oberen Teil richtig verstanden habe lädst du den UDINT1 in den Akku 1 und schiebst ihn 1 Bit nach rechts.
Dann lädst du den UDINT2 und machst das gleiche.
Danach vergleichst du die beiden und springst zu GT oder LT.
Aber wo sind GT und LT?

Und was hat es mit dem Linksschieben und wieder rechtsschieben auf sich im unteren Teil?
 
ich denke, er maskiert das vorzeichen aus. damit erreichst du immer einen vorzeichenlosen wert. so gehts auch :)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja, läuft jetzt so wie ich es möchte. höchstmöglicher wert 4000000, also UDINT. Hab einen SCL-Baustein erstellt, dort als INOUT eine UDINT Variable übergeben und in SCL es einfach programmiert.

Code:
IF #CountComm > 4000000 THEN
        #CountComm := 0;
END_IF;

so, bin grad etwas verwirrt. auch diese version funktioniert so nicht. bei 65534 fängt es wieder bei null an. also scheint der SCL compiler das gleiche zu machen wie beim AWL...
 
Moin gochtel,

65534 "riecht" nach Word bzw. Uint!

Welchen Datentyp hat CountComm?
Ist es ein IN/OUT?
Kannst Du mal Screenshots von der Deklaration und der Bausteinbeschaltung (also dem Aufruf) zeigen?

VG

MFreiberger
 
S7-AWL kennt kein UINT und hat keine UINT-Anweisungen. Das ist aber kein großes Problem. Man kann einfach die 16-Bit-"UINT"-Operanden mit 32-Bit-Operationen verarbeiten (+D >D ...), wodurch alle 16-Bit-Bitmuster 16#0000 bis 16#FFFF wie UINT (0..65535) verarbeitet werden.

S7-AWL kennt kein UDINT und hat keine UDINT-Anweisungen. Das ist aber kein großes Problem.
DINT und UDINT unterscheiden sich nur durch die Interpretation der Bitmuster 16#80000000 bis 16#FFFFFFFF (wo das höchste Bit .31 = 1 ist)
- DINT : 16#8000'0000..16#FFFF'FFFF = -2'147'483'648 .. -1
- UDINT: 16#8000'0000..16#FFFF'FFFF = 2'147'483'648 .. 4'294'967'295

DINT-Vergleiche interpretieren (16#8000'0000 .. 16#FFFF'FFFF) als kleiner (0 .. 16#7FFF'FFFF)
UDINT-Vergleiche interpretieren (16#8000'0000 .. 16#FFFF'FFFF) als größer (0 .. 16#7FFF'FFFF)

Dank der Zweierkomplement-Codierung von DINT kann man "relativ" (auf dem Zahlenstrahl bzw. Zahlenkreis) rechnen: beide "UDINT"-Operanden durch Subtraktion von 16#8000'0000 in den DINT-Bereich verschieben, dann DINT-Vergleich anwenden. Subtraktion von 16#8000'0000 entspricht Invertieren des höchsten Bit .31, was man als Verschiebung/Vertauschung der Werte in den jeweils anderen Bereich (16#8000'0000 .. 16#FFFF'FFFF) und (0 .. 16#7FFF'FFFF) interpretieren kann.
Code:
[COLOR="#008000"]//Dank der 2er-Komplement-Codierung von DINT kann man "relativ" rechnen: [/COLOR]
[COLOR="#008000"]//beide "UDINT"-Operanden durch -16#80000000 in den DINT-Bereich verschieben, [/COLOR]
[COLOR="#008000"]//dann DINT-Vergleich anwenden (x-16#80000000 entspricht Umdrehen des Bit .31)[/COLOR]

[COLOR="#008000"]//Variante A: Subtraktion von 16#8000_0000 (2.147.483.648)[/COLOR]
      L     #UDINT_Var_1
      +     L#-2147483648
      L     #UDINT_Var_2
      +     L#-2147483648
      >D
      =     #ist_groesser

[COLOR="#008000"]//Variante B: Invertieren des Bit .31[/COLOR]
      L     #UDINT_Var_1
      XOD   DW#16#80000000
      L     #UDINT_Var_2
      XOD   DW#16#80000000
      >D
      =     #ist_groesser

Harald
 

Anhänge

  • UDINT_DINT.png
    UDINT_DINT.png
    7 KB · Aufrufe: 16
Hab jetzt die Variante von Harald versucht. Auch kein Erfolg. Langsam hab ich den Eindruck, ich bin zu blöd :confused:

Code:
//Variante A: Subtraktion von 16#8000_0000 (2.147.483.648)
    #temp_CountComm := #CountComm - 2147483648;
    #temp_UDINT := 2000000 - 2147483648;
    
    IF #temp_CountComm > #temp_UDINT THEN
        #CountComm := 0;
    END_IF;
Ziel ist, zählen bis 2000000, dann Zähler wieder auf 0 stellen. der hört immer bei 655xx auf und fängt bei 0 an. Wo ist der Fehler?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
oje, jetzt geht hier alles durcheinander...

wenn Du auf 4 Mio vergleichen willst, dann brauchst Du kein SCL, DINT kann bis 2 Mrd.

wenn Du bis 4 Mrd. vergleichen willst, dann brauchst Du UDINT und den SCL-Baustein.

Die Varianten von Heinilein und PN/DP in AWL sind zwar schön, würd ich aber mit TIA und S7-1500 nicht machen...

Gruß.
 
Hab jetzt die Variante von Harald versucht. Auch kein Erfolg. Langsam hab ich den Eindruck, ich bin zu blöd :confused:

Ziel ist, zählen bis 2000000, dann Zähler wieder auf 0 stellen. der hört immer bei 655xx auf und fängt bei 0 an. Wo ist der Fehler?

Code:
      L     MD   500                    // DINT
      L     L#10000
      +D    
      T     MD   500


      L     MD   500
      L     L#2000000
      >=D   
      SPBN  nw1a
      L     0
      T     MD   500
nw1a: NOP   0
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Heinilein: Kannst du deinen Code kurz erklären?

Wenn ich den oberen Teil richtig verstanden habe lädst du den UDINT1 in den Akku 1 und schiebst ihn 1 Bit nach rechts.
Dann lädst du den UDINT2 und machst das gleiche.
Danach vergleichst du die beiden und springst zu GT oder LT.
Aber wo sind GT und LT?

Und was hat es mit dem Linksschieben und wieder rechtsschieben auf sich im unteren Teil?
Gerne, Jan.
Vorab, LT, EQ und GT sind die Sprungziele (irgendwo nach Deinem Belieben) , wo Du Deine Auswertung[en] programmieren kannst.
Das 2. Beispiel ist vielleicht besser zu gebrauchen, weil man da nur 1 Stelle hat, wo man den eigentlich gewünschten Vergleich ==D, <>D, <D, <=D, >D oder >=D direkt hinschreiben kann, so, als gäbe es den kleinen Umweg der Aufbereitung für den Vergleich gar nicht.

So, die Aufbereitung für die Vergleiche ist in beiden Beispielen gleich. Ich beschreibe hier mal nur das 2. Beispiel.

Es werden zunächst udint1/2 und udint2/2 verglichen, also die ursprünglichen Bit1..Bit31.
Sind diese ungleich, so weiss man schon jetzt, welche Zahl die kleinere bzw. grössere ist - unabhängig davon, dass wir beim Vergleich der halben Werte die ursprünglichen Bit0 geschlabbert haben.
Nur wenn beide halbe Werte gleich sind, müssen (und dürfen) wir noch prüfen, wie der jetzt entscheidende Vergleich der ursprünglichen Bit0 beider Zahlen ausfällt.

Wir wissen, dass die Befehle ==D, <>D, <D, <=D, >D und >=D die Inhalte der Akkus 1 und 2 als Zahlen im ZweierKomplement interpretieren.
D.h. Zahlen, bei denen das Bit31 den Wert 1 hat, werden als negative Zahlen und damit "in unserem UDINT-Sinne" falsch verstanden.
Sorgen wir also dafür, dass bei den Vergleichen das Bit31 in Akku1 und Akku2 den Wert 0 hat.
1. Indem wir im ersten Vergleich nur die halben Werte vergleichen, die wir durch SRD 1 berechnen (SRD füllt beim Schieben von links mit 0 auf).
2. Indem wir für den zweiten Vergleich - den wir nur dann ausführen, wenn der 1. Vergleich gesagt hat, beide halbe Zahlen sind gleich - das ursprüngliche Bit31 in beiden Zahlen "platt machen".
Denn wir wissen durch den ersten Vergleich, das die ursprünglichen Bit31 beider Zahlen gleich sind, egal, ob beide den Wert 0 oder beide 1 haben.
Sind beide Bit31 vor dem Löschen schon 0, so ändern wir durch das Löschen rein gar nichts.
Sind beide Bit31 vor dem Löschen 1, so ändern wir durch das Löschen zwar beide in 0, ABER das ändert rein gar nichts daran, dass beide Zahlen in den Bit1..Bit31 weiterhin unverändert gleich bleiben.
Auf das Ergebnis des folgenden Vergleichs haben deshalb nur die (ursprünglichen) Bit0 der beiden Zahlen einen Einfluss.
Um die Bit31 der beiden Zahlen zu löschen, habe ich die BefehlsFolge SLD 1 und SRD 1 gewählt - könnte man auch durch verUNDen mit 7FFFFFFF tun - oder durch verUNDen mit 1, so dass Bit1..Bit31 gelöscht und tatsächlich nur noch Bit0 übrigbleibt.

Gruss, Heinileini
 
Zuletzt bearbeitet:
Hab jetzt die Variante von Harald versucht. Auch kein Erfolg. Langsam hab ich den Eindruck, ich bin zu blöd :confused:

Code:
//Variante A: Subtraktion von 16#8000_0000 (2.147.483.648)
    #temp_CountComm := #CountComm - 2147483648;
    #temp_UDINT := 2000000 - 2147483648;
    
    IF #temp_CountComm > #temp_UDINT THEN
        #CountComm := 0;
    END_IF;
Ziel ist, zählen bis 2000000, dann Zähler wieder auf 0 stellen. der hört immer bei 655xx auf und fängt bei 0 an. Wo ist der Fehler?
Also wenn Du SCL verwendest dann brauchst/darfst Du gar keine Tricks sondern deklarierst die Variablen als UDINT und fertig. Der Compiler übersetzt das automatisch mit den richtigen Tricks.
Nur wenn Du in AWL programmierst dann mußt Du trickreich mit DINT-Anweisungen UDINT-Werte verarbeiten.

Und wenn Du eh' nur bis höchstens ca. 2 Milliarden arbeitest, dann brauchst Du noch nichtmal UDINT, da reicht auch DINT.

Harald
 
Ziel ist, zählen bis 2000000, dann Zähler wieder auf 0 stellen. der hört immer bei 655xx auf und fängt bei 0 an. Wo ist der Fehler?
Da musst Du uns die Stelle zeigen wo gezählt wird. Dein Zählcode arbeitet anscheinend nur mit 16 Bit. Datentyp falsch deklariert oder wie wird gezählt?

Also:
- Wie genau wird mit #CountComm gezählt? Zeige uns den Code
- Gibt es vielleicht Überschneidungen mit anderen Speicherzugriffen, daß #CountComm ganz oder teilweise durch andere Speicherzugriffe überschrieben wird?

Harald
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
ich Zähle so:
Code:
      U     %DBX0.5     
      FP    %DBX1.1
      SPBN  ne03
      L     #CountComm_Test
      +     1
      T     #CountComm_Test
ne03: NOP 0

Variable ist als UDINT deklariert. Ich befürchte das "+ 1" ist das Problem...
 
Was ist das denn für ein +? Lässt sich das übersetzen?
Normalerweise musst du doch +I oder +D angeben...

Edit: Welp, TIL dass du mit + direkt eine Konstante addieren kannst. Dabei wird die Konstante ohne Angabe des Datentyps als Integer intepretiert und somit wird ein +I ausgeführt. Gem. Hilfe musst du ein "L#" vor die Konstante setzen um mit 32 bit Zahlen zu rechnen.
 
Zuletzt bearbeitet:
ich Zähle so:
Code:
      U     %DBX0.5     
      FP    %DBX1.1
      SPBN  ne03
      L     #CountComm_Test
      [COLOR="#FF0000"]+     1[/COLOR]
      T     #CountComm_Test
ne03: NOP 0

Variable ist als UDINT deklariert. Ich befürchte das "+ 1" ist das Problem...
Genau so ist es. Als welcher Datentyp #CountComm_Test deklariert ist, ist dem AWL völlig egal. AWL arbeitet mit den AKKUs. Das "+ 1" ist eine 16-Bit-INT-Addition. Du musst schreiben "+ L#1", dann wird 32-Bit-DINT addiert.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Was ist das denn für ein +? Lässt sich das übersetzen?
Normalerweise musst du doch +I oder +D angeben...

Edit: Welp, TIL dass du mit + direkt eine Konstante addieren kannst. Dabei wird die Konstante ohne Angabe des Datentyps als Integer intepretiert und somit wird ein +I ausgeführt. Gem. Hilfe musst du ein "L#" vor die Konstante setzen um mit 32 bit Zahlen zu rechnen.

Das "[FONT=&quot]+ 1[/FONT]" ist eine 16-Bit-INT-Addition. Du musst schreiben "[FONT=&quot]+ L#1[/FONT]", dann wird 32-Bit-DINT addiert.

Hmm, den kannt ich auch noch nicht ;)
 
Der AWL-Klassiker: Wenn Ganzzahlkonstanten verwendet werden, und der Wert liegt im INT-Bereich, dann verwendet der AWL-Übersetzer auch nur INT (16 Bit). Um da eindeutig 32-Bit Ganzzahlkonstante vorzugeben, muß man L#... schreiben. Ganz besonders bei negativen Ganzzahlkonstanten! "L -1" und "L L#-1" ergeben ganz verschiedene Werte im AKKU (-1 = 16#0000FFFF / L#-1 = 16#FFFFFFFF).

Harald
 
Zurück
Oben