Vai al contenuto
PLC Forum


Curiosità: chi fa largo uso di ST ?


step-80

Messaggi consigliati

Buongiorno a tutti

 

come da titolo, volevo sapere se qualcuno di voi ha eletto ST come linguaggio universale, usandolo anche con pura logica Booleana per esempio.

Credo che ognuno di noi abbia il suo linguaggio preferito, al di là di quanto è effettivamente 'efficace' per fare ciò che ci siamo prefissati.

 

Anzi, credo che ognuno di noi sia mentalmente 'predisposto' ad usare un linguaggio piuttosto che l'altro, il motivo non lo so spiegare.

 

Io per esempio per quanto mi sforzi ad usare il Ladder, non riesco ad avere l'immediata idea di come si svolga il flusso. Non so se questo dipenda dal fatto che visivamente una operazione in ladder occupi più spazio dell'equivalente in ST ,ma comunque sia questo non mi aiuta. 

Detto questo, tempo fa consultando un manuale di ST del plc che stavo usando, sono incappato in questo:

Mits5.thumb.png.3be058529c1f6f8a55f330df8ff18c58.png

 

e cioè il tempo impiegato dalla cpu per eseguire la STESSA operazione in 2 linguaggi: IL(lista istruzioni) ed-appunto-ST. 

La differenza mi ha lasciato sconcertato: immaginavo una differenza sostanziale, ma qui si parla del 7-800% in più per eseguire la STESSA cosa. 

 

Mi chiedo a questo punto a che livelli di programmazione sia necessario arrivare perchè ciò rappresenti un problema. Voglio dire: su una macchinetta media che costruisco io(3-4 assi brushless + una 20ina di ev pneumatiche, circa 50-60 i/o in tutto) potrei vedere la differenza secondo voi scrivendo tutto in un linguaggio piuttosto che l'altro? Oppure a questi livelli ST gli fa il solletico?

 

Se riesco, vorrei fare una prova: testare 2 program block che eseguono esattamente la stessa operazione(su un asse per esempio, diciamo una serie di posizionamenti in sequenza con qualche pausa in mezzo), e vedere che differenza in termini di tempo di scansione riscontrerei. Voi cosa ne pensate?

 

P.s: vorrei evitare i discorsi del tipo che ST è meglio per fare certe cose e Ladder è meglio per fare altre cose😊

 

 

 

 

 

 

 

 

 

 

Link al commento
Condividi su altri siti


Io faccio largo uso di ST e mi sono dato delle regole di sintassi e posizionamento del codice in modo da agevolare il debug e la visualizzazione on-line.

 

La condizione di uguale la gestisco così:

// Cumulativo delle condizioni che provocano l'arresto delle pompe
Ok_pompe :=(NOT OverloadInverterMotorHydraulicPump AND
            NOT OverloadMotorCoolingOil AND
            NOT OverloadMotorCoolingFan AND
            NOT OverloadMotorPilotValve AND
            NOT OverloadMotorCoolingOil AND
            NOT OverloadMotorServiceValve AND
            NOT Inverter_Fault_HydrPump AND
            Powersupply24Vdc_inputPLC AND
            Powersupply24Vdc_outputPLC AND
            Powersupply24Vdc_outputPLC_actuators AND
            Powersupply24Vdc_maincontrolpanel AND
            Powersupply24Vdc_Sinamics AND
            Powersupply24Vdc_IM174 AND
            NOT rit_energy_saving.Q) OR
            boSimulazioneIO;   

 

La condizione di SET-RESET la gestisco così:

IF    TemperaturaOlioPrincipale/10 > iSetpointRaffreddamentoPrincipale_M01 AND
    SensorLeveLTankOil AND 
    NOT Overloadmotorcoolingoil THEN
        START_Motorcooling  := TRUE;
END_IF;        
IF     (TemperaturaOlioPrincipale/10 < iStopCoolingPrincipale_M01) OR ONsafetyrelaygeneralcycle OR ONSafetyRelayEmergency THEN
        START_Motorcooling  := FALSE;
END_IF;

 

Notare bene che gli operandi sono su righe diverse per una visualizzazione chiara quanto la visualizzazione a contatti. Se si tratta di una cosa semplice allora metto tutto su una riga come per la condizione di RESET.

 

Ovviamente qualora ci siano delle restrizioni sullo sviluppo software mi adeguo e scrivo a contatti, ma non mi piaceva in passato, non mi piace ora e non penso possa piacermi in futuro.

 

 

Link al commento
Condividi su altri siti

Yiogo: forse la mia domanda non era chiara. Io volevo sapere chi di voi fa uso di ST a prescindere dal compito. Cioè chi lo usa per tutto il programma , senza chiedersi se sarebbe stato piu semplice scrivere certe parti in altri linguaggi. 

 

PigroPlc: esattamente ciò che volevo sapere. Il codice che hai postato è il tipico compito che si eseguirebbe a contatti, ma che alcuni preferiscono scrivere in ST. 

 

Solitamente tendo ad usare costrutti CASE per molte cose. Mi aiutano ad avere la visione piu completa possibile del flusso macchina. 

 

Un esempio:

 

 

//Servo Program K= (10*(NumeroAsse) + (i_wOpMode - 1))
//i_wOpMode: 
//0: NOT Enabled - Jog Available
//1: Home 
//2: INC
//3: ABS
//4: PFSTART
//...Fino a  499 per comando singolo asse
//......
//1000: Sync Control Command - Advanced Mode
------------------------------------------------*)
(***************************************************************************************)
(*****************************_ENABLE_********************************************)
IF i_xEn THEN
    IF NOT xExAct THEN    (* If Loc_Ex_Act_X = FALSE it's the first entry *)
        wState    := 10;
        xExAct    := TRUE;
    END_IF;
ELSE
    IF xExAct  THEN
        wState    := 1000;    
        xExAct     := FALSE;
    END_IF;
END_IF;

(**************************************************************************************)
(*****************************_STATE_*********************************************)    
CASE wState OF

0:    (* Not Enable *)
     xAxSVSTRq                        := FALSE;    
    xRapidStop                            := FALSE;
    xAxCHGVRq                         := FALSE;
    xSpeedChgEn                     := FALSE;

    o_xActive                                := FALSE;
    o_xError                                := FALSE;
    o_xOpModeActive            := FALSE;
    o_xOpModeDn                    := FALSE;
    o_wOpMode                        := 0;
    o_xSyncActive                    := FALSE;
    o_xSyncCtrlChgDn            := FALSE;
            
10: (* Wait  Start Servo Program Command *)
    o_xActive                                := TRUE;
    o_xOpModeActive            := FALSE;
    o_xOpModeDn                    := FALSE;
    o_xSyncCtrlChgDn            := FALSE;
     io_ServoCmd.dwSyncInitialParam := 0;
     
     (* Speed Change During Jog Command*) 
    dwCHGVSpeedChange    :=    io_ServoCmd.dwJogSpeed;
    
     (* Sync Ctrl Initial Position Parameter*)     
    MOVE_E( NOT xSyncCtrlFirstStartDn , 1 , io_ServoCmd.dwSyncInitialParam );    
        
        
                            
    IF    NOT io_ServoCmd.xRapidStopCommand    AND
         NOT io_ServoCmd.xStopCommand                AND
         NOT io_ServoStatus.xStartAccept                    AND
        io_ServoStatus.xServoReady                            AND
        NOT io_ServoCmd.xForwardRotationJOG    AND
        NOT io_ServoCmd.xReverseRotationJOG    AND
        i_xStart
    THEN
        o_wOpMode    := -1; (* OpMode Error *)
        
        IF (i_wOpMode > 0) AND (i_wOpMode < 499) THEN         

            MOVE_E( (i_wOpMode = 1) , 0 , xSyncCtrlFirstStartDn );                                         

            wServoBlock    := (10 * i_wAxNum) +  (i_wOpMode - 1); (* Servo Program K= (10*(NumeroAsse) + (i_wOpMode - 1)) *)        
            o_xOpModeActive    := TRUE;
            o_wOpMode                        := i_wOpMode;    
            wState                            := 20;            
        ELSIF (i_wOpMode >= 1000) AND (i_wOpMode < 1999) THEN                                      
            io_ServoCmd.xSyncControlStart    := TRUE;                (* Sync Control Command *)                      
            o_xOpModeActive    := TRUE;    
            o_wOpMode                        := i_wOpMode;
            wState                            := 200;
        END_IF;
        
    END_IF;

20: (* Servo Program Start Request *)
    xAxSVSTRq        := TRUE;

    (* Wait Ax Busy *)
    IF    io_ServoStatus.xStartAccept  OR xMotionScanOn THEN    
        wState                            := 30;
    END_IF;

    (* OpMode Change During Operation *)
    MOVE_E( o_wOpMode <>i_wOpMode , 900 , wState );                     
    (* Check Stop Command *)
    MOVE_E( (io_ServoCmd.xRapidStopCommand    OR io_ServoCmd.xStopCommand) , 600 , wState );
    (* Error Detection *)
    MOVE_E( o_xError , 500 , wState );

30: (* Servo Program Run *)    

    (* Speed Change Servo Program Run *)         
     dwCHGVSpeedChange    :=    io_ServoCmd.dwSpeed;

    (* Wait Servo Program Done *)     
    IF    NOT io_ServoStatus.xStartAccept THEN    
        o_xOpModeActive    := FALSE;    
        o_xOpModeDn            := TRUE;
        wState                            := 100;
    END_IF;

    (* OpMode Change During Operation *)
    MOVE_E( o_wOpMode <>i_wOpMode , 900 , wState );                     
    (* Check Stop Command *)
    MOVE_E( (io_ServoCmd.xRapidStopCommand    OR io_ServoCmd.xStopCommand) , 600 , wState );
    (* Error Detection *)
    MOVE_E( o_xError , 500 , wState );
        
100: (* Servo Program Done - Wait For New Cycle *)    

    IF NOT i_xStart THEN
        wState                := 10;
    END_IF;

    (* Error Detection *)
    MOVE_E( o_xError , 500 , wState );
    
(************************************)
(********* Sync Control ***********)
(************************************)
200:(* Sync Control Check *)

                            
    (* Sync Control Reset *)                                                              
    IF NOT i_xStart THEN
        io_ServoCmd.xSyncControlStart    := FALSE;
        wState                := 230;        
    (* Wait Sync Control Active *)    
    ELSIF io_ServoStatus.xSyncControlActive THEN
        xSyncCtrlFirstStartDn    := TRUE;
        wState    := 210;             
    END_IF;            

    (* Error Detection *)
    MOVE_E( o_xError , 500 , wState );
    (* Check Stop Command *)
    MOVE_E( (io_ServoCmd.xRapidStopCommand    OR io_ServoCmd.xStopCommand) , 400 , wState );

    
210: (* Check Sync Control Change Value *)        
    IF xMotionScanOn THEN
        dwPhaseOffset    := io_ServoCmd.dwPhaseOffset;
        dwPhaseRem    := ReminderDINT_FC((i_dwPhasePosition  + dwPhaseOffset) ,io_ServoCmd.dwCamAxisLenghtPerCycle );
        dwPhaseError    := dwPhaseRem - io_ServoStatus.dwCamAxisCurrentValuePerCycle;
        IF dwPhaseError >= (io_ServoCmd.dwCamAxisLenghtPerCycle / 2)THEN
            dwPhaseError    := dwPhaseError - io_ServoCmd.dwCamAxisLenghtPerCycle;
        ELSIF dwPhaseError <= -(io_ServoCmd.dwCamAxisLenghtPerCycle / 2) THEN
            dwPhaseError    := dwPhaseError + io_ServoCmd.dwCamAxisLenghtPerCycle;
        END_IF;               
        dwSyncControlChangeValue    := dwPhaseError;
        wState    := 220;
    END_IF;            
                                 
220:(* Sync Control Active *)

    (* Sync Control Reset *)                                                              
    IF NOT i_xStart THEN
        io_ServoCmd.xSyncControlStart    := FALSE;
        wState                := 230;
    ELSE
        IF i_xSyncCtrlChgRq AND xMotionScanOn THEN            
            (* Sync Control Change First Time  *)
            IF    NOT o_xSyncCtrlChgDn  AND (dwSyncControlChangeValue <> 0) THEN
                io_ServoCmd.dwSyncControlChangeCommand    := 4;
                 io_ServoCmd.dwSyncControlChangeValue            := dwSyncControlChangeValue;
                 wState                := 240;(* Sync Control Change Command Request *)
            (* Sync Control Change After First Sync Enable  *)
            ELSIF o_xSyncCtrlChgDn AND (dwPhaseOffset <> io_ServoCmd.dwPhaseOffset) THEN
                io_ServoCmd.dwSyncControlChangeCommand    := 4;
                io_ServoCmd.dwSyncControlChangeValue    := io_ServoCmd.dwPhaseOffset - dwPhaseOffset ;
                 o_xSyncCtrlChgDn    := FALSE;
                dwPhaseOffset := io_ServoCmd.dwPhaseOffset;
                 wState                := 240;(* Sync Control Change Command Request *)
            ELSE
                o_xSyncCtrlChgDn    := TRUE;
            END_IF;
        END_IF;
    END_IF;

    (* Error Detection *)
    MOVE_E( o_xError , 500 , wState );
    (* Check Stop Command *)
    MOVE_E( (io_ServoCmd.xRapidStopCommand    OR io_ServoCmd.xStopCommand) , 400 , wState );
    
230: (* Sync Control NOT Active *)
                            
    (* Wait Sync Control Active *)
    IF NOT io_ServoStatus.xSyncControlActive THEN
        wState    := 10;
    END_IF;    

    (* Error Detection *)
    MOVE_E( o_xError , 500 , wState );
    (* Check Stop Command *)
    MOVE_E( (io_ServoCmd.xRapidStopCommand    OR io_ServoCmd.xStopCommand) , 400 , wState );

240: (* Sync Control Change Command Request *)
    io_ServoCmd.xSyncCtrlChgRq    := xMotionScanOn ; 

    IF io_ServoCmd.xSyncCtrlChgRq AND NOT io_ServoStatus.xSyncCtrlChgDn THEN
        wState    := 250;
    END_IF;
    
250: (* Wait Sync Control Change Command Done *)

    (* Sync Control Reset *)                                                              
    IF NOT i_xStart THEN
        io_ServoCmd.xSyncControlStart    := FALSE;
        io_ServoCmd.xSyncCtrlChgRq    := FALSE;
        wState                := 230;        
    ELSIF io_ServoStatus.xSyncCtrlChgDn AND  xMotionScanOn THEN
        io_ServoCmd.xSyncCtrlChgRq    := FALSE;    
        o_xSyncCtrlChgDn                            := TRUE;
        wState    := 220; (* Sync Control Active *)        
    END_IF;

    (* Error Detection *)
    MOVE_E( o_xError , 500 , wState );
    (* Check Stop Command *)
    MOVE_E( (io_ServoCmd.xRapidStopCommand    OR io_ServoCmd.xStopCommand) , 400 , wState );

400: (* Check To Re-Stat Cycle *)
    io_ServoCmd.xSyncControlStart    := FALSE;                    
    io_ServoCmd.xSyncCtrlChgRq    := FALSE;            

    IF NOT io_ServoStatus.xStartAccept AND
        NOT io_ServoStatus.xSyncControlActive
    THEN
        wState    := 10;
    END_IF;        

500: (* Axis Error *)
    io_ServoCmd.xSyncControlStart    := FALSE;                    
    io_ServoCmd.xSyncCtrlChgRq    := FALSE;            
    o_xOpModeActive    := FALSE;    

    MOVE_E( NOT i_xStart AND NOT o_xError , 10 , wState );

900: (* OpMode Change During Execution  *)
    o_xOpModeActive            := FALSE;    
    xAxSVSTRq                        := FALSE;
    xRapidStop                            := TRUE;
    wState                                    := 910;

    MOVE_E( (NOT io_ServoStatus.xStartAccept OR o_xError) AND xMotionScanOn , 910 , wState );

910: (* Reset Rapid Stop Command *)
    xRapidStop            := FALSE;

    MOVE_E( NOT io_ServoCmd.xRapidStopCommand AND NOT i_xStart , 10 , wState );

600: (* Wait For Re-start Cycle *)     
    MOVE_E( NOT i_xStart , 10 , wState );
        
1000: (* Exit Action: Rapid Stop Command *)
    xRapidStop            := TRUE;
    wState                    := 1010;

1010: (* Exit Action: Wait Axis Not Busy *)
    IF NOT io_ServoStatus.xStartAccept
        AND
        xMotionScanOn
    THEN
        xRapidStop    := FALSE;
        wState            := 1020;    
    END_IF;
        
1020: (* Exit Action: Reset Servo Command *)
        o_xActive        := FALSE;
        io_ServoCmd.xSyncControlStart                := FALSE;
        io_ServoCmd.xServoOffCommand        := FALSE;
        io_ServoCmd.xRapidStopCommand    := FALSE;
        wState                    := 0;                                            
END_CASE;

(* Change State Check *)    
IF wState <>  wPrevState THEN
  wPrevState             :=  wState;
  wScanCnt    := 0;            
END_IF;

(* FB Active *)    
IF o_xActive THEN
     (* First Sync Reset  *)    
    MOVE_E( i_xSyncCtrlFirstStartRst , 0 , xSyncCtrlFirstStartDn );    

    (* Speed Change Enable*)
    xSpeedChgEn    := (o_xOpModeActive AND o_wOpMode > 1 AND o_wOpMode < 1000)
                                        OR
                                        (NOT o_xOpModeActive AND (io_ServoCmd.xForwardRotationJOG OR io_ServoCmd.xReverseRotationJOG));    

    IF xSpeedChgEn THEN
        xAxCHGVRq    :=    dwCHGVSpeedChange    <> dwCHGVSpeedChangeAux;
        dwCHGVSpeedChangeAux    := dwCHGVSpeedChange;
    END_IF;
 
     (* ServoCmd - Axis Reset *)    
    io_ServoCmd.xErrorReset        := i_xRst; 
    
    (* ServoCmd - Rapid Stop Command *)
    io_ServoCmd.xRapidStopCommand    := xRapidStop OR i_xRapidStop;

    (* ServoCmd - Servo Off Command *)
    io_ServoCmd.xServoOffCommand    := i_xServoOffRq;

    (* ServoStatus - Ax Error *)    
    o_xError    := io_ServoStatus.xErrorDetection                 OR
                            io_ServoStatus.xServoErrorDetection;
                            
    (* ServoStatus - Syn Control Active *)
    o_xSyncActive    := io_ServoStatus.xSyncControlActive;

    (* First Sync Done  *)
    o_xSyncCtrlFirstStartDn    := xSyncCtrlFirstStartDn; 
    
    (* Cycle Counter - 200 ms Delay *)
    wMinScanTime            := MAXIMUM( 1 ,SD524);
    wScanNum                     := 200/wMinScanTime;
    INC(wScanCnt  < 1000,wScanCnt);
    xMotionScanOn    := WORD_TO_INT(wScanCnt)  > wScanNum;     
END_IF;

(**************************************************************************************)
(*****************************_FB_CALL_*******************************************)                            
(* Servo Program Command *)
DP_SVST( xAxSVSTRq , i_wCpuNum, i_sAx , wServoBlock, aAxVSTCompleteDevice,wAxSVSTCompleteStatus);
xAxSVSTRq    := FALSE;
(* Speed Change Command *)
DP_CHGV( xAxCHGVRq , i_wCpuNum , i_sAx , dwCHGVSpeedChange , aAxCHGVCompleteDevice , wAxCHGVCompleteStatus);
xAxCHGVRq    := FALSE;

 

Questa è una FB di gestione asse che mi sono creato. Gestisce Jog, posizionamenti assoluti, relativi, sincronismi..oltre a gestire errori eventuali dell'asse . 

Farla in Ladder sarebbe stato senza dubbio possibile, ma notevolmente più dispersivo. 

 

 

 

 


 

Modificato: da step-80
Link al commento
Condividi su altri siti

Io trovo una scelta da masochisti fare tutto il programma in un unico linguaggio.
Per quanto riguarda i tempi di esecuzione, penso dipenda non tanto dal linguaggio, ma da come il PLC interpreta ogni linguaggio.
Per esempio, con S7-300 tutto viene sempre tradotto in AWL e, i programmi scritti in SCL, richiedono molte più istruzioni per svolgere lo stesso compito scritto direttamente in AWL.

Questo, ovviamente, incide sui tempi di esecuzione.

Con le CPU 1500, il compilatore SCL (ST) non converte in AWL (che non corrisponde esattamente a IL), ma genera il suo compilato, molto più efficiente rispetto a quanto fatto con S7-300.

 

Poi, a seconda del PLC ci saranno sicuramente differenze di tempi di esecuzione di un linguaggio rispetto ad un altro, ma le differenze dell'esempio le trovo alquanto inverosimili.
Oppure potranno essere reali per un particolare PLC, ma non da assumere come regole generali.

 

Link al commento
Condividi su altri siti

Quote

// Cumulativo delle condizioni che provocano l'arresto delle pompe
Ok_pompe :=(NOT OverloadInverterMotorHydraulicPump AND
            NOT OverloadMotorCoolingOil AND
            NOT OverloadMotorCoolingFan AND
            NOT OverloadMotorPilotValve AND
            NOT OverloadMotorCoolingOil AND
            NOT OverloadMotorServiceValve AND
            NOT Inverter_Fault_HydrPump AND
            Powersupply24Vdc_inputPLC AND
            Powersupply24Vdc_outputPLC AND
            Powersupply24Vdc_outputPLC_actuators AND
            Powersupply24Vdc_maincontrolpanel AND
            Powersupply24Vdc_Sinamics AND
            Powersupply24Vdc_IM174 AND
            NOT rit_energy_saving.Q) OR
            boSimulazioneIO;  

 

Anch'io quando mi trovo a scrivere in ST cose di questo tipo vado a capo ogni riga, per rendere tutto più leggibile.
Con una sola differenza rispetto all'esempio di Pigroplc: gli operatori AND e OR li metto a capo:

// Cumulativo delle condizioni che provocano l'arresto delle pompe
Ok_pompe :=(NOT OverloadInverterMotorHydraulicPump
            AND NOT OverloadMotorCoolingOil
            AND NOT OverloadMotorCoolingFan
            AND NOT OverloadMotorPilotValve 
            AND NOT OverloadMotorCoolingOil 
            AND NOT OverloadMotorServiceValve 
            AND NOT Inverter_Fault_HydrPump 
            AND Powersupply24Vdc_inputPLC 
            AND Powersupply24Vdc_outputPLC 
            AND Powersupply24Vdc_outputPLC_actuators 
            AND Powersupply24Vdc_maincontrolpanel 
            AND Powersupply24Vdc_Sinamics 
            AND Powersupply24Vdc_IM174 
            AND NOT rit_energy_saving.Q) 
            OR boSimulazioneIO;  

Ma è solo una questione di abitudini.

Link al commento
Condividi su altri siti

Roberto Gioachin
6 ore fa, step-80 scrisse:

ma qui si parla del 7-800% in più per eseguire la STESSA cosa

A parte che una differenza del genere è già strana, ma questo differisce molto da costruttore a costruttore.

Gli ambienti di sviluppo oggi compilano tutto quello che viene editato in un unico codice riconosciuto dalla CPU, questo significa che anche scrivendo in linguaggi diversi quello che entra realmente nel plc potrebbe essere la stessa cosa.

2 ore fa, step-80 scrisse:

Farla in Ladder sarebbe stato senza dubbio possibile, ma notevolmente più dispersivo.

Anche questo è molto discutibile, non è assolutamente detto che una volta compilato un programma sequenziale di questo tipo sia più "leggero" rispetto ad altri linguaggi, anche questo può variare molto da costruttore a costruttore.

Facciamo un esempio: la compilazione di quanto hai rappresentato comporta al codice plc di eseguire una serie di comparazioni per verificare il codice "CASE" attivo ed eseguire quanto riferito a quel codice; alcuni costruttori hanno istruzioni specifiche per eseguire le stesse operazioni (ma anche più complesse se serve) utilizzando il linguaggio SFC, e questo linguaggio utilizza dei BIT di passo, non ha quindi bisogno di fare comparazioni, riducendo il tempo di esecuzione, se poi si considera che ogni passo non attivo diventa un salto di programma si capisce come il tempo di esecuzione diminuisca ancora di più.

Quindi direi che le tue considerazioni possono essere corrette per un costruttore ma non per un altro.

 

Link al commento
Condividi su altri siti

1 ora fa, Roberto Gioachin scrisse:

A parte che una differenza del genere è già strana

Lo screen inviato arriva direttamente da un manuale Mitsubishi, per la precisione il manuale Structured Text per serie L. Anche a me sembra tanta roba, al punto da spingermi ad aprire la discussione. 

Dico la verità: ho 'barato' perchè speravo che scrivendo in una sezione più generica il post avrebbe avuto più visibilità. 

1 ora fa, Roberto Gioachin scrisse:

Anche questo è molto discutibile, non è assolutamente detto che una volta compilato un programma sequenziale di questo tipo sia più "leggero" rispetto ad altri linguaggi, anche questo può variare molto da costruttore a costruttore.

Aspetta, forse mi sono espresso male. Per me iil termine 'dispersivo' si riferisce solo ed esclusivamente al contesto grafico. 

Quando vedo una cosa del genere

CASE wState OF

0: fai questo; 

10; fai quest'altro; 

20: alza pippo

...ecc 

 

Con un colpo d'occhio capisco perfettamente cosa succede quando la mia variabile di stato assume valore 0,10,20 ecc.

In ladder(ma è sicuramente un mio limite) mi ci vuole di più. Questo in fase di stesura ma soprattutto in fase di debug. 

 

2 ore fa, batta scrisse:

Per esempio, con S7-300 tutto viene sempre tradotto in AWL e, i programmi scritti in SCL, richiedono molte più istruzioni per svolgere lo stesso compito scritto direttamente in AWL.

Batta il manuale a cui faccio riferimento è della serie L Mitsubishi, paragonabile come fascia al 300. A questo punto o i jap si sono tenuti come al solito dalla parte della ragione(anche se cifre cosi accurate mi fanno pensare abbiano eseguito dei test approfonditi) oppure...non saprei.

Riporto un altra pagina dove si prendono in considerazione altri costrutti:

 

Immagine2.png.287e6252198cb5969f09f4e697198206.png

 

 

Link al commento
Condividi su altri siti

Un programma semplice scritto in ST (poche righe) è più "pesante" di  uno scritto in ladder e occupa più memoria.

Questo vale per Mitsubishi , siemens non lo so. 

 

Link al commento
Condividi su altri siti

ifachsoftware

Ogni linguaggio ha un suo perchè , personalmente utilizzo Ladder per tutte le logiche Booleane , St per tutto quello che sono formule e calcoli.

Parlando di Siemens , col nuovo TIA Portal ho trovato molto comodo partire con un programma in Ladder , dove posso inserire dei rami in ST.

Facendo cosi' la parte booleana la scrivo in Ladder , il resto in St.

Non conosco le differenze di tempi di esecuzione , ma ritengo che con le potenze di calcolo dei PLC attuali e della complessità crescente dei programmi sia una priorità guardare innanzitutto alla leggibilità del codice prima ancora di risparmiare qualche nanosecondo per scrivere delle istruzioni (a meno che non strettamente necessario , in quel caso rimane sempre l'AWL ....).

Comunque con Siemens ci sono delle istruzioni per misurare i tempi ciclo ; per sfizio appena avrò del tempo faro' delle prove...

Modificato: da ifachsoftware
Link al commento
Condividi su altri siti

4 ore fa, batta scrisse:

Ma è solo una questione di abitudini.

Eh si Batta.

Devo dire che anche la tua soluzione risulta molto leggibile. Mi riservo di fare delle prove. 

Quello che conta è la facilità di comprensione quando si mette in visualizzazione dinamica per fare debug.

L'editor di Simotion a contatti è a dir poco penoso rispetto all'editor del TIA, già io propendo per l'ST, figuriamoci su Simotion.......

Quando la logica booleana si complica con più rami, tengo separate le singole condizioni racchiuse da parentesi, male che vada metto dei flag cumulativi. In fondo anche a contatti vale la pena di creare flag cumulativi piuttosto che complicare le cose creando mostri di incomprensione che necessiterebbero di un video bislungo.

37 minuti fa, ifachsoftware scrisse:

ma ritengo che con le potenze di calcolo dei PLC attuali e della complessità crescente dei programmi sia una priorità guardare innanzitutto alla leggibilità del codice prima ancora di risparmiare qualche nanosecondo

abbiamo creato linee di produzione con dei pedalò che giravano a 100 msec .... e parliamo di 35 anni fa! Si adottava addirittura la soluzione di utilizzare i micro switch a doppio contatto (uno NO che andava al plc come input da gestire nella logica e l'altro NC che interrompeva il movimento) altrimenti il pezzo si fermava con tolleranze mostruose.

Adesso devi mettere le ganasce alla cpu per farla girare a 4 msec. 😁

Concordo sulla LEGGIBILITA', il resto è un di più.

 

Link al commento
Condividi su altri siti

6 ore fa, step-80 scrisse:

esattamente ciò che volevo sapere. Il codice che hai postato è il tipico compito che si eseguirebbe a contatti, ma che alcuni preferiscono scrivere in ST

Step-80,

il CASE io lo uso solamente per le catene sequenziali, è la morte sua!

Qualora la catena sequenziale abbia la necessità di sdoppiarsi non faccio altro che impostare altri indici di CASE esterni che al termine dello svolgimento retituiscono un flag di catena sequenziale conclusa. Il flag viene quindi interrogato nella catena sequenziale principale. 

Qualche anno fa facevo anche qualcosa di simile qui sotto esposto perché mi sembrava di evidenziare lo stato dell'uscita ma è durata poco, ho standardizzato il sistema postato in precedenza. Si è rivelato un inutile orpello a mio avviso.

IF boAuxEVPressureON AND NOT EmergencyStop THEN
	AuxEVPressureON:= TRUE;
ELSE
 	AuxEVPressureON:= FALSE;
END_IF;

 

Link al commento
Condividi su altri siti

Marco Fornaciari

Per esperienza dal 1985, le prestazioni e l'uso di memoria dei linguaggi dipende dal tipo di PLC e dalla sua architettura interna, processore compreso.

Di Siemens 300 e 400 sappiamo tutti che il modo migliore di usare AWL.

Il "letterale" (odierno ST) Telemecanique e Modicon ante 1990 occupava 1/3 di memoria e 1/5 di tempo di scansione: e lì mi sono sbizzarito allo spasimo.

ST di Omron CX occupa 3 volte la stessa memoria e vale la pena usarlo solo per i calcoli, ma occhio alle troppe parentesi.

I linguaggi ST di altri PLC non li utilizzo, anche perchè i clienti non vogliono che venga utilizzato: i miei sono clienti utenti finali con manutenzione interna che vuole l'accesso.

Va da se che in abbinamento ai linguaggi bisogna anche fare anche buon uso di: task, subroutine, e blocchi funzione. Nel secolo scorso con l'uso appropriato in combinazione ho portato programmi da oltre 70 ms a 6, oppure forzato la scansione generale a 50 ms, ma con richiami di alcune task ogni 2 ms (Telemecanique e Siemen 115 CPU 945).

Con i PLC di ultima generazione il problema velocità normalmente non si presenta, ma c'è il probelma di semplicità nell'edizione e nella comprensione nel tempo di un programma.

Poi è inutile utilizzare un PLC nato per il Motion per far funzionare una impastatrice, ovvero uno per controllo di processo per una confezionatrice.

 

Link al commento
Condividi su altri siti

Nicola Carlotto

se uno proviene dalla pura elettromeccanica difficilmente usa ST, se uno proviene dalla pura informatica difficilmente usa il LADDER,

Ciao

Modificato: da Nicola Carlotto
Link al commento
Condividi su altri siti

9 ore fa, Nicola Carlotto scrisse:

se uno proviene dalla pura elettromeccanica difficilmente usa ST, se uno proviene dalla pura informatica difficilmente usa il LADDER

pensa che io ho fatto meccanica ..... 😁😁😁 per me è stato un trauma

Link al commento
Condividi su altri siti

Quote

Batta il manuale a cui faccio riferimento è della serie L Mitsubishi, paragonabile come fascia al 300. A questo punto o i jap si sono tenuti come al solito dalla parte della ragione(anche se cifre cosi accurate mi fanno pensare abbiano eseguito dei test approfonditi) oppure...non saprei.

Se i tempi riportati dal manuale Mitsubishi sono reali, significa una sola cosa: il Mitsubishi gestisce molto male il testo strutturato.
Poi, a dirla tutta, io non sono d'accordo con il conteggio delle istruzioni riportato nelle tabelle.
Seguiamo il primo esempio, che è il più semplice. Nella tabella scrivono che

IF X0 THEN

    D0 := 100;

END_IF;

equivale a 7 passi, mentre

LD X0

MOVE K100 D0

sono solo 3 passi.

In entrambi i casi significa:

- leggere lo stato di X0

- controllare se è vero o falso

- se è vero:
- caricare la costante 100

- scrivere il valore nella variabile D0

 

Come riescano a leggere 7 passi nel primo caso e 3 nel secondo, proprio non lo capisco.
Il lavoro che dovrà fare il processore, se il compilatore lavora come si deve, è esattamente lo stesso.
E poi, anche ammesso che il rapporto istruzioni sia 7/3, non si spiega lo stesso come il tempo di esecuzione diventi 12/1.
Ripeto, l'unica spiegazione che posso trovare è una pessima gestione del testo strutturato.

Link al commento
Condividi su altri siti

Immagine5.png.ffa380fe371db81989457a5d30afd568.png

 

A dire il vero, questo è quello che viene generato dal compilatore. Non sono ne 3 passi ne 7. 

Questo invece quanto generato facendo la stessa cosa in ladder

Immagine4.thumb.png.91b8a86e5569b50a6699558367103d67.png

E anche vero che la prima immagine si può tradurre semplicemente:

Immagine6.png.71f0c1ab0dde4cd719473b8446a1ec78.png

 

che diventa perfettamente uguale al ladder.

 

Link al commento
Condividi su altri siti

Roberto Gioachin

Attenzione, le due espressioni non sono la stessa cosa, per fare un confronto si devono utilizzare espressioni analoghe

A parte il fatto che, come dice batta, l'ST è gestito male se compila in quel modo, chi ha realizzato il software avrà avuto le sue ragioni ma usare salti di programma per queste istruzioni mi sembra un eccesso.

Detto questo, nel primo esempio si sono fatte delle impostazioni, sul secondo una assegnazione.

Prova in ST a scrivere M1 = M0, vedrai che la compilazione è molto diversa.

Io capisco che il plc ha tanta memoria ed un elevata velocità di elaborazione, ma non serve buttare via spazio in questo modo.

Io sono dell'opinione (e non solo io) che quando un programma inizia troppo spesso con "IF" non si è fatto un buon lavoro.

 

Vedo adesso che il terzo esempio è proprio quello che volevo dire io

 

 

Modificato: da Roberto Gioachin
Link al commento
Condividi su altri siti

@Roberto Gioachin io ho cominciato a programmare in un periodo recente, per cui non ero abituato a certe accortezze che permettono di ottimizzare le risorse. 

Ciò non toglie che scrivo e rompo le scatole perchè voglio imparare, avendo la fortuna di poterlo fare da Voi che siete Professionisti. 

Non mi è mai passato per la mente di usare bit al posto di word per sprecare meno risorse, ma da quando ho scoperto(grazie a voi) che il compilatore ed il tempo di scansione ringraziano cerco di stare attento a ciò che uso.

Non sapevo nemmeno che ST, ladder, SFC ecc vengono tradotti tutti nel medesimo listato...da quando l'ho scoperto ho cercato di imparare a tradurre, vado a vedermi cosa 'digerisce' il mio plc del minestrone che gli scrivo e cerco di ottimizzare. Certo questo se si tratta di macchine complesse, se sono 10 righe non sto li a sbattermi tanto. 

 

Questa del programma che inizia troppo spesso con IF è un'altra perla che non conoscevo; starò attento anche a come uso i costrutti visto che , se usati in modo improprio, portano via un sacco di risorse. 

 

Che ST di Mitsubishi sia gestito male...qui non posso pronunciarmi. C'è da dire che uso una versione di software (GX Works2) che è palesemente superata , ormai è già qualche anno che è uscito il 3 ma non l'ho mai usato(anche perchè, solito mistero giapponese, lo puoi usare solo con determinati tipi di cpu che io non uso). 

 

Ringrazio comunque tutti per il contributo. 

Link al commento
Condividi su altri siti

Roberto Gioachin

Il motivo per cui dico che il compilatore a me sembra troppo dispersivo è perché mi aspetterei questo:

 

2019-03-26_19h30_40.png.11ca61c047b99442b00fb334d4b32e9f.png

 

 

2019-03-26_19h31_32.png.a8bda96a6efd9d5dd136ce7fa68982e6.png

 

Lascia perdere i primi 17 passi che si riferiscono alla firma digitale dell'intero programma, lascia perdere anche il passo 22 che è un END e viene messo alla fine dell'intero programma, rimangono 4 passi. Questo mi aspetterei. 

Comunque sia si tratta di istruzioni di impostazione (Set e Reset), scritta così è inutile nel 90 percento dei casi, meglio un istruzione di assegnazione.

Se poi consideri che le istruzioni di Set e Reset sono fra i maggiori accusati quando si ha un programma che si ferma in maniera inaspettata, beh…  io direi di utilizzarli solamente dove servono.

 

Link al commento
Condividi su altri siti

13 minuti fa, Roberto Gioachin scrisse:

Se poi consideri che le istruzioni di Set e Reset sono fra i maggiori accusati quando si ha un programma che si ferma in maniera inaspettata, beh…  io direi di utilizzarli solamente dove servono.

Se ho capito bene, preferisci usare istruzioni di assegnazione (OUT) piuttosto che impostazione? E impostare come fai? autoritenute?

Link al commento
Condividi su altri siti

Marco Fornaciari

Esempio di marcia arresto

Variabili bool utilizzate

Ingresso   P_marcia = cablato NA

Ingresso   P_arresto = cablato NC

uscita       C_Motore

 

C_Motore:= (P_marcia OR C_Motore) AND P_arresto

 

Semplice!

Modificato: da Marco Fornaciari
invio errat
Link al commento
Condividi su altri siti

Marco Fornaciari

Scrivere in ST presuppone dimestichezza con alcune basilari regole matematiche.

Tra l'altro in diversi PLC l'uso delle istruzioni inizianti con IF non permette i fronti di salita e discesa delle variabili di uscita booleane, spesso per avere i fronti bisogna scivere:

 

IF pollo

Then SET uovo

END IF

 

uovo:= uovo    // serve per avere i fronti.

 

Poi se uno si vuole divertire

Mela:= ((gatto * cane) >= (mucca / cavallo * pera)) AND martello (porta OR cipolla AND carota) AND ( (cipolla ANDWORD 6298) / 25) AND (pippo (Pluto)[123] <> Mario (luigi)[123]) ecc. ecc. alla fine c'erano circa 200 caretteri per dare il consenso generale ad un dosaggio di ingredienti.

Pare non abbia senso, ma l'ho fatto, va da se c'erano anche: un cablaggio e una struttura di ricetta in sistonia con queste istruzioni create apposta per lasciare il programma sprotetto (come da capitolato) ma di fatto incomprensibile al 99,99 % dei programmatori, anche perchè dietro c'era la ricetta impostata sul PC e gestita da una sezione scritta in C e totalmente indicizzata.

Per la cronaca, le variabili: gatto, cane, mucca, cavallo, pera, e cipolla, sono ingressi e uscite digitali che indicano lo stato dell'impianto. Solo in due sapevamo il significato.

 

 

 

 

Link al commento
Condividi su altri siti

Roberto Gioachin
11 ore fa, step-80 scrisse:

Se ho capito bene, preferisci usare istruzioni di assegnazione (OUT) piuttosto che impostazione? E impostare come fai? autoritenute?

Non ho mai detto che non uso le impostazioni, ma le uso solo se servono e sto ben attento.

 

9 ore fa, Marco Fornaciari scrisse:

C_Motore:= (P_marcia OR C_Motore) AND P_arresto

Questo è il modo giusto. Più affidabile e meno impegnativo per il plc.

 

Link al commento
Condividi su altri siti

9 ore fa, Marco Fornaciari scrisse:

C_Motore:= (P_marcia OR C_Motore) AND P_arresto

 

Sto ancora aspettando che mi capiti un problema del genere, dove ho 1 uscita motore, 1 pulsante di start ed 1 di stop. 

Ho provato anche questa strada (quindi niente SET e niente RST) sia in Ladder che in ST, è vero hai il vantaggio che la tua uscita è scritta in un posto solo ed hai chiare davanti le condizioni per le quali deve attivarsi e disattivarsi. Ma se le condizioni sono date da vari altri blocchi, i quali possono presentare diverse modalità operative ognuna delle quali deve poter scrivere su quell'uscita ..per quanto si tenti di rimanere puliti ed ordinati l'unica salvezza rimane commentare anche quello che li per li si ritiene superfluo secondo me.

Commentare, commentare ed ancora commentare.

Parlo per me sia chiaro. Non ho più la memoria che avevo 20 anni fa , a volte mi vengono idee che se non metto giù subito scritte da qualche parte svaniscono in fretta, sormontate da quella miriade di 'lampadine' che ci si accendono e spengono in testa continuamente(bit😃).

 

8 ore fa, Marco Fornaciari scrisse:

uovo:= uovo    // serve per avere i fronti.

Qui non ci sono arrivato. Se fai SET uovo, uovo assume stato 1. 

Poi assegni lo stato di uovo(che dovrebbe essere 1) ad uovo..il quale dovrebbe rimanere ad 1. Cosa mi sono perso?

 

 

 

 

Modificato: da step-80
Link al commento
Condividi su altri siti

Crea un account o accedi per commentare

Devi essere un utente per poter lasciare un commento

Crea un account

Registrati per un nuovo account nella nostra comunità. è facile!

Registra un nuovo account

Accedi

Hai già un account? Accedi qui.

Accedi ora
×
×
  • Crea nuovo/a...