STRING einer DB-Variablen indirekt zuweisen (SCL)

maweri

Level-2
Beiträge
383
Reaktionspunkte
101
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Leute,

ich steh' hier vor einem Problem.

Zur Erklärung:
Um einen Barcodedrucker anzusteuern, muß ich ein jedesmal ein kleines Programm an diesen senden. Das Programm habe ich zeilenweise in einem Printer-DB (bestehend aus 25 String[254]-Variablen) hinterlegt. Insgesamt gibt es 5 veränderliche Daten auf dem Barcode-Label (4x Text, 1x Barcode). Diese Daten werden vom Kunden in einem DB als Strings bereitgestellt.

Ich hole mir den String aus dem Kunden-DB ab. Bereite ihn für den Drucker auf. Setze dann einen neuen String zusammen und schreibe ihn an die richtige Stelle in den Printer-DB.

Problem:
So wie ich das vorhabe geht's nicht. Bei der rot markierten Programmzeile wird der Fehler: Unzuläsiger Datentyp ausgegeben.

Kann mir da jemand weiterhelfen???


Code:
FUNCTION_BLOCK assignment
 
VAR_INPUT
    Printer_DB:     BLOCK_DB;   // program lines DB
    Line_No:        INT;        // number of program line 
    Source:         STRING;     // source string
    Type_of_print:  INT;        // 1=text, 2=barcode
END_VAR
 
VAR_TEMP
    line_addr:      INT;        // address of program line 
    str_len:        INT;        // length of string
    Prefix:         STRING;     // prefix for print type
    prog_line:      STRING;     // program line
END_VAR
 
BEGIN
// determining string length
str_len := LEN (S:= Source);
 
// compiling program line
Prefix := '';
IF Type_of_print = 1 THEN
    Prefix := 'PRTXT "';
ELSIF   Type_of_print = 2 THEN
    Prefix := 'PRBAR "';
END_IF;
prog_line := 'a'; // initializing string variable
prog_line := CONCAT (IN1 := Prefix, IN2 := Source, IN3 := '"');
 
// transfering string
line_addr := (Line_No - 1) * 256;
[COLOR=red]Printer_DB.DB[line_addr] := prog_line;[/COLOR]
 
END_FUNCTION_BLOCK

Gruß
maweri
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Printer-DB

Code:
Line_01 STRING[254] 'FONT "Swiss 721 Bold BT",8'  
Line_02 STRING[254] 'PRPOS 5,200'  
Line_03 STRING[254] 'PRTXT "XXX Werk XXXXXXX"'  
Line_04 STRING[254] 'PRPOS 290,200'  
Line_05 STRING[254] 'PRTXT "XXXXX IP-LHD Sw/Sw NonKneebag"'  
Line_06 STRING[254] 'BARFONT "Swiss 721 BT",8,0,0,1,1,100,2,0,0 ON'  
Line_07 STRING[254] 'BARSET "CODE128"'  
Line_08 STRING[254] 'PRPOS 130,40'  
Line_09 STRING[254] 'PRBAR "20768002879F45010735150157"'  
Line_10 STRING[254] 'ALIGN 1'  
Line_11 STRING[254] 'PRPOS 5,0'  
Line_12 STRING[254] 'PRTXT "A"'  
Line_13 STRING[254] 'PRPOS 30,0'  
Line_14 STRING[254] 'PRTXT "207 680 0287"'  
Line_15 STRING[254] 'PRPOS 220,0'  
Line_16 STRING[254] 'PRTXT "Prod.Datum:"'  
Line_17 STRING[254] 'PRPOS 360,0'  
Line_18 STRING[254] 'PRTXT "15.05.08"'  
Line_19 STRING[254] 'PRPOS 545,0'  
Line_20 STRING[254] 'PRTXT "Q 07"'  
Line_21 STRING[254] 'PRINTFEED'  
Line_22 STRING[254] ''  
Line_23 STRING[254] ''  
Line_24 STRING[254] ''  
Line_25 STRING[254] ''

Die Zeilen 5, 9, 14, 18 und 20 enthalten den variablen Anteil des Labels.
Ich will meinen FB 'assignment' also 5x aufrufen und jede der Programmzeilen einzeln erzeugen.

maweri
 

Anhänge

  • Printer-DB.jpg
    Printer-DB.jpg
    167 KB · Aufrufe: 54
Zuletzt bearbeitet:
Ich denke, das geht nicht mit Block_DB. Entweder du adressierst den DB direkt, indem du ihn also in deinem FB direkt verwendest und nicht als Block_DB. Oder du extrahierst daraus die DB_Nummer und bastelst dir dann daraus eine Adresse für ein Block_move zusammen. Die SIemens-Hilfe ist das ungenau:

1.

BLOCK_FB
BLOCK_FC
BLOCK_DB
BLOCK_SDB

Kennzeichnet einen bestimmten Baustein, der von einem aufgerufenen AWL-Codebaustein verwendet werden soll.
Aktualparameter: z. B. FC101, DB42
Hinweise:
Auf den Datentyp
BLOCK_DB können Sie absolut zugreifen (myDB.dw10). Ebenso können Sie ihn mit BLOCK_DB_TO_WORD() weiter verarbeiten.
Die Datentypen BLOCK_SDB, BLOCK_FB und BLOCK_FC sind von S7-SCL-Programmen nicht auswertbar.
Sie können sie lediglich dazu verwenden, Parameter dieses Typs beim Aufruf von AWL-Bausteinen zu versorgen
2.

Auf den Datentyp BLOCK_DB können Sie absolut zugreifen (myDB.dw10). Für die anderen Block-Datentypen stellt S7-SCL keine Operationen zur Verfügung. Es können lediglich Parameter dieses Typs bei Bausteinaufrufen versorgt werden. Bei Funktionen ist das Durchreichen eines Eingangsparameters nicht möglich.
3.
Strukturierter Zugriff auf Datenbausteine

Der strukturierte Zugriff erfolgt über den Bezeichner der im Datenbaustein vereinbarten Variablen. Sie können die Variable jeder typgleichen Variablen zuweisen.
Die Variable in dem Datenbaustein referenzieren Sie, indem Sie den DB-Namen und, getrennt durch einen Punkt, den Namen der einfachen Variablen angeben.
Syntax
syn106_wmf.gif


Die einfache Variable steht hierbei für eine Variable, der Sie bei der DB-Vereinbarung einen elementaren oder einen zusammengesetzten Datentyp zugeordnet haben.
Wird ein Parameter vom Typ
BLOCK_DB oder das Ergebnis der Konvertierungs-Funktion WORD_TO_BLOCk_DB als Einleitung für einen Zugriff auf einen Datenbaustein benutzt, so ist kein strukturierter, sonder nur ein absoluter oder indizierter Zugriff möglich.
Beispiel
Im Vereinbarungsteil des FB10:
VAR
Ergebnis: STRUCT ERG1 : INT;
ERG2 : WORD;
END_STRUCT
END_VAR

Anwenderdefinierter Datentyp UDT1
TYPE UDT1 STRUCT ERG1 : INT;
ERG2 : WORD;
END_STRUCT

DB20 mit anwenderdefiniertem Datentyp:
DB20
UDT1
BEGIN ...

DB30 ohne anwenderdefinierten Datentyp:
DB30 STRUCT ERG1 : INT;
ERG2 : WORD;
END_STRUCT
BEGIN ...

Funktionsbaustein mit den Zugriffen:
..
FB10.DB10();
ERGWORT_A := DB10.Ergebnis.ERG2;
ERGWORT_B := DB20.ERG2;
ERGWORT_C := DB30.ERG2;
Wobei bei 3. das "Indiziert" eigentlich nur auf BLOCK_DB_TO_WORD() zutrefen kann.

PS: Denn die Frage wäre ja, woher soll SCL, zum Zeitpunkt des Comilierens wissen, was für einen FB du später mal an "Printer_DB" anhängst?

PS2: Wenn du mit dem DB direkt arbeitest, könntest du ihn anders strukturieren (Line: Array[1..20] of String[254]). Darauf kannst du dann indiziert zugreifen.
 
Zuletzt bearbeitet:
An BLOCK_DB kann's m.E. nicht liegen.
Bei dem folgendem FB läuft's problemlos. (Das ist übrigens der FB, der meinen Printer-DB nochmals aufbereitet, weil hinter jeder Progzeile noch ein CR eingesetzt werden muß).


Code:
FUNCTION_BLOCK intermec 
VAR_INPUT
    Prog_DB:     BLOCK_DB; // program lines DB
    Send_DB:  BLOCK_DB; // printer data DB
    No_of_lines: INT;      // number of program lines
END_VAR
 
VAR
    pos:        INT;  // position counter printer data
    b_length:   BYTE; // length of string in byte
    i_length:   INT;  // length of string in int
    i:          INT;  // loop counter program lines
    j:          INT;  // loop counter string length
    len_pos:    INT;  // position of lenght information
    char_pos:   INT;  // position of character
END_VAR
 
BEGIN
// Reset counter printer data
pos := 0; 
 
// loop program lines
FOR i := 1 TO No_of_lines DO
 len_pos:= (i - 1) * 256 + 1;
    b_length := Printer_DB.DB[len_pos];
    i_length := BYTE_TO_INT(b_length);
 
    // loop string length
        FOR j := 1 TO i_length DO
            char_pos := len_pos + j;
            Send_DB.DB[pos] := Printer_DB.DB[char_pos];
            pos := pos + 1;
        END_FOR;
 
     // insert carriage return   
     Send_DB.DB[pos] := B#16#D;
     pos := pos + 1;
 END_FOR;
 
 END_FUNCTION_BLOCK

Vielleicht 'weiß' S7 nicht, das es sich um den Typ STRING handelt.
In dem obigen Programm übergeben ich ja nur einzelne CHAR, was ja auch leicht als HEX-Wert interpretiert werden kann.
Aber wie komme ich dann bei meinem String 'prog_line' an die einzelnen CHAR:confused:

Der Send-DB sieht so aus:
Code:
DB_VAR ARRAY[1..1460]   
 CHAR


EDIT:
PS: Der Gedanke kam mir auch.

PS2: Werde das mal probieren.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja, das ist aber was anderes, du schreibst da ein Char indiziert in ein Array of Char. Das schein tatsächlich indiziert zu gehen, das meint Siemens wohl auch. Fraglich ist, ob das evtl. nur mit Grundtypen geht (Bool, Byte, Word, Dword), welche man direkt auch mit Transferbefehlen schreiben kann? Aber du willst ja einen ganzen String schreiben, das geht nicht. Wenn schon, dann müßtest du diesen String Char für Char indiziert in einer For-Schleife in den Block-DB schreiben, denke ich mal.
 
@Maweri
Aber wie komme ich dann bei meinem String 'prog_line' an die einzelnen CHAR

Da gibts die 'MID' Funktion. Input String, Position und Anzahl der Zeichen (bei Dir 1) angeben, das Ergebnis ist dann Dein String, bzw. Char
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Des Rätsels Lösung

So jetzt läuft's!!!

Danke Ralle für den Tip mit dem AT-Befehl. (Den kannte ich noch nicht).

:icon_exclaim: WICHTIG 1: Der String, der an Source 'angelegt' wird, muß ebenfalls die Länge 254 haben. Habe díe Rohdaten extra aufgebläht.
:icon_exclaim: WICHTIG 2: Der Array beim AT funktioniert nicht dem Typ CHAR, sonst gibt's wieder die Probleme bei der Zuweisung in der FOR-Schleife.


Code:
////////////////////
/// used blocks: ///
/// LEN, CONCAT  ///
////////////////////
 
FUNCTION_BLOCK assignment
 
VAR_INPUT
    Printer_DB:     BLOCK_DB;   // program lines DB
    Line_No:        INT;        // number of program line 
    Source:         STRING;     // source string
    Type_of_print:  INT;        // 1=text, 2=barcode
END_VAR
 
VAR
    line_addr:      INT;        // address of program line 
    str_len:        INT;        // length of string
    Prefix:         STRING;     // prefix for print type
    prog_line:      STRING;     // program line
    i:              INT;        // loop counter char
    addr:           INT;        // start address string
    char_prog_line AT prog_line : ARRAY[1..256] OF BYTE;  
END_VAR
 
BEGIN
// determining string length
str_len := LEN (S:= Source);
 
// compiling program line
Prefix := ''; //deleting Prefix
 
IF Type_of_print = 1 THEN
    Prefix := 'PRTXT "';
ELSIF   Type_of_print = 2 THEN
    Prefix := 'PRBAR "';
END_IF;
 
prog_line := 'a'; // initializing string variable
prog_line := CONCAT (IN1 := Prefix, IN2 := Source, IN3 := '"');
 
// transfering string
addr := (Line_No - 1) * 256 - 1;
 
FOR i := 3 TO 256 DO
    line_addr := addr + i;
    printer_DB.DB[line_addr] := char_prog_line[i];
END_FOR;
 
END_FUNCTION_BLOCK
 
@Grubba

Da gibts die 'MID' Funktion. Input String, Position und Anzahl der Zeichen (bei Dir 1) angeben, das Ergebnis ist dann Dein String, bzw. Char

Vom Ansatz her auch nicht schlecht. Man könnte die Position durch die Schlaufe laufen lassen.

Aber die Erfahrungen der letzten Stunden haben mir gezeigt, daß es Probleme mit den Typen CHAR und STRING und indirekter DB-Adressierung gibt.

MID liefert als Ergebnis einen String (auch wenn's hier nur 1 Zeichen wäre). Man müsste dann wieder das eine Zeichen auslesen und in ein BYTE wandeln, um die Zuweisung hin zu bekommen.
 
Zurück
Oben