# STRING einer DB-Variablen indirekt zuweisen (SCL)



## maweri (26 Mai 2008)

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???



```
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


----------



## Ralle (26 Mai 2008)

Sei so gut und zeig mal noch die Definition des Printer_DB.


----------



## maweri (26 Mai 2008)

*Printer-DB*


```
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


----------



## Ralle (26 Mai 2008)

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
> ...


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.
> ...


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.


----------



## maweri (26 Mai 2008)

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ß).



```
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 

Der Send-DB sieht so aus:

```
DB_VAR ARRAY[1..1460]   
 CHAR
```
 

EDIT: 
PS: Der Gedanke kam mir auch.

PS2: Werde das mal probieren.


----------



## Ralle (26 Mai 2008)

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.


----------



## Ralle (26 Mai 2008)

maweri schrieb:


> Aber wie komme ich dann bei meinem String 'prog_line' an die einzelnen CHAR



Da fällt mit zuerst der AT-Befehl ein, such mal im Forum und in der SCL-Hilfe danach.


----------



## Grubba (26 Mai 2008)

@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


----------



## maweri (26 Mai 2008)

*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.



```
////////////////////
/// 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
```


----------



## maweri (26 Mai 2008)

@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.


----------

