TIA PORTAL Configurazione dinamica
- Dettagli
- Categoria: Software
- Pubblicato Giovedì, 16 Aprile 2026 04:03
- Scritto da Baraldi ing. Enrico
- Visite: 188
Configurazione dinamica: capacità del software di adeguarsi a svariate configurazioni hardware. Sfruttando le librerie LCC (Library for Conficuration Control) del TIA Portal (link) abbiamo la possibilità di creare un software che può gestire diversi impianti e/o diverse macchine. Un software unico per diverse configurazioni di impianto o macchina. Siamo quindi nell'ambito della realizzazione di software modulare e configurabile a runtime, ovvero quando il software "gira" su un PLC. Il principale vantaggio è quello di avere un software che possiamo riutilizzare su altri impianti o macchine e soprattutto la nostra presenza per la messa in servizio non necessaria. In produzione, passando attraverso un'HMI od un file .csv i parametri di configurazione, in autonomia possono avviare le attività di test e collaudo dell'impianto o macchina.
Andiamo a vedere quali sono i possibili scenari che ci troviamo ad affrontare:
A - scenario a livello di PLC

la configurazione hardware del PLC presenta moduli diversi in funzione dell'opzione 1 o dell'opzione 2.
B - scenario a livello di moduli nell'IO (ProfiBus, Profinet)

i dispositivi sull'IO (ProfiBus, Profinet) variano in funzione dell'impianto o macchina.
C - scenario a livello di PLC e moduli IO

quest'ultimo scenario coincide con la realizzazione della nostra architettura di progetto. La definizione dell'hardware per assolvere al compito di automazione affidatoci.
Fatta questa breve introduzione entriamo nel dettaglio dello scenario A.
Di seguito presento due configurazioni hardware come esempi di utilizzo dato che il software è stato testato con entrambe le configurazioni.
Scenario A1
|
|
Configurazione hardware: slot dispositivo 1 - CPU 1512SP F-1-PN; 2 - F-DI 8x24VDC HF; 3 - F-DQ 4x24VDC/2A PM HF; 4 - DI 16x24VDC ST; 5 - DQ 16x24VDC/0.5A ST; 6 - modulo server. |
Scenario A2
|
|
Configurazione hardware: slot dispositivo 1 - CPU 1512SP F-1-PN; 2 - DI 16x24VDC ST; 3 - DI 16x24VDC ST; 4 - DI 16x24VDC ST; 5 - DQ 16x24VDC/0.5A ST; 6 - DQ 16x24VDC/0.5A ST; 7 - DQ 16x24VDC/0.5A ST; 8 - modulo server. |
Di seguito faremo riferimento allo scenario A2 dato che è la configurazione di una CPU che attualmente controlla un impianto reale e produttivo.
Prima di proseguire introduciamo il principio di base: la configurazione hardware del sistema di controllo deve contenere tutti i moduli e dispositivi possibili che le varie configurazioni di macchina od impianto richiedono. In figura la configurazione hardware, nella vista di rete, di tutto il progetto MASTER (sarà ampliato dopo i primi test viste le potenzialità). Comprende inverter G120 e G120C, encoders, hub IOLink e dispositivi safety.

fig. "Configurazione Hw PLC"
Prima di addentrarci nei dettagli per realizzare la nostra funzionalità evidenzio una proprietà della CPU che ci potrebbe tornare utile per arricchire le potenzialità del nostro software.

attiviamo nella CPU la funzionalità Web Server. Sarà utile per caricare il file csv di configurazione nella MMC della CPU alla prima messa servizio. Infatti, dopo aver scaricato la configurazione hardware ed il software nella CPU, transizione della CPU da STOP a RUN e la nostra macchina/impianto è pronta per la messa in servizio. Quest'ultima potrà essere eseguita dal personale in officina senza la nostra presenza. Niente male .....
Il mio progetto è stato sviluppato appoggiando i parametri di configurazione su una DB. La gestione del file .csv sarà lo spunto per un altro articolo.
Nella prossima pagina andiamo nel dettaglio dello scenario A2. Saranno illustrati i passi da eseguire affinchè la configurazione dinamica sia eseguita con successo.
PASSO 0
La CPU deve conoscere che la configurazione dei dispositivi collegati sarà gestita dal programma utente. Quindi l'opzione "abilita configurazione del dispositivo da programma utente" deve essere attiva. Nelle proprietà della CPU, l'opzione:

deve essere attivata. Passiamo ora al passo successivo dove andiamo a presentare le funzioni della libreria LCC.
PASSO 1
Useremo due funzioni della libreria:
a - LCC_ConfigDevice (FB);
b - LCC_ReconfigSys (FB).
- a -
La FB LCC_ConfigDevice richiama al suo interno la funzione di sistema "WRREC". Quest'ultima è di tipo asincrona. Richiederà più cicli per essere elaborata. La funzione "WRREC" è utilizzata per scrivere il DataSet della CPU. Vediamo ora la FB LCC_ConfigDevice.
in cui i tipi di dato delle interfacce sono:

Particolare attenzione dovrà essere dedicata alla costruzione dell'elemento dataRec .Le informazioni di configurazione risiedono proprio in quella struttura dati. Vediamo quindi come ho gestito la configurazione della mia CPU 1512SP-F-1PN.
NOTA: la CPU alla partenza comunque necessita di una configurazione base, altrimenti se il data set non è corretto passa dallo stato di avvio a quello di stop senza attivare alcuna procedura di lettura degli IO.
Utilizzo la FB LCC_ConfigDevice per configurare il rack del PLC. Nel caso della mia CPU il numero di moduli che posso andare a gestire sono 66:

come si può notare nella pagina di configurazione dell'hardware per la CPU. Di conseguenza ho creato nel PLC una struttura dati per indicare la presenza o meno di un modulo e la sua posizione nel rack. Prima di vedere la struttura dati presento il codice che ho inserito in OB100 per far si che la CPU si avvii con un data set corretto:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
"Tag_18" := FALSE; spia per verifica codice eseguito
"System".Sts.ConfigDone := "System".Sts.LccConfigOk := "System".Sts.IOconfigOk := FALSE;
FOR #index := 1 TO 66 DO
// check how many module configured
IF "Configurator".Config.PLC_IO_Configuration.RackPlc[#index].Name <> '' THEN
#Cnt := #Cnt + 1;
END_IF;
//reset all values "ohDataset".ohS71500.slots structure data
"ohDataset".ohS71500.slots[#index].NumSlot := 0;
"ohDataset".ohS71500.slots[#index].BaseTypeSlot := 0;
END_FOR;
//set the header's value
"ohDataset".ohS71500.header.blockLength := 4 + INT_TO_USINT(#Cnt) * 2;
"ohDataset".ohS71500.header.blockID := 196;
"ohDataset".ohS71500.header.type := 2; //1500SP CPU
"ohDataset".ohS71500.header.typeSub := 0;
//set the plc rack configuration accordingly to the DB
//fill the structure data with real module installed
FOR #index := 1 TO 66 DO
"ohDataset".ohS71500.slots[#index].NumSlot := "Configurator".Config.PLC_IO_Configuration.RackPlc[#index].NumMod;
"ohDataset".ohS71500.slots[#index].BaseTypeSlot := "Configurator".Config.PLC_IO_Configuration.RackPlc[#index].BaseUnitType;
END_FOR;
//reset var status
"ohDataset".ohS71500StatusID := 0;
"ohDataset".ohS71500Status := 0;
//call block library for set up the configuration
"LCC_ConfigDevice_DB"(hwID := 33,
statusID => "ohDataset".ohS71500StatusID,
status => "ohDataset".ohS71500Status,
dataRec := "ohDataset".ohS71500);
IF ("ohDataset".ohS71500Status = 0) THEN
"System".Sts.LccConfigOk := TRUE;
END_IF;
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Le DB utilizzate sono "ohDataSet", "Configurator" e "System". Già dai nomi possiamo capire lo scopo delle DB. ohDataSet è quella per la funzione LCC_ConfigDevice mentre Configurator sarà la DB utilizzata per definire le varie configurazioni delle nostre CPU, System per appoggiare gli stati della procedura. Descriviamo le strutture dati utilizzate affinchè il codice risulti più chiaro.
La DB "Configurator":
contiene la struttura dati UDT_SystemCfg che è composta di tre array di strutture dati.

vediamo ora nel dettaglio le strutture dati interne.
UDT_SlotPlc
|
|
In cui a parte l'elemento Name di tipo String(8) che ho aggiunto, ne vedremo l'utilizzo più avanti, gli elementi NumMod e BaseUnitType sono elementi necessari per il corretto funzionamento della FB LCC_ConfigDevice. Infatti sono gli stessi elementi del tipo di dato "LCC_typeSlotET200SP" della libreria LCC. NumMod : indica in quale posizione del rack della CPU si trova il modulo; BaseUnitType : consente di definire se la base è di tipo a separazione di potenziale o meno. Se valore 0 allora sarà considerato il tipo di base configurato, se valore 1 ci sarà una base che apre un nuovo potenziale. |
UDT_Device
|
|
Questa struttura dati contiene gli elementi necessari per la configurazione dei dispositivi di IO, cioè quei dispositivi che sono connessi al sistema via Profinet od altro bus di campo. Nel mio caso il valore iniziale "TASWASLU" è una stringa per identificare se esiste il dispositivo. Vero che possiamo inserire fino a 512 dispositivi di IO ma sicuramente, come è nel mio caso, saranno configurati in un numero inferiore. L'elemento più importante è "ValHwDevice" perchè è il numero che TIA portal ha assegnato al dispositivo quando lo abbiamo inserito nella configurazione hardware. |
UDT_ET200S
|
|
Questa struttura dati è inserita in vista della configurazione dei nodi di periferia ET200SP. E' da notare che questa struttura dati contiene i tipi di dati della libreria LCC, ovvero i tipi dati: - "LCC_typeHeader" - "LCC_SlotET200SP" |
Le strutture presentate sono quelle utilizzate per configurare il sistema, quelle che saranno modificate in fase di configurazione del PLC. La FB LCC_ConfigDevice però richiede un'altro tipo di dataset per il suo corretto funzionamento. E' il tipo di dato che troviamo nella Db "ohDataSet".

sarà questa struttura dati che passata alla FB LCC_ConfigDevice ci permetterà di configurare la nostra CPU. Infatti il richiamo della FB è:
"LCC_ConfigDevice_DB"(hwID := 33,
statusID => "ohDataset".ohS71500StatusID,
status => "ohDataset".ohS71500Status,
dataRec := "ohDataset".ohS71500);
dove la struttura dati "ohS71500" è stata popolata nelle righe precedenti andando a scorrere la DB "Configurator". Come è valorizzata la struttura dati della DB "Configurator":
![]() |
|
in cui i moduli dalla posizione 9 fino alla 66 saranno tutti non definiti, come è d'altronde nella configurazione hardware della CPU. Quindi se torniamo all'analisi del codice il primo ciclo FOR:
FOR #index := 1 TO 66 DO
// check how many module configured
IF "Configurator".Config.PLC_IO_Configuration.RackPlc[#index].Name <> '' THEN
#Cnt := #Cnt + 1;
END_IF;
//reset all values "ohDataset".ohS71500.slots structure data
"ohDataset".ohS71500.slots[#index].NumSlot := 0;
"ohDataset".ohS71500.slots[#index].BaseTypeSlot := 0;
END_FOR;
conta il numero di moduli che dovranno essere definiti. Il numero dei moduli ci tornerà utile per determinare la lunghezza dei blocco dati che la funzione "LCC_ConfigDevice" elaborerà. L'azzeramento della struttura dati "ohS71500" è per avere l'area pulita.
Il codice:
//set the header's value
l'header ha una lunghezza di 4 byte, i moduli occupano 2 byte ciascuno
"ohDataset".ohS71500.header.blockLength := 4 + INT_TO_USINT(#Cnt) * 2;
numero del data set, deve essere 196 "ohDataset".ohS71500.header.blockID := 196;
2 perchè è una CPU 1500SP, se fosse una CPU1500 andrà impostato a 4 "ohDataset".ohS71500.header.type := 2; //1500SP CPU
deve essere 0 "ohDataset".ohS71500.header.typeSub := 0;
prima della chiamata della funzione andiamo ad impostare la parte di configurazione dei moduli, con il secondo ciclo FOR:
//set the plc rack configuration accordingly to the DB
//fill the structure data with real module installed
FOR #index := 1 TO 66 DO
"ohDataset".ohS71500.slots[#index].NumSlot := "Configurator".Config.PLC_IO_Configuration.RackPlc[#index].NumMod;
"ohDataset".ohS71500.slots[#index].BaseTypeSlot := "Configurator".Config.PLC_IO_Configuration.RackPlc[#index].BaseUnitType;
END_FOR;
Il 66 potrebbe essere sostituito con la variabile #Cnt, funziona ugualmente ma dato che l'area è stata pulita in precedenza lo copio tutto. Quindi la chiamata della funzione LCC con il data set 196 informa la CPU della posizione dei moduli configurati in configurazione hardware.
//reset var status
"ohDataset".ohS71500StatusID := 0;
"ohDataset".ohS71500Status := 0;
//call block library for set up the configuration
"LCC_ConfigDevice_DB"(hwID := 33,
statusID => "ohDataset".ohS71500StatusID,
status => "ohDataset".ohS71500Status,
dataRec := "ohDataset".ohS71500);
IF ("ohDataset".ohS71500Status = 0) THEN
"System".Sts.LccConfigOk := TRUE;
END_IF;
Abbiamo quindi passato alla CPU come è configurata. La figura che segue sarà esplicativa.

Il modulo che in configurazione hardware avevamo messo in posizione 5 nella CPU reale si trova invece in posizione 4. Il modulo che è in posizione 4 nella configurazione hardware nella CPU reale non c'è. Se abbiamo fatto tutte le cose corrette il risultato è la CPU in RUN e senza errori hardware.
PASSO 2
Vista la parte di configurazione del rack della CPU ora rimane da esplorare la parte di configurazione della perifieria. Come abbiamo detto in precedenza per configurare la periferia basata sui moduli della famiglia "ET200SP" dobbiamo utilizzare delle strutture dati differenti. Focalizziamoci ora sulla configurazione di dispositivi di IO, vedi figura "Configurazione Hw PLC". I dispositivi di IO nel mio caso sono gli inverter G120C, G120, master IOLink ed encoder. In questo caso la libreria che andremo ad utilizzare è la "LCC_ReconfigSys".
- b -
Presentiamo la FB con le sue interfacce ed i suoi tipi di dati
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//search how many devices there are on the real configuration
#Cnt := 0;
#indexcfg := 0;
FOR #index := 0 TO 66 DO
"ohDataset".ctrlRec.OptDevices[#index] := 0;
IF "Configurator".Config.PLC_IO_Configuration.IOConfig[#index].Name <> "DEVICE_NOT_DEFINED" THEN
IF "Configurator".Config.PLC_IO_Configuration.IOConfig[#index].Presence THEN
#Cnt := #Cnt + 1;
"ohDataset".ctrlRec.OptDevices[#indexcfg] := "Configurator".Config.PLC_IO_Configuration.IOConfig[#index].ValHwDevice;
#indexcfg := #indexcfg + 1;
IF #indexcfg >= 33 THEN
EXIT;
END_IF;
END_IF;
END_IF;
END_FOR;
"NumIoDevice" := #Cnt;
//adjust data structure value according the configuration
"ohDataset".ctrlRec.numOptDevices := INT_TO_UINT(#Cnt);
"ohDataset".ctrlRec.version := 16#0100;
//reconfig the IO
//reset the variables
"LccReconfigErrInfo" := 0;
"LccReconfigStatus" := 0;
REPEAT
"LCC_ReconfigSys_DB"(execute := TRUE,
hwID := 64,
ctrlRec := "ohDataset".ctrlRec,
done => "LccReconfigDone",
busy => "LccReconfigBusy",
error => "LccReconfigError",
status => "LccReconfigStatus",
errorInfo => "LccReconfigErrInfo");
UNTIL "LccReconfigDone" OR "LccReconfigError"
END_REPEAT;
"System".Sts.IOconfigOk := "LccReconfigDone" AND NOT "LccReconfigError";
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



