Tips and tricks

Swap variabile DWORD

Ecco come utilizzare la funzione ROL per eseguire lo swap su variabile DWORD.

Nell’esempio Il valore 16#12345678 viene trasformato nel valore 16#56781234 e trasferito nella variabile VarOut.

Definizione variabili
image0

Esempio LD

image1

Esempio IL

LD 16#12345678
ROL 16
ST VarOut (* Output variable *)

Esempio ST

VarOut:=ROL(16#12345678, 16); (* Output variable *)

Swap variabile WORD

Ecco come utilizzare la funzione ROL per eseguire lo swap su variabile WORD.

Nell’esempio Il valore 16#1234 viene trasformato nel valore 16#3412 e trasferito nella variabile VarOut.

Definizione variabili
image2

Esempio LD

image3

Esempio IL

LD 16#1234
ROL 8
ST VarOut (* Output variable *)

Esempio ST

VarOut:=ROL(16#1234, 8); (* Output variable *)

Swap variabile BYTE

Ecco come utilizzare la funzione ROL per eseguire lo swap su variabile BYTE.

Nell’esempio Il valore 16#12 viene trasformato nel valore 16#21 e trasferito nella variabile VarOut.

Definizione variabili
image4

Esempio LD

image5

Esempio IL

LD 16#12
ROL 4
ST VarOut (* Output variable *)

Esempio ST

VarOut:=ROL(16#12, 4); (* Output variable *)

Espandere DWORD in 32 BOOL

Ecco un come utilizzando i blocchi funzione DoubleToWord, WordToByte, ByteToBit sia possibile espandere una variabile DWORD in 32 variabili BOOL.

Definizione variabili
image6

Esempio FBD (Ptp114a200, FBD_DWExpand)

image7

Comprimere 32 BOOL in DWORD

Ecco come utilizzando i blocchi funzione BitToByte, ByteToWord, WordToDouble sia possibile comprimere 32 variabili BOOL in una variabile DWORD.

Definizione variabili
image8

Esempio FBD (Ptp114a200, FBD_DWCompress)

image9

Definizione di “Format” nella SysVarsscanf

Come visto la funzione SysVarsscanf legge una stringa e ne interpreta il contenuto basandosi sul parametro Format. Questo parametro deve essere definito seguendo le indicazioni riportate nella tabella.

Specifier Meaning
%d An integer in normal decimal (that is, base-10) notation.
%o An integer in octal (base-8) notation.
%x An integer in hexadecimal (base-16) notation.
%D An integer in decimal, or (if it starts with 0) octal, or (if it starts with 0x) hexadecimal notation. Hence, sscanf(«12», «%D», i), sscanf(«014», «%D», i) and sscanf(«0xC», «%D», i) all yield the value 12 in i.
%f A floating-point number.
%c The character code of a single character.
%s A string. If %s is followed by %d, %s will read any non-numerical characters. If followed by %[], %s will read any characters not present in the set in the %[]. If followed by normal text, %s will match all characters up to, but not including, the first occurrence of that text.
%Ns As above, but a string of exactly N characters
%[chars]

A string containing any of the characters in the list characters.

A minus sign can be used to give a range of values, so e. g. %[a-d] means a string consisting of any of the characters a, b and c.

A ^ sign means «not», so e. g. %[^abc] means any character except a, b and c.

They can be combined, so %[a-cf] means a, b, c, and f.

%{format%} Repeatedly matches the format specifier format as many times as possible, and gives an array of arrays with the results. Example: %{%d%} matches zero or more integers.
%% A single percent (%) character.

Se viene posto un asterisco tra il segno % ed l’operatore (Esempio %*d) la funzione esegue la scansione dell’operatore ma non valorizza la variabile di ritorno. Questo può essere utile per saltare dalla stringa alcuni caratteri.

Le definizioni riportate possono essere modificate in accordo alle Regular expressions. Di seguito riporto uno screenshot di un programma di esempio.

image10

Come si vede nella scansione dei numeri è possibile definire il numero di cifre da acquisire. Ipotizzando una stringa del tipo “124.5” avremo:

SysVarsscanf(ADR(SSource), “%d”, USINT_TYPE Ritornerà il valore USINT 124 fermando la scansione al primo carattere che non è numerico (Il punto decimale).

SysVarsscanf(ADR(SSource), “%2d”, USINT_TYPE Ritornerà il valore USINT 12 fermando la scansione dopo 2 cifre.

SysVarsscanf(ADR(SSource), “%f”, REAL_TYPE Ritornerà il valore REAL 124.5 fermando la scansione al primo carattere che non è numerico (Lo spazio dopo il numero).

SysVarsscanf(ADR(SSource), “%2f”, REAL_TYPE Ritornerà il valore REAL 12 fermando la scansione dopo 2 cifre.

SysVarsscanf(ADR(SSource), “%s”, STRING_TYPE Ritornerà il valore STRING ab+cd:e fermando la scansione al terminatore di stringa.

SysVarsscanf(ADR(SSource), “%3s”, STRING_TYPE Ritornerà il valore STRING ab+ fermando la scansione dopo 3 caratteri.

SysVarsscanf(ADR(SSource), “%3[a-z]”, STRING_TYPE Ritornerà il valore STRING ab fermando la scansione al primo carattere che non è compreso nel range da a-z. Nel caso ci fossero stati più caratteri in quel range la scansione si sarebbe fermata al 3 carattere.

SysVarsscanf(ADR(SSource), “%[a-z]”, STRING_TYPE Ritornerà il valore STRING ab fermando la scansione al primo carattere che non è compreso nel range da a-z.

SysVarsscanf(ADR(SSource), “%[^+]”, STRING_TYPE Ritornerà il valore STRING ab fermando la scansione al primo carattere che non è diverso dal carattere “+”.

SysVarsscanf(ADR(SSource), “%[^:]”, STRING_TYPE Ritornerà il valore STRING ab+cd fermando la scansione al primo carattere che non è diverso dal carattere “:”.

Definire caratteri ascii non stampabili

Nella gestione di protocolli di comunicazione e/o per impostare modalità di stampa su stampanti necessita eseguire l’output di caratteri ascii non stampabili, cioè caratteri con codici inferiori al 16#20 o superiori al 16#7F.

Per la definizione dei caratteri ascii stampabili basta includere tra apici singoli i caratteri (Esempio “abcd”).

Per i caratteri non stampabili, occorre anteporre al valore esadecimale del carattere il simbolo $, quindi per il carattere di <STX> 16#02 avremo la definizione “$02”, per <ETX> “$03” e così di seguito.

Ricordo che alcuni caratteri di controllo come il line feed, codice 16#0A, sia possibile definirli sia come “$0A” che come “$l”. Il carriage return, codice 16#0D, è possibile definirlo sia come “$0D” che come “$r”. Riporto tabella esplicativa.

Sequenza Significato Esadecimale Esempio
$$ Carattere $ 16#24 ’I paid $$5 for this’
$” Apostrofo 16#27 ’Enter $’Y$’ for YES’
$l Line feed 16#0A ’next $l line’
$r Carriage return 16#0D “Hello$r”
$n New line 16#0D0A ’This is a line$n’
$p New page 16#0C ’last line $p first line’
$t Tabulazione 16#09 ’name$tsize$tdate’
$hh   16#hh ’ABCD = $41$42$43$44’

Ecco un esempio di utilizzo della funzione SysVarfprintf per definire oltre ai caratteri stampabili anche i caratteri non stampabili ed inviarli verso lo stream di uscita. In questo esempio viene inviato verso la porta seriale COM0 la stringa [Ciao] seguita da carriage return e line feed.

Definizione variabili
image11
Esempio LD
image12

Rx/Tx dati su stream

Come si è visto con la funzione Sysfopen è possibile definire un collegamento tra una risorsa di I/O ed un flusso di dati stream da cui è possibile gestire la ricezione e/o la trasmissione di dati.

Per la ricezione dei dati in ingresso dallo stream si utilizza la funzione per controllo se dati presenti SysGetIChars e la funzione per la lettura degli stessi Sysfgetc.

Definizione variabili
image13

Esempio ST

(* Rx data from stream. *)
Ptr:=ADR(RxString); (* String pointer *)
WHILE (TO_BOOL(SysGetIChars(File))) DO
@Ptr:=TO_USINT(Sysfgetc(File)); (* Rx string *)
Ptr:=Ptr+1; (* String pointer *)
(* Check if string pointer overflow. *)
IF (Ptr > ADR(RxString)+31) THEN EXIT; END_IF;
END_WHILE;

Per la trasmissione dei dati in uscita dallo stream si utilizza la funzione che controlla se spazio disponibile SysGetOSpace, e se lo spazio è sufficiente a contenere la stringa, o come nell’esempio, se il buffer di uscita è vuoto è possibile trasferire la stringa sullo stream con la funzione SysVarfprintf.

Definizione variabili
image14

Esempio ST

(* Tx data to stream. *)
IF (TO_UDINT(SysGetOSpace(File)) = SysGetTxBSize(File)) THEN
i:=TO_UINT(SysVarfprintf(File, '%s', STRING_TYPE, ADR(TxString)));
END_IF;

Conversione tipo dati

La conversione dei dati (Detto anche casting) è una pratica necessaria nella programmazione, naturalmente se il tipo dati di destinazione ha un range inferiore del tipo dati di origine viene effettuato un troncamento del valore. Vediamo caso per caso le varie conversioni:

Tipo BOOL: Le conversioni da qualsiasi tipo verso un BOOL, tornano FALSE se il valore del dato da convertire è 0. Tornano TRUE se il valore del dato da convertire è diverso da 0 (anche < 0).

Tipo SINT/USINT: Le conversioni da qualsiasi tipo verso un USINT, tornano il valore del byte meno significativo del valore da convertire espresso in esadecimale. Esempio il valore 4660 (16#1234) tornerà 52 (16#34), lo stesso vale per i REAL esempio 300.0 (16#012C) tornerà 44 (16#2C). Per il tipo SINT se il valore esadecimale supera 127 il numero sarà negativo.

Tipo INT/UINT: Le conversioni da qualsiasi tipo verso un UINT, tornano il valore dei due bytes meno significativi del valore da convertire espresso in esadecimale. Esempio il valore 305419896 (16#12345678) tornerà 22136 (16#5678), lo stesso vale per i REAL esempio 90000.0 (16#15F90) tornerà 24464 (16#5F90). Per il tipo INT se il valore esadecimale supera 32767 il numero sarà negativo.

Nella programmazione IEC con LogicLab sono previste apposite funzioni di conversione di tipo, vediamole.

Name Input type Output type Function
TO_BOOL Any BOOL Converts any data type into a boolean
TO_SINT Any SINT Converts any data type into a short integer (8 bits, signed)
TO_USINT Any USINT Converts any data type into an unsigned short integer (8 bits, unsigned)
TO_INT Any INT Converts any data type into an integer (16 bits, signed)
TO_UINT Any UINT Converts any data type into an unsigned integer (16 bits, unsigned)
TO_DINT Any DINT Converts any data type into a long integer (32 bits, signed)
TO_UDINT Any UDINT Converts any data type into an unsigned long integer (32 bits, unsigned)
TO_REAL Any REAL Converts any data type into a floating point (32 bits, signed)

Esempi

Conversione di una variabile di tipo DINT in una variabile di tipo USINT nei diversi linguaggi di programmazione. Naturalmente se il valore della variabile VarDINT supera il valore 255 (Limite della variabile VarUSINT), verrà ritornato il resto della divisione per il limite.

Definizione variabili
image15

Esempio FBD

image16

Esempio LD

image17

Esempio IL

LD VarDINT (* DINT variable *)
TO_USINT
ST VarUSINT (* USINT variable *)

Esempio ST

VarUSINT:=TO_USINT(VarDINT); (* USINT variable *)

User Informations and Settings

E” previsto un interfacciamento tra il programma utente PLC ed il sistema operativo, questo permette di visualizzare ed impostare da sistema operativo variabili il cui valore è disponibile all’interno del programma utente.

SysUInfoA, SysUInfoB, SysUInfoC, SysUInfoD, 4 variabili stringa da 16 caratteri, che possono essere valorizzate da programma utente e visualizzabili da sistema operativo.

SysUSetA, SysUSetB, SysUSetC, SysUSetD, 4 variabili stringa da 16 caratteri, che possono essere valorizzate da sistema operativo e utilizzate da programma utente.

E” prevista una pagina web (Menù User) in cui sono visualizzate le variabili SysUInfo(x) ed è possibile impostare le variabili SysUSet(x).

image18

Nell’esempio riporto un semplice programma che acquisisce i valori delle variabili SysUSet(x) e li trasferisce nella rispettiva variabile di visualizzazione SysUInfo(x). Nella pagina web il valore impostato nella variabile SysUSet(x) su accettazione con il tasto Write verrà ritornato nella variabile SysUInfo(x) come visibile dallo screenshot riportato sopra.

Definizione variabili
image19

Esempio ST

(* Read user settings and write user infos. *)
IF (SysUVSet) THEN
i:=SysVarsscanf(ADR(SysUSetA), '%d', UDINT_TYPE, ADR(Values[0]));
i:=SysVarsnprintf(ADR(SysUInfoA), 16, '%d', UDINT_TYPE, ADR(Values[0]));
i:=SysVarsscanf(ADR(SysUSetB), '%d', UDINT_TYPE, ADR(Values[1]));
i:=SysVarsnprintf(ADR(SysUInfoB), 16, '%d', UDINT_TYPE, ADR(Values[1]));
i:=SysVarsscanf(ADR(SysUSetC), '%d', UDINT_TYPE, ADR(Values[2]));
i:=SysVarsnprintf(ADR(SysUInfoC), 16, '%d', UDINT_TYPE, ADR(Values[2]));
i:=SysVarsscanf(ADR(SysUSetD), '%d', UDINT_TYPE, ADR(Values[3]));
i:=SysVarsnprintf(ADR(SysUInfoD), 16, '%d', UDINT_TYPE, ADR(Values[3]));
END_IF;

Aggiungere porte seriali

Sui dispositivi dotati di connessione Ethernet è possibile aggiungere porte seriali utilizzando dei convertitori Ethernet/Seriale. Ecco lo screenshot di un programma LD che utilizza un convertitore ATC1000 configurato come server per aggiungere una porta seriale da utilizzare per una connessione Modbus.

image20

Se configuri il convertitore come server TCP devi utilizzare il FB SysTCPClient per connetterti al convertitore e poi potrai utilizzare il file pointer in uscita al FB per gestire il tuo protocollo di comunicazione.

Nel mio esempio ho scelto una configurazione dove il convertitore Ethernet/Seriale agisce da server TCP e lo SlimLine da Client, ma naturalmente puoi invertire i ruoli. Oppure puoi utilizzare una connessione UDP. Se hai più porte seriali da aggiungere dovrai istanziare più FB SysTCPClient, una per ogni porta COM aggiuntiva.

Naturalmente il modo di comunicazione RS232/RS485 ed i parametri, baudrate, parità, bits vanno impostati tramite la pagina web di configurazione del convertitore.