Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

9
voti

Linguaggi di programmazione dei PLC Siemens

Questo è il primo articolo che scrivo che tratta argomenti inerenti al mio lavoro, proverò a fare un riassunto delle tipologie di linguaggi disponibili per la programmazione dei PLC nel mondo Siemens (famiglia S7), portando qualche semplice esempio concreto.
Le "nuove" generazioni di PLC S7-1200 e S7-1500 uscite ormai già da qualche anno, unite all'ambiente di sviluppo TIA Portal che ha soppiantato il Simatic Manager, hanno portato ad una modifica di rotta rendendo di fatto obsoleto un certo modo di programmare.

Indice

1. Premessa

Lo standard IEC 61131-3, nato ancora nel 1993 e voluto dall'organizzazione PLCopen, definisce gli elementi base per la programmazione nell'automazione industriale con PLC, quali linguaggi, tipi di dati ed unità organizzative del software.
I linguaggi previsti sono quattro, due di tipo grafico:

  • diagramma a contatti - LD (Ladder Diagram)
  • diagramma a blocchi funzione - FBD (Function Block Diagram)

e due di tipo testuale:

  • lista istruzioni - IL (Instruction List) - dichiarato deprecato dalla terza revisione dello standard (2012)
  • testo strutturato - ST (Structured Text)

A questi si aggiunge il diagramma funzionale sequenziale - SFC (Sequential Function Chart), derivato dal Grafcet e che permette di descrivere graficamente le sequenze di un sistema di automazione.

Figura 1 - I cinque linguaggi IEC 61131-3

Figura 1 - I cinque linguaggi IEC 61131-3


La standardizzazione è molto importante, sia per ridurre i costi/tempi di formazione, sia per facilitare la portabilità del codice o almeno di alcuni moduli, anche se è innegabile che i PLC commerciali presentano spesso delle peculiarità legate al costruttore, come l'esatta sintassi di un particolare linguaggio o le modalità di dichiarazione delle variabili.
Io francamente avrei inserito nella lista anche un linguaggio standard come il C, ma è un mio punta di vista personale.

Per quanto riguarda Siemens, i corrispondenti linguaggi sono:

  • diagramma a contatti: KOP (Kontactplan)
  • diagramma a blocchi funzione: FUP (Functionsplan)
  • lista istruzioni: AWL (Anweisungsliste) / STL (Statement List)
  • testo strutturato: SCL (Structured Control Language)
  • diagramma funzionale sequenziale: GRAPH

Per le CPU S7-1200 non sono disponibili i linguaggi AWL e GRAPH.

2. Introduzione

In ogni CPU è già presente un sistema operativo che organizza le varie funzioni, ad esempio:

  • aggiornamento dell'immagine di processo degli ingressi e delle uscite
  • richiamo del programma utente
  • gestione degli errori
  • identificazione di allarmi e richiamo dei rispettivi OB


Figura 2 - Sistema operativo e programma utente

Figura 2 - Sistema operativo e programma utente


Il programma utente elabora il compito specifico di automazione e viene caricato nella CPU.

A meno che non si tratti di poche operazioni e davvero molto semplici, è sconsigliato implementare tutto il codice del programma utente in un unico blocco, per fare un paragone con altri ambiti, sarebbe come scrivere un intero programma C nella funzione Main.
Per questo motivo è previsto che il codice venga organizzato in blocchi (programmazione strutturata), in questo modo possono essere resi più o meno generici e riutilizzabili alcuni moduli, il tutto diventa più leggibile, sezionabile per il debug, modificabile da altri.
La profondità massima di annidamento varia a seconda della famiglia di CPU, ad esempio per S7-300 e S7-1200 si può arrivare ad una profondità di 16 blocchi per classe di priorità, per S7-400 e S7-1500 la profondità massima è di 24 blocchi.

Quando viene richiamato un blocco, ne vengono elaborate le istruzioni fino al termine, di seguito l'elaborazione viene ripresa dall'istruzione successiva del blocco richiamante:

Figura 3 - Richiamo di un blocco

Figura 3 - Richiamo di un blocco


2.1 Ambiente di sviluppo

L'ambiente di sviluppo attuale è TIA (Totally Integrated Automation) Portal, una piattaforma modulare pensata per tutti i compiti di automazione, che consente di installare i vari moduli in modo da avere poi tutto in una unica applicazione, il modulo per lo sviluppo del PLC è STEP 7, la versione basic consente di programmare solo la famiglia S7-1200, quella professional anche S7-300/400/1500.
Il pacchetto PLCSIM consente la simulazione del programma PLC e potrebbe essere molto utile.
In precedenza vi erano più applicazioni separate: Simatic Step 7 per i PLC, Starter per gli azionamenti, WinCC per i pannelli, ecc.

Questo articolo fa riferimento a TIA Portal V16.

2.2 Tipi di blocchi

Le tipologia di blocchi disponibili sono:

  • blocchi organizzativi - OB
  • funzioni - FC
  • blocchi funzionali - FB
  • blocchi dati - DB


Figura 4 - Tipi di blocchi

Figura 4 - Tipi di blocchi


Per ciascun blocco di codice (OB-FC-FB) può essere specificato il linguaggio di programmazione, in modo da utilizzare quello più adatto a seconda dell'operazione da eseguire.

Figura 5 - Inserimento di un blocco

Figura 5 - Inserimento di un blocco


I blocchi in linguaggio AWL-KOP-FUP sono ulteriormente divisi in segmenti, ciascuno con un rispettivo titolo e commento.

Si può sempre commutare il linguaggio di programmazione tra KOP e FUP, cambierà anche la rappresentazione grafica di quanto già scritto. Si può inoltre avere una programmazione mista anche all'interno del blocco:

  • con le CPU S7-300 e S7-400 nei blocchi KOP e FUP possono essere inseriti segmenti AWL
  • con le CPU S7-1200 e S7-1500,nei blocchi KOP e FUP possono essere inseriti segmenti SCL


E' bene inoltre abituarsi ad usare le proprietà dei blocchi per memorizzare almeno la versione e l'autore, magari con un commento esteso.

2.2.1 Blocchi organizzativi [OB]

I blocchi organizzativi sono l'interfaccia tra sistema operativo e programma utente, vengono richiamati dal sistema, a seconda della CPU impiegata possono essere disponibili blocchi organizzativi diversi.
OB1 è l'unico blocco presente alla creazione di un nuovo progetto, gli altri possono essere inseriti e programmati per determinare il funzionamento della CPU a seconda dell'evento. Nelle ultime versioni di TIA Portal è possibile modificare anche il numero di questi blocchi organizzativi.
I principali OB sono:

  • OB1 (Program Cycle), viene elaborato ciclicamente e rappresenta il programma principale (Main), il tempo ciclo è variabile e dipende dalle operazioni svolte
  • OB100 (Startup), viene elaborato una volta sola, all'avvio, nel momento in cui la CPU passa dallo stato STOP a RUN
  • OB30-38 (Cyclic Interrupt), vengono elaborati ad intervalli regolari (schedulazione orologio) interrompendo OB1, quindi in maniera indipendente dal tempo di scansione, se si imposta un intervallo troppo basso che non si riesce a rispettare, viene avviato un OB di allarme
  • OB40-48 (Hardware Interrupt), vengono richiamati in corrispondenza di uno specifico evento HW assegnato, ad esempio l'attivazione di un ingresso, interrompendo anche in questo caso OB1
  • OB80 (Time Error Interrupt), viene richiamato nel caso di superamento del tempo ciclo massimo impostato (Watch Dog)
  • OB82 (Diagnostic Error Interrupt), viene richiamato in caso di rilevamento di un errore da parte di un'unità con funzioni di diagnostica
  • OB83 (Pull or Plug of Modules), viene richiamato in caso di estrazione/inserimento di moduli progettati
  • OB86 (Rack or Station Failure), viene richiamato in caso di guasto di un telaio di montaggio o in periferia decentrata (bus di campo)
  • OB121 (Programming Error), viene richiamato se si verifica un errore durante l'elaborazione del programma

Per gli OB sono selezionabili i linguaggi KOP-FUP-SCL-AWL (quest'ultimo non con S7-1200).

2.2.2 Funzioni [FC]

Le funzioni sono blocchi di codice senza memoria, possono essere richiamate più volte ed in punti diversi, direttamente dal programma principale o da altre FC/FB. Possono ricevere e restituire uno o più parametri al chiamante e possono accedere alle variabili globali (DB o merker), ma non hanno una memoria interna statica.
L'editor dei blocchi di codice è diviso in due parti, nella parte superiore è visibile l'interfaccia del blocco, in quella inferiore il codice:

Figura 6 - Interfaccia blocchi FC

Figura 6 - Interfaccia blocchi FC


Nell'interfaccia possono essere definiti le seguenti tipologie di parametri:

  • Input: parametri in ingresso letti dal blocco
  • Output: parametri in uscita scritti dal blocco
  • InOut: parametri di transito, letti dal blocco al richiamo e modificabili dallo stesso
  • Temp: definizione di variabili locali temporanee, permettono il salvataggio di risultati intermedi, prima di utilizzare questi parametri è buona norma inizializzarli (a seconda del tipo di accesso e del tipo di dato potrebbero assumere dei valori casuali all'entrata nel blocco)
  • Constant: definizione di costanti locali
  • Return: valore restituito al blocco chiamante, è paragonabile ad un parametro Output, ma può risultare comodo con il linguaggio SCL per scrivere espressioni matematiche o valutazioni logiche su una riga come in altri linguaggi

L'assegnazione dei parametri Input/Output/InOut al richiamo del blocco avviene come copia (call by value) nel caso di dati semplici, mentre avviene tramite puntatore (call by reference) nel caso di dati strutturati.

Per gli FC sono selezionabili i linguaggi KOP-FUP-SCL-AWL (quest'ultimo non con S7-1200).

2.2.3 Blocchi funzionali [FB]

I blocchi funzionali hanno una caratteristica importante rispetto alle funzioni: vengono richiamati con un blocco dati di istanza, infatti vengono anche definiti "blocchi con memoria".
Rispetto alle FC:

  • i parametri in ingresso, uscita e transito vengono memorizzati in modo permanente nel blocco dati di istanza, se ne potrà disporre anche dopo l'elaborazione, per le variabili di ingresso si può impostare anche un valore predefinito del parametro (quindi ad esempio è possibile non passare tutti i parametri)
  • nell'interfaccia del blocco sarà disponibile una sezione Static, dove è possibile definire variabili che manterranno il valore tra una chiamata e l'altra, anche per queste variabili è possibile impostare un valore iniziale
  • nell'interfaccia del blocco non sarà disponibile il parametro Return, specifico delle FC
  • tutte le variabili dell'interfaccia del blocco, escluso le Temp e Constant, saranno disponibili nel blocco dati di istanza


Come per le FC, i blocchi funzionali possono essere richiamate più volte ed in punti diversi, direttamente dal programma principale o da altre FC/FB e possono accedere alle variabili globali (DB o merker).

Il blocco funzionale può salvare i propri dati specifici dell'istanza in un proprio DB o nel DB di istanza del FB richiamante (multi-istanza), per fare questo si dichiara il blocco FB da richiamare tra i dati Static.

I blocchi funzionali permettono di lavorare a moduli, facendo attenzione è possibile impostare anche sul PLC una programmazione orientata agli oggetti, anche se rudimentale, consideriamo un FBx come una classe:

  • si può impostare l'interfaccia del blocco verso l'esterno
  • nei dati Static abbiamo la memorizzazione dei membri della classe
  • con la multi-istanza possiamo avere delle sotto-classi all'interno del blocco
  • un blocco dati di istanza è come un oggetto, ovvero una istanza della classe FBx

per lavorare così non si dovrà far riferimento a variabili globali all'interno del blocco e non si dovrà accedere al DB di istanza da altre funzioni.

L'assegnazione dei parametri Input/Output/InOut al richiamo del blocco avviene sempre come copia (call by value), tranne nel caso di dati strutturati di transito InOut, che avviene tramite puntatore (call by reference), a meno di casi particolari.
Ne consegue che, a livello di efficienza, è meglio dichiarare nella sezione InOut parametri come strutture dati, in modo da evitare un'inutile copia ed accedervi mediante puntatore.

Per gli FB sono selezionabili i linguaggi KOP-FUP-SCL-AWL-GRAPH (gli ultimi due non con S7-1200).

2.2.4 Blocchi dati [DB]

I blocchi dati sono usati per memorizzare i dati del programma utente. Possono essere:

  • DB globali: strutture definite a piacere con variabili visibili da tutti gli altri blocchi
  • DB di istanza: sono usati per gestire i dati delle singole istanze degli FB
  • DB array: disponibili solo con S7-1500 per utilizzi particolari


I blocchi dati per S7-1200 o S7-1500 possono avere accesso ottimizzato o standard (quelli per S7-300 o S7-400 solo standard), l'impostazione è modificabile nelle Proprietà->Attributi del blocco e di default l'accesso ottimizzato è attivo:

Figura 7 - Accesso ottimizzato al blocco

Figura 7 - Accesso ottimizzato al blocco

I blocchi con accesso ottimizzato non dispongono di una struttura definita, gli elementi contengono solo il nome simbolico e non l'indirizzo, mentre in quelli con accesso standard, oltre al nome simbolico è visibile la colonna offset e diventa possibile accedere alla variabile anche attraverso il suo indirizzo assoluto in memoria.

L'accesso non ottimizzato è stato mantenuto per consentire l'interfacciamento con terze parti che necessitano di conoscere gli indirizzi delle variabili, altrimenti l'uso del simbolico è fortemente consigliato:

  • l'accesso ai dati è più veloce in quanto gestito dal sistema
  • è possibile definire la ritentività per le singole variabili, in caso contrario si può impostare la ritentività solo per l'intero DB
  • l'indirizzamento assoluto è sempre meno necessario, oltre che più scomodo, protocolli come OPC-UA lavorano in simbolico e da codice è possibile comunque accedere (accessi slice) a singoli bit , byte o word di una variabile, ad esempio #<nome-var>.%X3 per accedere al bit 0.3 di una bitmask


L'accesso ottimizzato lavora in maniera differente tra S7-1200 e S7-1500.
Nel primo caso viene ottimizzata l'occupazione in memoria, salvando le variabili più grandi (come larghezza) all'inizio del blocco e quelle più piccole alla fine:

Figura 8 - Accesso ottimizzato in S7-1200

Figura 8 - Accesso ottimizzato in S7-1200

Nel secondo caso viene privilegiata la performance ed i singoli bit occupano un byte per evitare il mascheramento nelle operazioni booleane a bit:

Figura 9 - Accesso ottimizzato in S7-1500

Figura 9 - Accesso ottimizzato in S7-1500


L'accesso ottimizzato è una impostazione disponibile anche per altri blocchi, per gli FB determina come viene creato il DB di istanza, per gli FC l'indirizzamento delle variabili locali.

2.3 Variabili

Le principali aree degli operandi sono:

  • immagine di processo degli ingressi - %I
  • immagine di processo delle uscite - %Q
  • merker - %M - utilizzo deprecato
  • contatori - %C - utilizzo deprecato
  • temporizzatori - %T - utilizzo deprecato
  • blocchi dati - %DB
  • dati locali - %L

Sono tutte aree globali, tranne i dati locali (Temp) dei blocchi.

Le aree di memoria sono organizzate in byte, la notazione con % rappresenta un indirizzamento assoluto:

  • %I3.7 - ingresso byte 3, bit 7
  • %M10.0 - merker byte 10, bit 0
  •  %Q5.8 - uscita con indirizzo errato, l'accesso a bit deve essere compreso tra x.0 e x.7
  • %DB2.DBB3 - blocco dati 2, byte 3
  • %MW50 - merker word 50 (byte 50 e 51)
  • %ID4 - ingressi double-word 4 (byte 4-5-6-7)

Mentre con le CPU S7/300-400 l'indirizzamento assoluto era molto utilizzato anche per questioni di performance, con le S7-1200/1500 Siemems consiglia fortemente l'indirizzamento simbolico e l'utilizzo dell'accesso ottimizzato ai blocchi, sconsigliando l'utilizzo di variabili globali come merker, temporizzatori e contatori, da sostituire con variabili di blocco, timer e counter IEC (utilizzabili con i propri DB di istanza o in multi-istanza) in modo da favorire lo sviluppo di moduli generici e riutilizzabili.

Con le tabelle delle variabili è possibile gestire i nomi simbolici delle variabili globali, che vanno richiamati tra apici "nome-var", mentre nell'interfaccia del blocco si gestiscono le variabili di blocco viste in precedenza (Input/Output/InOut/Static/Temp), che vanno richiamate con la notazione #nome-var.

Gli accessi slice (solo per S7-1200/1500) accennati in precedenza consentono un indirizzamento mirato all'interno delle variabili dichiarate:

  • #nome-var.%X<numero bit>
  • #nome-var.%B<numero byte>
  • #nome-var.%W<numero word>
  • #nome-var.%D<numero double-word>


2.3.1 Tipi di dati

Per i tipi di dati bisognerebbe scrivere un articolo a parte, potete avere un'infarinata leggendo questo vecchio articolo, che è ancora valido.
Qui vi riporto una tabella riassuntiva con le disponibilità a seconda della CPU:

Numeri binari S7-300/400 S7-1200 S7-1500
BOOL X X X
Bitmask S7-300/400 S7-1200 S7-1500
BYTE (8 bit) X X X
WORD (2 byte) X X X
DWORD - Double WORD (4 byte) X X X
LWORD - Long WORD (8 byte) - - X
Numeri interi S7-300/400 S7-1200 S7-1500
SINT - Short INT (1 byte) - X X
INT (2 byte) X X X
DINT - Double INT (4 byte) X X X
USINT - Unsigned Short INT (1 byte) - X X
UINT - Unsigned INT (2 byte) - X X
UDINT - Unsigned Double INT (4 byte) - X X
LINT - Long INT (8 byte) - - X
ULINT - Unsigned Long INT (8 byte) - - X
Numeri in virgola mobile S7-300/400 S7-1200 S7-1500
REAL (4 byte) X X X
LREAL - Long REAL (8 byte) - X X
Tempo S7-300/400 S7-1200 S7-1500
S5TIME - formato BCD (2 byte) - deprecato X - X
TIME (4 byte) [ms] X X X
LTIME - Long TIME (8 byte) [ns] - - X
Data e ora S7-300/400 S7-1200 S7-1500
DATE (2 byte) [days] X X X
TOD - Time of day (4 byte) [ms] X X X
LTOD - Long time of day (8 byte) [ns] - - X
DT - Date and time (8 byte) x - X
LDT - Date and long time (8 byte) - - X
DTL - X X
Stringhe S7-300/400 S7-1200 S7-1500
CHAR (1 byte) X X X
WCHAR - Wide CHAR (2 byte) - X X
STRING (len+2 byte) X X X
WSTRING - Wide CHAR STRING (len+2 word) - X X
Tipo di dati definiti dall'utente (UDT) S7-300/400 S7-1200 S7-1500
UDT X X X
Strutture dati anonime S7-300/400 S7-1200 S7-1500
STRUCT X X X
Array S7-300/400 S7-1200 S7-1500
ARRAY [] of <data type> X X X
Puntatori S7-300/400 S7-1200 S7-1500
REF_TO <data type> - - X
VARIANT - X X
POINTER (6 byte) X - X
ANY (10 byte) X - X


2.3.2 Temporizzatori e contatori

Pe evitare di usare i timer e counter globali e rendere riutilizzabili i blocchi di codice, abbiamo a disposizione degli FB di sistema (SFB) che implementano le tipologie più utilizzate (qualche informazione sui timer la trovate anche in questo mio articolo) e che necessitano di un DB di istanza:

Timer IEC
  • TON - temporizzatore ritardato all'inserzione
  • TOF - temporizzatore ritardato alla disinserzione
  • TP - temporizzatore ad impulso (genera un impulso di durata impostata)
  • TONR - temporizzatore ritardato all'inserzione ritentivo (con memoria) ovvero quando l'ingresso va a FALSE il conteggio non viene resettato

l'interfaccia di questi blocchi prevede i seguenti parametri di IN/OUT:

  • IN (Input) - condizioni per l’avvio del timer [BOOL]
  • PT (Input) - tempo di conteggio [TIME,LTIME]
  • Q (Output) - stato del timer [BOOL]
  • ET (Output) - valore attuale del conteggio [TIME,LTIME]
  • R (Input) - resetta il timer [BOOL] - solo con TONR


Counter IEC
  • CTU - conteggio in avanti
  • CTD - conteggio all'indietro
  • CTUD - conteggio in avanti ed all'indietro

I contatori incrementano o decrementano ll conteggio in corrispondenza di un fronte sull'ingresso, a seconda della tipologia lo stato commuta con il raggiungimento di una soglia impostata.

3. Linguaggi

Facciamo una breve carrellata sui linguaggi di programmazione, per poi tornarci con degli esempi.

3.1 KOP (Ladder Diagram)

Il diagramma a contatti è uno dei primi linguaggi utilizzati sui PLC, molto amato dai manutentori e dal service per l'immediatezza nel seguire le combinazioni logiche, si può in prima battuta immaginare di ruotare in orizzontale i vari rami di uno schema funzionale, dando la vaga impressione di una "scala a pioli" (ladder), la rappresentazione è quindi basata sui circuiti elettromeccanici, i rami sono anche detti rung.

Figura 10 - Ladder Diagram

Figura 10 - Ladder Diagram


3.2 FUP (Function Block Diagram)

Il diagramma a blocchi funzione è un altro linguaggio grafico, la rappresentazione è basata sui sistemi circuitali elettronici. Ogni segmento contiene i vari percorsi logici e le interrogazioni dei segnali vengono collegate tra di loro mediante dei blocchetti.
Alcuni lo preferiscono al KOP quando si hanno molti rami, io li trovo equivalenti.

Figura 11 - Function Block Diagram

Figura 11 - Function Block Diagram


3.3 AWL (Instruction List)

AWL è la versione di Siemens della lista istruzioni, definito "hardware oriented", è un linguaggio di basso livello, il più vicino al linguaggio macchina tra quelli visti in precedenza, ricorda un po' l'assembly e lavora direttamente sui registri della CPU.

E' il linguaggio dove ho nettamente più esperienza: quando iniziai a lavorare, nel '95/96, Step 7 era una novità, la "vecchia guardia" era abituata con AWL dello Step 5 e la stessa Siemens definiva questo linguaggio come il più performante e con il set di istruzioni più ampio: se era sempre possibile passare da KOP/FUP ad AWL, non lo era il contrario. Certo può sembrare un po' ostico, ma quando poi ci si abitua ci si rende anche conto delle potenzialità, si imparano a dominare puntatori e registri di indirizzo, e con l'esperienza si mettono in atto varie accortezze.

Con le CPU S7-1200/1500 abbiamo una inversione di rotta:

  • le prestazioni superiori nell'usare questo linguaggio non sono più aprezzabili (i registri della CPU da quanto ho capito sono simulati ed i processori molto più veloci)
  • il linguaggio ad alto livello SCL non è più opzionale ma integrato nello Step 7 di TIA Portal e consente operazioni complesse con una semplicità non comparabile con AWL
  • AWL non è disponibile per le CPU S7-1200, chiaro segnale anche dalla stessa Siemens
  • la terza revisione dello standard IEC 61131-3 lo dichiara deprecato: una cattiva programmazione può facilmente causare loop infiniti, puntamento a zone errate di memoria, errori aritmetici, insomma se questo linguaggio può essere intuitivo per un programmatore, senza una formazione specifica è molto difficile analizzarne il codice


Figura 12 - Instruction List

Figura 12 - Instruction List


3.4 SCL (Structured Text)

Il testo strutturato è un linguaggio simile al Pascal, molto comodo per la manipolazione di dati o per svolgere algoritmi complessi, troviamo infatti i vari costrutti (IF, CASE, FOR, WHILE, ecc.) presenti nei linguaggi ad alto livello.

Con TIA Portal è divenuto uno dei linguaggi nativi e viene compilato direttamente in linguaggio macchina, mentre in passato era opzionale e veniva compilato in codice AWL poco efficiente.

Figura 13 - Structured Text

Figura 13 - Structured Text


3.5 GRAPH (Sequential Function Chart)

Il diagramma funzionale sequenziale è utilizzato per definire e strutturare l'organizzazione interna dei programmi e dei blocchi, più che un linguaggio è un mezzo grafico per partizionare il codice e visualizzare visivamente lo stato o la modalità della macchina, mettendone in evidenza il comportamento sequenziale.

Molti automatismi possono essere scomposti in una serie di fasi (o stati o passi), con GRAPH è possibile descrivere come un sistema, al verificarsi di determinati eventi, passi da una stato all'altro.
Un diagramma può essere anche molto articolato, con rami mutuamente esclusivi (divergenza e successiva convergenza) o con esecuzione simultanea (parallelismo e successiva sincronizzazione).

Figura 14 - Sequential Function Chart

Figura 14 - Sequential Function Chart


4 Esempi di utilizzo

Dopo tante chiacchiere, il miglior modo per capire qualcosa ed evidenziare alcune delle differenze tra i vari linguaggi, è vedere degli esempi di utilizzo.

4.1 Esercizio di logica combinatoria e di temporizzazione

Come esempio di questo tipo ho scelto uno schema che avevo già pronto, relativo ad un compito molto semplice, l'avviamento stella-triangolo di un motore asincrono:

Per realizzarlo tramite PLC, innanzitutto identifichiamo ed assegniamo ingressi ed uscite:

Ingressi
  • I0.0 - F2 Protezione termica, contatto NC
  • I0.1 - S1 Pulsante di arresto, contatto NC
  • I0.2 - S2 Pulsante di avvio, contatto NA
Uscite
  • Q0.0 - KM1 Teleruttore comando motore
  • Q0.1 - KM2 Teleruttore avviamento a stella
  • Q0.2 - KM3 Teleruttore connessione a triangolo

Il funzionamento prevede:

  • allo start (pressione di S1) devono attivarsi contemporaneamente KM1 e KM2, consentendo l'avvio del motore con collegamento a stella quindi a tensione ridotta \scriptstyle\frac{V_L}{\sqrt{3}}
  • dopo il tempo di accelerazione (nello schema gestito da KT1) il motore raggiunge la velocità nominale, si disattiva KM2
  • in questa breve fase il motore non risulta alimentato e gira per inerzia
  • dopo il tempo di transizione T2 (nello schema dovuto alla commutazione dei contatti) si attiva KM3 collegando il motore a triangolo e quindi alla tensione di rete (avviamento concluso)
  • in qualunque momento alla pressione del pulsante di stop S1 o con l'intervento della termica F2 il motore deve arrestarsi

Visto che non costa nulla (la logica è programmabile e non cablata) prevediamo di gestire anche il breve ritardo di transizione T2 tra la disattivazione di KM2 e l'attivazione di KM3.

Il diagramma temporale quindi sarebbe:


Proveremo ad impostare il lavoro in modo da ottenere un blocco riutilizzabile tutte le volte che avremo la necessità di usare un avviamento stella-triangolo di un motore asincrono. Io userò un FB, quindi con memoria statica, che consentirà di:

  • utilizzare i timer IEC in multi-istanza senza assegnare ogni volta dei DB di istanza specifici
  • esporre all'esterno i ritardi T1 e T2, assegnandogli dei valori predefiniti (T1 = 5 s e T2 = 50 ms), in modo che siano comunque modificabili ed adattabili ad ogni motore, ma se vanno bene i valori di default allora possiamo anche non passarli

Possiamo quindi già implementare l'interfaccia del blocco:

Figura 18 - Interfaccia del blocco per avviamento stella-triangolo

Figura 18 - Interfaccia del blocco per avviamento stella-triangolo

dove abbiamo come parametri di input al blocco i tre ingressi ed i due ritardi, in più ho previsto un segnale di abilitazione generica, da utilizzare per condizionare il funzionamento del motore ad esempio a seconda del modo operativo della macchina o con arresto di emergenza non attivo. Come segnali di output avremo le tre uscite dei teleruttori, mentre nei dati Static ho inserito le istanze dei timer IEC, un flag di comando attivo ed una variabile statica necessaria per interrogare il fronte di salita del pulsante di start (non strettamente necessario, ma già che c'eravamo).

L'interrogazione del fronte di salita o di discesa di un ingresso o di una determinata condizione, genera un segnale che rimane alto per un solo ciclo di scansione al verificarsi della commutazione dell'ingresso:

In questo caso, usando il fronte, si evita l'avvio del motore in casi anomali in quanto quando si preme il pulsante di start le abilitazioni devono esserci tutte, ad esempio se vengono premuti sia S1 che S2 simultaneamente e poi si rilascia S1, il motore non parte: è necessario rilasciare anche S2 e ripremerlo.

4.1.1 KOP

Nella logica cablata alcune scelte sono derivate dalla necessità di utilizzare il minor numero di contatti o, come nello schema funzionale di esempio, per evitare di mantenere alimentata la bobina del temporizzatore durante il normale funzionamento del motore.
Nell'implementazione su PLC tutte queste problematiche non ci sono, ogni bobina non ha limite sul numero di contatti, come non c'è nessun problema ad utilizzare delle memorie intermedie, per cui non è necessario seguire "alla lettera" lo schema di partenza.
Il compito lo ho svolto così:

Figura 20 - Avviamento stella-triangolo in KOP

Figura 20 - Avviamento stella-triangolo in KOP


il simbolo P è usato per interrogare il fronte positivo del segnale di #Start, inoltre ho preferito utilizzare l'istruzione flip-flop SR per attivare il comando (R1-reset ha priorità rispetto a S-set), ma sarebbe equivalente ad impostare una bobina con auto-ritenuta:

Figura 21 - Avviamento stella-triangolo con auto-ritenuta in KOP

Figura 21 - Avviamento stella-triangolo con auto-ritenuta in KOP


Ho poi simulato il funzionamento con PLCSIM, nel collegamento online la grafica è molto utile:

Figura 22 - Collegamento online avviamento stella-triangolo in KOP

Figura 22 - Collegamento online avviamento stella-triangolo in KOP


Riporto per completezza il trace rilevato, sempre in simulazione:

Figura 23 - Trace avviamento stella-triangolo

Figura 23 - Trace avviamento stella-triangolo


Il richiamo del blocco funzionale, in questo caso da OB1 è visualizzato così:

Figura 24 - Richiamo del blocco in KOP

Figura 24 - Richiamo del blocco in KOP

dove notiamo l'assegnazione degli ingressi (a sinistra) e delle uscite (a destra), mente i ritardi sono stati lasciati ai valori di default.

4.1.2 FUP

L'implementazione è analoga a quanto visto in KOP, la rappresentazione è la seguente:

Figura 25 - Avviamento stella-triangolo in FUP

Figura 25 - Avviamento stella-triangolo in FUP

notate che gli operandi negati sono indicato con il "pallino", i box con il simbolo "&" rappresentano l'operazione AND, quelli con simbolo ">=1" l'operazione OR.

Anche qui la grafica viene in aiuto nell'analisi con collegamento online:

Figura 26 - Collegamento online avviamento stella-triangolo in FUP

Figura 26 - Collegamento online avviamento stella-triangolo in FUP


E qui vediamo il richiamo in OB1 con le stesse modalità del KOP:

Figura 27 - Richiamo del blocco in FUP

Figura 27 - Richiamo del blocco in FUP


4.1.3 AWL

Ecco l'esercizio svolto in AWL, l'editor dà la possibilità di inserire commenti ogni riga:

Figura 28 - Avviamento stella-triangolo in AWL

Figura 28 - Avviamento stella-triangolo in AWL

al contrario di altri PLC, in AWL per iniziare un ramo non c'è l'istruzione LD (Load), ma in genere si parte direttamente con un A (And), ho usato lo mnemonico internazionale, nelle impostazioni è possibile settare in alternativa quello tedesco (che era predefinito nel vecchio Simatic Manager).
L'istruzione FP serve per interrogare il fronte positivo, AN e ON sono le operazioni AND ed OR con operando negato.

Ecco come si presenta il collegamento online, è possibile visualizzare sia il risultato logico di ogni sequenza che lo stato dei vari operandi:

Figura 29 - Collegamento online avviamento stella-triangolo in AWL

Figura 29 - Collegamento online avviamento stella-triangolo in AWL


Così compare il richiamo del blocco da OB1:

Figura 30 - Richiamo del blocco con AWL

Figura 30 - Richiamo del blocco con AWL


4.1.4 SCL

Nel caso del SCL, l'interfaccia è stata leggermente modificata per utilizzare il blocco funzionale di sistema R_TRIG, per interrogare il fronte di salita del pulsante start, quindi la memoria BOOL di appoggio Static, diventa l'istanza appunto di R_TRIG ed inoltre è stata aggiunta una variabile intermedia temporanea per l'utilizzo del fronte:

Figura 31 - Modifica interfaccia blocco avviamento stella-triangolo con SCL

Figura 31 - Modifica interfaccia blocco avviamento stella-triangolo con SCL

in alternativa avremmo potuto interrogare in autonomia il fronte memorizzando lo stato precedente dell'ingresso su una variabile BOOL e verificando l'evento di commutazione.

Ecco il compito svolto in SCL, anche qui è possibile commentare ogni riga, il tutto diventa molto compatto:

Figura 32 - Avviamento stella-triangolo con SCL

Figura 32 - Avviamento stella-triangolo con SCL


Così compare nel collegamento online:

Figura 33 - Collegamento online avviamento stella-triangolo con SCL

Figura 33 - Collegamento online avviamento stella-triangolo con SCL

in caso di espressioni la colonna di destra mostra il risultato dell'elaborazione, ma è possibile con la freccetta espandere la visualizzazione per avere lo stato dei vari operandi.

Il richiamo del blocco da OB1 si presenta così:

Figura 34 - Richiamo del blocco con SCL

Figura 34 - Richiamo del blocco con SCL

i parametri di ingresso e transito sono assegnati con ":=", quelli di uscita con "=>".

4.2 Esercizio di calcolo

Un esempio di calcolo potrebbe essere la conversione di un segnale analogico 4-20mA proveniente da un trasduttore lineare di posizione.
Va sempre verificato sul datasheet del modulo utilizzato, ma in genere la rappresentazione di un valore analogico è di questo tipo:

Figura 35 - Rappresentazione valore analogico 4-20mA per ET200SP

Figura 35 - Rappresentazione valore analogico 4-20mA per ET200SP


Immaginiamo che la posizione del dispositivo assuma i valori -500 e 500 rispettivamente agli estremi del range nominale del trasduttore.
In questo caso utilizziamo un FC, non ci serve memoria statica, in Input prevediamo di passare il valore analogico di ingresso, assieme alle posizioni minima/massima corrispondenti ai valori nominali, mentre come ritorno della funzione il valore di posizione calcolato.

La diagnostica di overflow/underflow/rottura conduttore è impostabile anche nella configurazione dell'hardware, ma in questo caso, a scopo didattico, prevediamo di segnalare la condizione di rottura conduttore come parametro di uscita del blocco, valutando un valore analogico inferiore al limite under-range (1.185 mA). L'interfaccia del blocco diventa:

Figura 36 - Interfaccia del blocco per conversione valore analogico

Figura 36 - Interfaccia del blocco per conversione valore analogico


4.2.1 KOP

In questo esercizio ho utilizzato le istruzioni NORM_X e SCALE_X concatenate, la prima restituisce in output un valore Real compreso tra 0 e 1, corrispondente al valore in ingresso rispetto al range nominale, la seconda riporta in scala il valore rispetto alle posizioni limite, se il valore analogico è inferiore al limite under-range, la posizione non viene calcolata e si attiva il segnale #CableCut:

Figura 37 - Conversione valore analogico in KOP

Figura 37 - Conversione valore analogico in KOP


in alternativa è possibile convertire i valori Int in Real ed usare l'operazione CALCULATE in un unico passo:

Figura 38 - Conversione valore analogico in KOP con CALCULATE

Figura 38 - Conversione valore analogico in KOP con CALCULATE


I connettori EN/ENO, che compaiono anche in FUP, rappresentano rispettivamente l'abilitazione in ingresso ed in uscita: le istruzioni con questo meccanismo vengono eseguite se l'ingresso di abilitazione EN è TRUE, se l'elaborazione del box è regolare allora l'uscita ENO sarà anch'essa a TRUE, se si verifica un errore nel corso dell'elaborazione, ENO viene resettata. Se EN non è interconnessa, l'istruzione viene sempre eseguita.

4.2.2 FUP

La rappresentazione nel diagramma a blocchi funzione anche in questo caso è molto simile al KOP:

Figura 39 - Conversione valore analogico in FUP

Figura 39 - Conversione valore analogico in FUP


4.2.3 AWL

In AWL l'esercizio di calcolo può sembrare un po' complesso.
Per condizionare operazioni in AWL normalmente si usano i salti anche se poco eleganti (in questo caso il salto condizionato JC), mentre per i calcoli bisogna porre attenzione al tipo di dati dei vari operandi, l'istruzione L x sposta il contenuto dell'accumulatore 1 all'accumulatore 2 e carica il valore x nell'accumulatore 1, mentre -R,+R,*R,/R eseguono le operazioni elementari tra accumulatori con dati di tipo Real :

Figura 40 - Conversione valore analogico in AWL

Figura 40 - Conversione valore analogico in AWL


4.2.4 SCL

Con SCL l'esercizio di calcolo diventa quasi banale, in poche righe è tutto implementato (sono andato a capo nell'ultima operazione solo per rendere più leggibile):

Figura 41 - Conversione valore analogico in SCL

Figura 41 - Conversione valore analogico in SCL


4.3 Esempio di selezione di un valore

Per questo compito immaginiamo di dover selezionare da un array di valori di tipo INT, quello corrispondente ad un indice che viene passato come parametro di ingresso, anche in questo caso useremo un FC in quanto non serve memoria statica.

Se l'indice non è compreso nell'intervallo prevediamo di restituire -999.
Come interfaccia del blocco, passiamo in ingresso l'array indefinito (che verrà passato per riferimento) e l'indice per la selezione del valore. La funzione ritornerà il valore selezionato:

Figura 42 - Interfaccia del blocco per selezione valore

Figura 42 - Interfaccia del blocco per selezione valore

se si trattasse di un FB, converrebbe mettere l'array su un parametro di transito InOut, in modo che venga passato tramite puntatore per riferimento (si evita una inutile copia dei dati).

Questo esercizio sembrerebbe banale per chi è abituato con linguaggi ad alto livello, ma sul PLC è stato reso semplice con l'accesso simbolico agli elementi dell'array, in precedenza era possibile con AWL e memorizzazione assoluta, puntando all'indirizzo in memoria dell'elemento.

4.3.1 KOP

L'esercizio è stato svolto usando le istruzioni LOWER/UPPER_BOUND per determinare i limiti dell'array (con DIM si specifica il numero di dimensioni), mentre con IN_RANGE si verifica la correttezza dell'indice passato:

Figura 43 - Selezione di un valore in KOP

Figura 43 - Selezione di un valore in KOP



4.3.2 FUP

Anche in questo caso cambia la rappresentazione grafica, ma non il senso rispetto a quanto visto in KOP:

Figura 44 - Selezione di un valore in FUP

Figura 44 - Selezione di un valore in FUP


4.3.3 AWL

Ecco l'esercizio svolto in AWL, anche qui abbiamo innanzitutto determinato i limiti inferiore e superiore dell'array ed abbiamo dovuto usare i salti (condizionati JC ed incondizionati JU):

Figura 45 - Selezione di un valore con AWL

Figura 45 - Selezione di un valore con AWL

l'istruzione POP ripristina #Index (in DInt) nell'accumulatore 1.

4.3.4 SCL

Anche in questo caso, come nell'esercizio precedente, in questo tipo di operazioni SCL dimostra l'immediatezza e la semplicità di un linguaggio ad alto livello:

Figura 46 - Selezione di un valore in SCL

Figura 46 - Selezione di un valore in SCL


4.4 Esercizio di iterazione

Come esempio di iterazione, prevediamo di ritornare l'indice del primo valore di un array di interi, che supera una determinata soglia. Anche in questo caso useremo un FC.
Se nessun valore soddisfa questa condizione, ritorniamo -1.

Impostiamo ora l'interfaccia del blocco, come nel caso precedente passiamo in ingresso l'array indefinito, con anche la soglia per individuare l'indice. La funzione ritornerà l'indice che soddisfa la condizione impostata:

Figura 47 - Interfaccia del blocco per ricerca elemento

Figura 47 - Interfaccia del blocco per ricerca elemento


4.4.1 KOP

Con il diagramma a contatti questo tipo di esercizio diventa macchinoso, si devono utilizzare i salti, in ogni segmento può esservi una sola istruzione di salto, e cosi via, io l'ho implementato così:

Figura 48 - Ricerca elemento in KOP

Figura 48 - Ricerca elemento in KOP

la prima operazione è quella di individuare i limiti dell'array ed inizializzare l'indice di appoggio, di seguito si effettua la verifica del superamento della soglia per ogni elemento fino al primo che soddisfa la condizione, uscendo dal blocco con ENO=1.

4.4.2 FUP

Vale lo stesso discorso fatto per l'esercizio in KOP:

Figura 49 - Ricerca elemento in FUP

Figura 49 - Ricerca elemento in FUP


4.4.3 AWL

Con AWL per eseguire le iterazioni abbiamo l'istruzione specifica LOOP, che però è alquanto macchinosa, decrementa il contenuto dell'accumulatore e salta all'etichetta se il valore è diverso da zero, altrimenti elabora l'istruzione successiva, quindi si deve gestire il contatore di iterazione e l'indice corrispondente:

Figura 50 - Ricerca elemento in AWL

Figura 50 - Ricerca elemento in AWL


4.4.4 SCL

Nell'esercizio di ricerca di un elemento, la superiorità del testo strutturato rispetto agli altri linguaggi emerge ancora più che nei due esempi precedenti:

Figura 51 - Ricerca elemento in SCL

Figura 51 - Ricerca elemento in SCL

l'istruzione RETURN esce dal blocco.


4.5 Esercizio di organizzazione di una sequenza con GRAPH

Per un'introduzione o un esempio concreto sul diagramma funzionale sequenziale servirebbero uno o più articoli dedicati ed è una materia in cui non sono esperto, provo a riportare un esempio ridotto e volutamente semplicistico (tralasciando modi operativi, arresto di emergenza, protezioni, timeout dei comandi, verifica coerenza segnali):
immaginiamo un portone basculante, mosso da un motore nelle due direzioni di apertura e chiusura, con corrispondenti finecorsa di raggiungimento della posizione; l'apertura viene comandata da un pulsante mentre la chiusura avviene automaticamente dopo un minuto. Una fotocellula, se rileva ostacoli durante la fase di chiusura, interrompe il comando riaprendo automaticamente il portone.

Come al solito mettiamo giù l'elenco degli ingressi e delle uscite:

Ingressi
  • I0.0 - S1 Pulsante di apertura, contatto NA
  • I0.1 - S2 Fotocellula OK, contatto NA (non oscurata = 1)
  • I0.4 - SQ1 Portone aperto, contatto NA
  • I0.5 - SQ2 Portone chiuso, contatto NA
Uscite
  • Q0.0 - KM1 Teleruttore comando apertura portone
  • Q0.1 - KM2 Teleruttore comando chiusura portone

Studiamo ora i possibili stati che può assumere il sistema e gli eventi che determinano un cambio di stato:


Ecco il diagramma che ho ottenuto in GRAPH, dove si notano chiaramente gli stati o passi (Sx) e le transizioni (Tx), Siemens la chiama "vista della catena":

Figura 53 - Vista della catena con GRAPH

Figura 53 - Vista della catena con GRAPH


se osserviamo la transizione T3, viene verificata la variabile <nome-stato>.T, ovvero il tempo di attivazione dello stato S3 (aperto) per eseguire l'attesa prima della chiusura automatica, mentre le azioni che ho usato sono di tipo "N" (normal not stored), ovvero eseguite continuamente finché lo stato è attivo, quindi non serve verificare il raggiungimento della posizione: quando cambia lo stato le azioni di comando del motore si resettano.
Vi sono vari tipi di azioni, legate anche a possibili eventi come l'attivazione o la disattivazione del passo, quelle di tipo "N" permettono anche il richiamo diretto di blocchi con relativi parametri, ma bisogna porre attenzione: il blocco verrà richiamato solo finché il relativo stato o passo rimane attivo.
In questo caso semplice le azioni sono gestite interamente nel blocco, ma nella pratica vengono gestite con la necessaria flessibilità in FC e FB esterni: le azioni del diagramma si occupano di pubblicare su delle variabili booleane globali qual è lo stato attivo <nome-stato>.X.

Questo è quello che si vede nel collegamento online, lo stato attivo viene evidenziato in verde:

Figura 54 - Collegamento online con GRAPH

Figura 54 - Collegamento online con GRAPH


Ho voluto interbloccare i due teleruttori del motore, in modo da evitare in particolare l'inversione di direzione immediata nel caso di oscuramento della fotocellula della transizione T5, per fare questo ho aggiunto due timer alla disinserzione nella sezione "istruzioni permanenti precedenti", ovvero che vengono eseguite continuamente prima della catena:

Figura 55 - Istruzioni permanenti precedenti con GRAPH

Figura 55 - Istruzioni permanenti precedenti con GRAPH


per poi usare l'interblocco "C" nelle rispettive azioni, che si può modificare nella "vista passo singolo".

In alternativa, per interbloccare l'apertura automatica con oscuramento fotocellula, si potrebbe usare l'azione "TF", che genera un ritardo alla disinserzione legato allo stato attivo:

Figura 56 - Vista passo singolo con GRAPH

Figura 56 - Vista passo singolo con GRAPH


ed usare questo timer per interbloccare il comando di apertura:

Figura 57 - Modifica interblocco con GRAPH

Figura 57 - Modifica interblocco con GRAPH


5. Conclusione

Gli esempi che abbiamo visto, anche se molto semplici, mostrano le peculiarità dei vari linguaggi, poi ognuno può avere preferenze personali:

  • KOP e FUP sono piuttosto equivalenti, il loro punto di forza è la grafica, che rende semplice la comprensione e diagnosi di espressioni logiche anche a personale non formato, per contro diventano macchinosi nell'implementazione di algoritmi neanche troppo complessi, con il vecchio Simatic Manager molte cose non erano realizzabili con questi linguaggi
  • AWL è il linguaggio storico di Siemens, di basso livello, flessibile, efficiente (se scritto bene), ma difficile da interpretare senza adeguata formazione, si possono commettere errori gravi senza il minimo avviso, il debug può portar via molto tempo anche a personale con esperienza, ne viene sconsigliato l'uso e attualmente non è più necessario: si può far tutto con gli altri linguaggi - non è disponibile su S7-1200
  • SCL è il linguaggio di alto livello, viene in soccorso dove KOP e FUP sono più carenti, consentendo, unitamente alla notazione simbolica, l'implementazione in maniera confortevole di algoritmi ed operazioni di manipolazione dati sempre più richieste dall'Industry 4.0, risulta inoltre di facile comprensione a qualunque programmatore e probabilmente è quello il cui codice è più facilmente migrabile su altri PLC o piattaforme, per contro può risultare scomodo nell'analizzare espressioni logiche lunghe ed articolate, ma è possibile scriverle su più righe
  • GRAPH può aiutare ad organizzare in maniera ordinata sequenze di automazione, grazie alla grafica sono immediatamente chiari stati e transizioni, l'implementazione delle azioni meglio gestirla in blocchi esterni con gli altri linguaggi - non è disponibile su S7-1200


Il documento si un po' allungato (anche se contiene molte immagini): spero di non avervi annoiato.

6. Riferimenti

PLCopen - Introduzione a IEC 61131-3
PLCopen - Status IEC 61131-3 standard
MotionControlTips - Why is IL language for PLCs falling out of favor
Siemens Forum - TIA Portal vs Step7 SCL compiler
Siemens Forum - Should STL (AWL) be retired?

9

Commenti e note

Inserisci un commento

di ,

Da ragazzini a scuola chi è che non ha mai usato i famosi "Bignami"?? Questo articolo andrebbe di sicuro annoverato nella preziosissima raccolta!!!! :-))

Rispondi

di ,

Grazie mille dimaios, speravo davvero in un tuo intervento: il giudizio di un esperto come te è sempre molto apprezzato.

Rispondi

di ,

Bravo. Bell'articolo. L'AWL ormai è ormai in disuso per ovvi motivi, è veramente raro il caso in cui sia assolutamente indispensabile. "Come esempio di questo tipo ho scelto uno schema che avevo già pronto, relativo ad un compito molto semplice, l'avviamento stella-triangolo di un motore asincrono" 10 e lode per aver scelto questo esempio. Sarà banale per un esperto di automazione ma deve essere assolutamente spiegato ad un neofita. Peccato aver solo un voto a disposizione. Meritatissimo.

Rispondi

di ,

Grazie Marco per il riscontro. Io purtroppo non ho avuto esperienze importanti con PLC diversi da Siemens. A scuola usavamo gli Omron (alle professionali ci davano di volta in volta compiti semplici di automazione, di cui dovevamo realizzare lo schema elettromeccanico in logica cablata, poi realizzare materialmente il quadretto, testare il tutto ed infine procedere con l'alternativa PLC), mentre sul lavoro, a parte una breve esperienza con un piccolo PLC Klockner Moeller, è stato tutto su Siemens, che in Europa è molto diffusa tanto che i partner con cui collaboriamo per le integrazioni di solito propongono per la loro parte preferenzialmente Siemens. In più siamo un po' legati ad una lunga esperienza con il loro controllo numerico, di cui abbiamo acquisito una conoscenza piuttosto verticale.

Rispondi

di ,

Bravo Sergio per l'articolo. Complimenti per tutto il lavoro di preparazione dei programmi e degli screenshot (che ti deve aver portato via parecchie giorni). Comunque resto un fan di Allen-Bradley (oggi Rockwell). L'informatica, l'elettronica digitale e la programmazione l'hanno inventata negli Stati Uniti e per gli altri è sempre una corsa per starci dietro.

Rispondi

di ,

Bene, l'articolo aveva proprio un intento didattico ☺

Rispondi

di ,

Temo che utilizzerò qualcosa (tutto?) di questo articolo quando dovrò fare lezioni sui PLC...

Rispondi

di ,

Grazie Goofy, sono felice che tu abbia apprezzato.

Rispondi

di ,

Ottimo!

Rispondi

Inserisci un commento

Per inserire commenti è necessario iscriversi ad ElectroYou. Se sei già iscritto, effettua il login.