S7-300 SCL program convert string DB to real DB

michaelchenca

Member
Join Date
Dec 2010
Location
Red deer AB
Posts
15
Dear Sir,

I try to write a function use SCL to read the string from a DB and convert it to real and transfer to another DB. But the simple task turnout to be a tough one. I need to use SFC20 to transfer the string to temporary one and split it and coverts it to be real. Final, I have to send it back to real DB by SFC20 again. It pass the compiler but doesn’t work. I am a new hand on STL and SCL. Siemens PLC is kind of hassle to program. A simple loop needs to use Any pointer. What a life! Following is my SCL. Your help is appreciated.


FUNCTION FC112 : VOID
VAR_INPUT

DB_Number_Real : BLOCK_DB;
DB_number_string: BLOCK_DB;
DB_String_Address : INT;
DB_real_address:INT;

END_VAR

VAR_TEMP

Decimal : INT;
Length:INT;

Temper_string:STRING[6];
leftstring:STRING[4];
rightstring:STRING[4];
d_factor:INT;
temper_real:REAL;

StringDST : ANY; // Any type refers to unknown variable type.

String_from_db AT StringDST : STRUCT
wType:WORD;
iLength:INT;
wDB:WORD;
dwArea:DWORD;
END_STRUCT;

real_locate: ANY;

Destination AT real_locate: STRUCT
wType:WORD;
iLength:INT;
wDB:WORD;
dwArea:DWORD;
END_STRUCT;

real_offset:WORD;
wStringOffset : WORD;
iSFCError : INT;

END_VAR
BEGIN

wStringOffset := INT_TO_WORD(8 * DB_String_Address);
real_offset:=Int_TO_WORD(4 * DB_real_Address);


// Data stucture of the "ANY" Type variable. Refer to ANY type in help for block diagram
STRING_from_DB.wType := w#16#1002; //any pointer for destination of string
STRING_from_DB.iLength := 8; // Set the length to 6: 8 String + 2 for the stuf in the beginning
STRING_from_DB.wDB := BLOCK_DB_TO_WORD(DB_number_string);
STRING_from_DB.dwArea:=dw#16#84000000 OR wStringOffset;





iSFCError:= BLKMOV(SRCBLK :=STRING_from_DB,DSTBLK :=temper_string );

// Find length for string value
Length := LEN(S:=temper_string);
Decimal:=FIND(In1:=temper_string,in2:='.');

IF decimal>0 THEN

CASE (length-decimal)of
1:d_factor:=10;
2:d_factor:=100;
3:d_factor:=1000;
4:d_factor:=10000;
ELSE: d_factor:=1;
END_CASE;

Leftstring:=LEFT(In:=temper_string,l:=(decimal-1));
rightstring:=RIGHT(in:=temper_string,l:=(length-decimal));
temper_real:=(STRING_TO_INT(in:=rightstring))/d_factor;

temper_real:=temper_real+ STRING_TO_INT(in:=leftstring);

ELSE
temper_real:=STRING_TO_INT(in:=temper_string);
END_IF;

Destination.wType:=w#16#1005;// type real// data
Destination.ilength:=4;
Destination.wDB:=BLOCK_DB_TO_WORD(DB_Number_Real);
Destination.dwArea:=dw#16#84000000 OR real_offset;

iSFCError:= BLKMOV(SRCBLK :=temper_real,DSTBLK :=Destination );




END_FUNCTION
 
It is not clear at all.
So the number of decimals varies ?
Does the STRING length vary ? (i.e. the length byte gets set correctly ?).
Or is it just a series of CHARs ?

"0.01" is a STRING[4]
"12.35" is a STRING[5]
"5" is a STRING[1]
 
Thanks Jesper for your reply

The strings are not more than 7byte. They are all in String type not CHAR. The length and decimal point will be varied because the number can be from 0.001 to 999.999. Those string may shorter than 7bytes like "5" which length=1, so that is why the len function need to be call.

michaelchenca
 
The source string DB has 300 strings, each string length in DB is set to be 7bytes but it will depend on the number. the target real DB each real is 4 bytes
 
The string DB's data (string) are come from HMI smarttags which read from USB memory and convert from textline to each individual real number string and write to PLC string DB.
 
Code is riddled with errors. Here it is re-coded without using SFC20.

Code:
FUNCTION FC112 : VOID
VAR_INPUT

DB_Number_Real : BLOCK_DB;
DB_number_string: BLOCK_DB;
DB_String_Address : INT;
DB_real_address:INT;

END_VAR

VAR_TEMP

Decimal : INT;
Length:INT;
i:INT;
Temper_string:STRING[7];
abData AT Temper_string:ARRAY[1..9] OF BYTE;
leftstring:STRING[4];
rightstring:STRING[4];
d_factor:REAL;
temper_real:REAL;
dwReal AT temper_real:DWORD;
END_VAR
BEGIN

//copy string from DB to temp variable
FOR i:=1 TO 9 DO
 abData[i]:=DB_number_string.DB[DB_String_Address+i-1];    
END_FOR;
// Find length for string value
Length := LEN(S:=temper_string);
Decimal:=FIND(In1:=temper_string,in2:='.');

IF decimal>0 THEN

CASE (length-decimal)of
1:d_factor:=10.0;
2:d_factor:=100.0;
3:d_factor:=1000.0;
4:d_factor:=10000.0;
ELSE: d_factor:=1.0;
END_CASE;
//always init temp strings before use
Leftstring:='';
RightString:='';
Leftstring:=LEFT(In:=temper_string,l:=(decimal-1));
rightstring:=RIGHT(in:=temper_string,l:=(length-decimal));

temper_real:=DINT_TO_REAL(INT_TO_DINT((STRING_TO_INT(in:=rightstring))))/d_factor;
temper_real:=temper_real+ STRING_TO_INT(in:=leftstring);
ELSE
temper_real:=STRING_TO_INT(in:=temper_string);
END_IF;
//Write resultant real
DB_Number_Real.DD[DB_real_address]:=dwReal;

END_FUNCTION
 
So the source is a text string in a text file.
And it has to pass via HMI tags that are formatted as STRING[7].
The HMI will take care of setting the length byte.
Apart from this, there is no check for STRINGs that do not adhere to the format of 3 integer digits, a decimal point, and 3 fractional digits.

The above sounds simple enough, but it is really a very special format that will take some code chewing to process into a bona fide REAL.

It is too late in the evening now to write a complete SCL code sample. Maybe tomorrow.
You have to decide if you want to check if the STRING is formatted correctly.
Think about that only "0"-"9" and "." are allowed.
Only one occurrence of "." is allowed.
At least 1 integer digit, max 3 integer digits.
If there is a ".", there must be 1-3 fractional digits.
 
Next time use an FB so you can declare your variables as STATs - you can then monitor your variables in the instance DB. You cannot monitor variables in the temp area unless you put in specific code to read them.
 
Last edited:
I do a minor change to establish a loop to 300 time. But the real DB turn out the value mass. Following are my change

FUNCTION FC112 : VOID
VAR_INPUT

DB_Number_Real : BLOCK_DB;
DB_number_string: BLOCK_DB;

END_VAR

VAR_TEMP


Decimal : INT;
Length:INT;
i:INT;
Address_pointer:INT;
Temper_string:STRING[7];
abData AT Temper_string:ARRAY[1..9] OF BYTE;
leftstring:STRING[4];
rightstring:STRING[4];
d_factor:REAL;
temper_real:REAL;
dwReal AT temper_real:DWORD;
END_VAR
BEGIN

FOR Address_pointer:=0 TO 299 DO

//copy string from DB to temp variable
FOR i:=1 TO 9 DO
abData:=DB_number_string.DB[Address_pointer+i-1];
END_FOR;
// Find length for string value
Length := LEN(S:=temper_string);
Decimal:=FIND(In1:=temper_string,in2:='.');

IF decimal>0 THEN

CASE (length-decimal)of
1:d_factor:=10.0;
2:d_factor:=100.0;
3:d_factor:=1000.0;
4:d_factor:=10000.0;
ELSE: d_factor:=1.0;
END_CASE;
//always init temp strings before use
Leftstring:='';
RightString:='';
Leftstring:=LEFT(In:=temper_string,l:=(decimal-1));
rightstring:=RIGHT(in:=temper_string,l:=(length-decimal));

temper_real:=DINT_TO_REAL(INT_TO_DINT((STRING_TO_INT(in:=rightstring))))/d_factor;
temper_real:=temper_real+ STRING_TO_INT(in:=leftstring);
ELSE
temper_real:=STRING_TO_INT(in:=temper_string);
END_IF;
//Write resultant real
DB_Number_Real.DD[Address_pointer]:=dwReal;
END_FOR;
 

Similar Topics

I feel like I'm going crazy, new to Siemens, coming from AB, and I cannot get a dang string copied in SCL. This is a S7-300, V16 PLC. I have a...
Replies
10
Views
3,501
How to realize transformation functions : 1/s and 1/(1+s) into SCL inside S7-300
Replies
0
Views
944
Hi. I tryid to make a shiftregister with 31 entry's. the string array are declared in the Static area of the FB. When I run the code its not...
Replies
1
Views
1,280
Looking for some help with an array of strings in SCL. I have an array of 99 string[98] I also have an array of 99 INT My first 4 chars of the...
Replies
9
Views
2,448
I am trying to take several individual CHAR bytes and turn them into a string. The CHAR bytes are located in a DB. I am trying to figure out the...
Replies
4
Views
3,502
Back
Top Bottom