Vai al contenuto
PLC Forum

Partecipa anche tu alla Live su Youtube martedì 28/01/2025 per festeggiare i 24 anni di PLC Forum

Per ulteriori informazioni leggi questa discussione: https://www.plcforum.it/f/topic/326513-28012025




Incrementare Una Dword Ogni Secondo E Contatempo.


Messaggi consigliati

Inserito:

Ciao a tutti,

Avrei bisogno di contare il tempo di lavoro totale di un motore senza usare contatori.

So' che e' un argomento stratrattato ma non sono riuscito a capire come fare.

Dopo varie ricerche sul forum mi piacerebbe sviluppare la soluzione proposta da Batta qualche anno fa...( l'ho riportata sotto)

non so' pero' come fare ad incrementare una Dword ogni secondo , ho provato con ADD_I ed un clock di un secondo ma non funziona!!!

Come si fa' poi a convertire la Dword in ( o con l'uso delle istruzioni /D e MOD) HH:MM:ss ???

Il programma e' su una CPU 318.

Grazie a tutti

Buona giornata

Roberto

Post di Batta

Inviato 20 dicembre 2008 - 22:40

Se ne è parlato più volte.
Io ti sconsiglierei l'uso dei contatori, che hanno valore massimo di conteggio di 999.
Certo, potresti utilizzare un contatore per i secondi, uno per i minuti e uno per le ore. Uno spreco enorme!
A mio avviso, il sistema più comodo è quello di incrementare una DWORD ogni secondo. Si ottiene un conteggio accurato e, con una DWORD, si arriva a contare fino a circa 68 anni.
Insomma, con un semplice clock di un secondo (ricavabile anche da merker di clock configurabili della cpu), ottieni un contasecondi semplicissimo da gestire.
Personalmente considero i contaore fatti incrementando i secondi, poi i minuti (ogni 60 secondi), poi le ore (ogni 60 minuti), una inutile complicazione.
Se poi ti serve la visualizzazione in hh:mm:ss, puoi seguire due strade: o la conversione fatta direttamente dall'interfaccia operatore (se presente ed in grado di farlo), o con l'uso delle istruzioni /D e MOD.

Dei semplici contasecondi sono anche facili da usare quando c'è da dare alternanza al funzionamento di utenze: basta una semplicissima comparazione per capire qual è l'utenza che ha lavorato meno, e decidere di farla partire per prima.
Se si parte con la gestione separata di ore, minuti e secondi, servono più comparazioni per arrivare al risultato.


Inserita: (modificato)

ho provato con ADD_I

scusa ADD a cosa? Immagino tu abbia messo anche l'altro addendo (1). In ogni caso io avrei utilizzato le funzioni di INCremento.

Modificato: da Lucky67
Inserita:

ho provato con ADD_I ed un clock di un secondo ma non funziona!!!

Se non fai vedere il codice, come possiamo capire dove hai sbagliato?

O meglio, un errore si vede subito: hai utilizzato l'istruzione ADD_I , che è la somma fra interi a 16 bit, con variabili a 32 bit. Casomai dovresti usare ADD_DI.

Ma immagino ci sian anche altri errori.

Se non vuoi complicarti la vita allegando immagini del codice scritto in KOP, convertilo in AWL ed incollalo in un post.

Per l'utilizzo delle istruzioni /D e MOD dovresti prima studiare il manuale, è poi chiedere cosa non capisci.

In breve:

l'istruzione /D è una divisione fra interi.

L'istruzione MOD ti dà invece il resto della divisione (sempre tra interi).

Per esempio, se il mio contatore è arrivato a contare 7418 secondi, con l'istruzione /D calcolo 7418 / 3600 = 2 (ovvero due ore). Con MOD ottengo il resto della divisione, ovvero 218 secondi.

Poi posso dividere i 218 secondi per 60 (con /D) ed ottengo 3. Con MOD ottengo nuovamente il resto, che è 38 secondi.

Quindi 7418 secondi corrispondono a 2 ore, 3 minuti e 38 secondi.

Inserita: (modificato)

il codice che ho iniziato a testare e' il seguente:

La prima parte conta il numero di accensioni con un contatore e funziona ,

La seconda parte e' quella che faccio fatica a capire...scusate ma e' la prima volta che scrivo in AWL e non conoscevo la funzione INC con i vari accumulatori.

Ho cercato di seguire l' . di siemens ma non riesco a capire come fare!!! in rosso la parte che non funziona.

La funzione di INC si verifica ad ogni ciclo del programma a prescindere dalle istruzioni precedenti?

FUNCTION FC 9 : VOID
TITLE =
VERSION : 0.1

BEGIN
NETWORK
TITLE =Start Motore

A DB3.DBX 2.0;
= DB9.DBX 14.1;
NETWORK
TITLE =

NETWORK
TITLE =numero di cicli di partenza

A DB9.DBX 14.1; //contatto di motore acceso
CU C 60;
BLD 101;
A M 0.1; //Contatto sempre on
L C#0;
S C 60;
NOP 0;
NOP 0;
LC C 60; // contatore del numero di accensioni
T DB9.DBW 12;
NOP 0;
NETWORK
TITLE =Tempo totale di accensione motore

A DB9.DBX 14.1; //contatto di motore acceso
A M 4.1; // clock con frequenza 1 HZ
L DB9.DBB 15;
////// il valore va da 00 a ff in modo rapido senza mai fermarsi, io pensavo che solo se le due condizioni precedenti davano RLC 1 si passasse ad incrementare di uno il valore della DB9.DBB 15.

INC 1;
T DB9.DBB 15;

NETWORK
TITLE =

L DB9.DBB 15;
T DB9.DBW 18;
NOP 0;
END_FUNCTION

Grazie Batta , la parte /D e MOD ora mi e' chiara.

Grazie per la pazienza....

Modificato: da roberto1972
Inserita:

La funzione di INC si verifica ad ogni ciclo del programma a prescindere dalle istruzioni precedenti?

Si almeno finchè RLC è 1- Se utilizzi un clock ad onmda quadra di 1 Hz avrai il segnale di clock a 1 per 500 ms e quindi INC continuerà a incrementare finchè il clock stesso non andrà nella fase di "riposo" ( o chiaramente il motore si fermerà). Devi mettere un fronte di salita dopo il clock in modo che ti dia solo un impulso ogni volta che RLC va ad uno e che quindi possa incrementare di uno solo ogni volta che sale il clock.

Inserita: (modificato)

Tutte le istruzioni che scrivi vengono eseguite, indipendentemente dallo stato di RLC.

Se vuoi che alcune istruzioni non vengano eseguite, devi fare un salto.

Ti sconsiglio inoltre di usare l'istruzione INC che lavora solo su variabili a 8 bit.

Vedo infatti che utilizzi la variabile DB9.DBB15 per fare l'incremento con INC, e poi trasferisci questa variabile di tipo BYTE nella variabile DB9.DBW18. Questo non ha alcun senso. Il tuo conteggio andrà da 0 a 255.

Potresti riscrivere il codice come segue:

TITLE =Tempo totale di accensione motore

      A     DB9.DBX   14.1              //contatto di motore acceso
      A     M      4.1                  // clock con frequenza 1 HZ
      JCN   M000                        //Se RLC=1 non saltare
      L     DB9.DBW   18                //Incrementa conteggio
      +     1
      T     DB9.DBW   18
M000: NOP   0

Tieni presente che usando per il conteggio una word (16 bit) puoi contare al massimo fino a 32767 secondi, che corrispondono a poco più di 9 ore.

Se hai bisogno di andare oltre questo limite, utilizza una DWord (32 bit), ed arrivi a contare fino a circa 68 anni.

Modificato: da batta
Inserita: (modificato)

Grazie

Con le vostre dritte sono riuscito ad andare avanti

TITLE =Tempo totale di accensione motore

A DB9.DBX 14.1 //contatto di motore acceso
A M 4.1 // clock con frequenza 1 HZ
FP M 99.0 // fronte positivo di salita
JCN M000 //Se RLC=1 non saltare
L DB9.DBD 18 //Incrementa conteggio con Dword
+ 1
T DB9.DBD 18
M000: NOP 0

Ora con la Dword calcolo i tempi

L DB9.DBD 18 //totale secondi
L 3600
/D
T DB9.DBD 22 //ore

L DB9.DBD 18
L 3600
MOD
T DB9.DBD 26 //resto

L DB9.DBD 26
L 60
/D
T DB9.DBD 30 //minuti

L DB9.DBD 26
L 60
MOD
T DB9.DBD 34 //resto dei secondi

Si puo' ora creare in un unico dato le ore/minuti/secondi usando dbd22:dbd30:dbd34 ?

Modificato: da roberto1972
Inserita:

per visualizzare i valori di ore minuti secondi non in forma esadecimale ho usato il move

E' corretto fare cosi?

L DB9.DBD 22 // dato in Dword
T DB9.DBD 38 // dato in Dint
NOP 0

Inserita:

Il move da DB9.DBD22 a DB9.DBD38 non ti serve.

Che tu abbia dichiarato la DB9.DBD22 come DWORD o come DINT non cambia nulla. Puoi sempre decidere di visualizzare il valore in decimale o in esadecimale, ma si tratta solo di diversa visualizzazione del valore. Il valore però è sempre lo stesso.

Inutile poi "sprecare" delle DWORD (o DINT) soprattutto per contenere minuti e secondi, che non vanno oltre il 59. Meglio usare dei semplici byte o, al massimo, delle word (o INT, che è lo stesso).

Anche se il risultato della divisione con /D e del resto con MOD è un valore a 32 bit, almeno per quanto riguarda minuti e secondi non potrà mai essere maggiore di 59. Puoi quindi trasferire il risultato in un byte, senza bisogno di trasformazioni di formato.

Quindi potresti benissimo scrivere:

      L     DB9.DBD   18                //totale secondi
      L     3600
      /D    
      T     DB9.DBW   22                //ore

      L     DB9.DBD   18
      L     3600
      MOD   
      T     #tmp_resto
      L     60
      /D    
      T     DB9.DBB   24                //minuti
      L     #tmp_resto
      L     60
      MOD   
      T     DB9.DBB   25                //resto dei  secondi

Per le ore ho ipotizzato che un conteggio fino a 32767 ore potesse bastare, quindi ho usato una variabile a 16 bit.

Per il resto della divisione ho usato una variabile temporanea. Visto che divido per 3600 il resto non potrà mai superare il valore di 3599, quindi anche questa variabile può essere a 16 bit.

Per i minuti e per i secondi, ho usato un byte.

Se metti i valori di DB9.DBD18, DB9.DBW22, DB9.DBB24 e DB9.DBB25 in una tabella di variabili, puoi visualizzare i valori in formato decimale e vedere che tutto funziona.

Anche nel blocco di codice puoi scegliere il formato di visualizzazione, semplicemente cliccando col tasto destro del mouse sui valori visualizzati.

Inserita:

grazie Batta,

ho fatto le modifiche consigliate e modificato la lettura in decimale, tutto ok.

fatta anche la tabella variabili, ora posso controllare i tempi di accensione .

Mi manca solo il fatto di avere questi 3 dati hh mm ss in uno unico , ho gia' letto che esiste il dato TIME ma come faccio a comporlo con i miei DB9.DBW22, DB9.DBB24 e DB9.DBB25 ?

Lo vorrei fare per poi provare a spostarlo sul' HMI winflex 2008 SP2 che gestisce il tutto... se riesco...questo non e' fondamentale.

Probabilmente ho bisogno dalle ore totali ricavare i giorni ma questo ora non ""piu'""( grazie a voi ) un problema usero' ancora /D e MOD , modifico il dato db9.dbw22 in byte e uso un'altra word per i giorni.

grazie dell'aiuto

Inserita:

Il dato in formato TIME non è altro che il tempo in millisecondi.

Se utilizzi un pannello operatore Siemens, non hai bisogno di scomporre i secondi totali in hh:mm:ss, ma ti basta moltiplicare per 1000 e mettere il risultato in una variabile dichiarata come TIME.

Il pannello operatore farà tutto il resto.

In questo modo però limiti il conteggio massimo fino a circa 24 giorni.

Se devi superare questo limite, mantieni le variabili separate e sul pannello operatore le visualizzi una vicina all'altra.

Se hai bisogno anche dei giorni, in testa al procedimento precedente (che comincia con la divisione per 3600 per calcolare le ore) inserisci una divisione per 86400, che sono i secondi di un giorno. Il resto lo dividi per 3600 e calcoli le ore, e così via.

Tieni presente che la variabile temporanea usata per il resto della divisione in questo caso può arrivare ad un valore massimo di 86399, quindi non può più essere una INT come nell'esempio precedente, ma deve per forza essere una DINT.

Per la dimensione delle variabili potresti quindi utilizzare una word per i giorni, e un byte per le ore, per i minuti e per i secondi.

Se poi preferisci usare word anche per ore minuti e secondi, non saranno certo quei tre byte utilizzati in più a creare problemi.

Inserita: (modificato)

grazie batta e lucky67 siete stati di grande aiuto

funziona tutto

ciao

Modificato: da roberto1972
Inserita:

"Il dato in formato TIME non è altro che il tempo in millisecondi.

Se utilizzi un pannello operatore Siemens, non hai bisogno di scomporre i secondi totali in hh:mm:ss, ma ti basta moltiplicare per 1000 e mettere il risultato in una variabile dichiarata come TIME.

Il pannello operatore farà tutto il resto."

ho provato ma non mi funziona...ho cantato vittoria troppo presto

In winflex ho richiamato la variabile che conta i millisecondi *1000 del blocco DB che e' impostata in formato TIME e'

db9.dbd18*1000 = db9.dbd24

DB9.dbd24 TIME T#1H1M1S T#1H1M1S in simatic funziona vedo ore minuti secondi scorrere.

quando creo una campo O in winflex non mi da' la possibilita' di impostarlo in formato TIME , imposto come valore da acquisire db9.dbd24

Se in winflex lo imposto in formato decimali vedo i millisecondi che scorrono ma non hh mm ss

Perche' non ho l'opzione time nel campo Output?

cosa sbaglio!!!

le ho provate tutte

grazie

ciao

Inserita:

Sì, hai ragione.

Per visualizzare automaticamente il tempo in hh:mm:ss il formato della variabile deve essere TIME_OF_DAY, e non TIME.

In questo caso però, la visualizzazione è corretta solo fino a 23:59:59.

Inserita:

perfetto ora si vede.

Se io pero' arrivato a 23:59:59 resetto i millisecondi e riparto da 0 e nello stesso tempo incremento di uno il conteggio dei giorni poi il time riparte da 0:00:00 e cosi' non sbaglia, giusto ?

Ora provo.

Inserita:

Sì, ma a questo punto devi comunque visualizzare sul pannello operatore due variabili, una INT per i giorni e una TIME_OF_DAY per ore minuti e secondi.

Se è questa la strada che intendi seguire, piuttosto che fare incremento dei giorni e azzeramento dei millisecondi, ti conviene usare sempre il metodo della divisione con il resto (partendo dalla variabile che contiene il conteggio totale in secondi).

Con una divisione per 86400 ricavi direttamente il numero dei giorni, mentre con MOD ti rimane il resto in secondi. Moltiplichi il resto per mille e metti il risultato nella variabile TIME_OF_DAY.

Esempio:

      L     DB9.DBD   18                //Var DINT conteggio totale in secondi
      L     L#86400                     //Secondi in un giorno
      /D    
      T     DB9.DBW   22                //Totale Giorni
      L     DB9.DBD   18                //Var DINT conteggio totale in secondi
      L     L#86400                     //Secondi in un giorno
      MOD                               //Calcola resto
      L     L#1000
      *D                                //Moltiplica resto per 1000
      T     DB9.DBD   24                //Trasferisci in variabile tipo TIME_OF_DAY
Inserita:

Il dubbio che mi ha portato a far resettare il conteggio di DB9.DBD18 era al superamento di 86400, ma giustamente tu usi il resto della divisione e quindi questo resto non potra' mai superare 23:59:59 ( scusa me lo spiego a me stesso...)

Come dicevi anche tu in un precedente post il limite e' di circa 24 gg .

Ho utilizzato sia il conteggio che il calcolo dei giorni come hai detto nel post.Tutto ok.

Ora pero' giusto per capire se volessi resettarlo ad ogni giorno raggiunto e' corretto scrivere cosi' dopo il calcolo del Time_OF_DAY?

Al raggiungimento di 86400 incrementa di 1 i giorni e poi resetta i secondi

L DB9.DBD 18 //Var DINT conteggio totale in secondi

L L#86400
==D
JCN M002
L DB9.DBW 22 //Totale Giorni

+ 1
T DB9.DBW 22

L 0
T DB9.DBD 18

M002: NOP 0

grazie

ciao

Inserita:

Sì, certo.

Apporterei solo una piccola modifica: usare >= al posto di ==

In realtà funziona tutto perfettamente anche con == .

L'unico inconveniente si potrebbe verificare solo se la DB9.DBD18 venisse modificata manualmente impostando un valore superiore a 86400.

Inserita:

grazie sei stato di grande aiuto

devo studiare un po di awl!!!

ciao

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...