Vai al contenuto
PLC Forum


Segnalazione Acustica- Cicalino


stefano_PLC

Messaggi consigliati

Buongiorno, su una cpu s7-1200 sto istallando oltre alla lampada dell' avaria una segnalazione acustica (cicalino), solamente che quando do il reset a prescindere se ho risolto le mie avarie o meno deve cessare il cicalino, idee su come farlo?

Perchè io quando sono in  avaria setto il bit del cicalino, quando premo il  reset rilevo il fronte di salita e resetto i l bit, il mio dubbio sorge quando non ho risolto le avarie e quindi mi rimane settato il cicalino, come posso risolvere questa cosa?

grazie in anticipo

Link al commento
Condividi su altri siti


Metodo che ho applicato per risolvere, secondo voi è giusto?

Personalmente ho fatto un confronto salvandomi il codice dell' avaria in una variabile di appoggio quando do il reset, quindi confronto il codice avaria è diverso dalla variabile di appoggio abilito il cicalino, se sono uguali non si ecciterà la bobina e quindi non suonerà, ovviamente ogni volta che si eccita la bobina pulisco i miei campi di appoggio.

Modificato: da stefano_PLC
Link al commento
Condividi su altri siti

prova questo codice 

 

FUNCTION "MEM_OR_AND" : Bool
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_INPUT 
      IN1 : Any;
      IN2 : Any;
      boAND_OR : Bool;   // FALSE = AND; TRUE = OR
   END_VAR

   VAR_TEMP 
      RetVal : Int;
      IN1End : DInt;   // End addresses for memory areas
      IN2End : DInt;
      Tst1 : Byte;
      Tst2 : Byte;
      MemPtr : DInt;   // Current memory pointer
      pIN1 : Any;   // DB address ANY pointer - used for accessing DB data
      pAnyIN1 AT pIN1 : Struct   // Diassembled ANY pointer structure
         S7Code : Byte;   // Code for S7 (fixed at 16#10)
         DataType : Byte;   // Code for data type
         Length : Int;   // Repetition factor = Send/receive length
         DBNumber : Int;   // Data block Number
         MemoryArea : Byte;   // Specified memory area = 0x84 = data block
         ByteAddressMSB : Byte;   // Byte address most significant bits
         ByteAddressLSB : Word;   // Byte address least significant bits
      END_STRUCT;
      u1Addr : DInt;   // Union pointer for calculation of byte offset address
      u1 AT u1Addr : Struct   // This is equivalent to a union in 'c' dword goes in and word / byte LSB / byte MSB come out
         ByteAddrLSBPad : Byte;   // Not Used
         ByteAddrMSB : Byte;   // Byte address most significant bits
         WordAddr : Word;   // Byte address least significant bits
      END_STRUCT;
      pIN2 : Any;   // DB address ANY pointer - used for accessing DB data
      pAnyIN2 AT pIN2 : Struct   // Diassembled ANY pointer structure
         S7Code : Byte;   // Code for S7 (fixed at 16#10)
         DataType : Byte;   // Code for data type
         Length : Int;   // Repetition factor = Send/receive length
         DBNumber : Int;   // Data block Number
         MemoryArea : Byte;   // Specified memory area = 0x84 = data block
         ByteAddressMSB : Byte;   // Byte address most significant bits
         ByteAddressLSB : Word;   // Byte address least significant bits
      END_STRUCT;
      u2Addr : DInt;   // Union pointer for calculation of byte offset address
      u2 AT u2Addr : Struct   // This is equivalent to a union in 'c' dword goes in and word / byte LSB / byte MSB come out
         ByteAddrLSBPad : Byte;   // Not Used
         ByteAddrMSB : Byte;   // Byte address most significant bits
         WordAddr : Word;   // Byte address least significant bits
      END_STRUCT;
   END_VAR


BEGIN
	(*
	effettua l'OR logico oppure l'AND logico fra 2 aree di memoria e lo mette sull'area del secondo parametro
	esempio utile se si vuole gestire il fronte di salita di un bit della prima area basta far ciclare una volta 
	l'OR logico quindi equalizzare le aree. 
	Con l'AND logico si azzerano anche gli allarmi della seconda area
	
	ESEMPIO:
	si vuole far suonare una sirena ogni volta che un allarme nuovo si verifica:
	1) richiamare il blocco MEM_OR_AND con il bit boAND_OR FALSE in modo da aggiornare la seconda area se un allarme cessa di esistere
	2) richiamare il blocco MEMCMP con il suo flag di uscita IN NEGATO collegato alla sirena (si attiva ogni volta che le aree sono diverse)
	3) sul fronte di salita del pulsante di tacitazione collegare il bit boAND_OR TRUE in modo da aggiornare la seconda area come la prima, quindi 
	   l'uscita MEMCMP ritorna FALSE
	*)
	
	
	
	
	#pIN1 := #IN1;                                  // appoggia il puntatore
	#pAnyIN1.DataType := 16#02;                     // forza il formato dei byte
	#u1.ByteAddrMSB := #pAnyIN1.ByteAddressMSB;     // aggiorna i puntatori
	#u1.WordAddr := #pAnyIN1.ByteAddressLSB;
	#IN1End := #u1Addr + (#pAnyIN1.Length * 8);     // aggiorna la fine shiftata dei 3 bit del puntatore 
	#pAnyIN1.Length := 1;                           // confronta solamente un byte alla volta
	
	#pIN2 := #IN2;                                  // idem per area di confronto
	#pAnyIN2.DataType := 16#02;
	#u2.ByteAddrMSB := #pAnyIN2.ByteAddressMSB;
	#u2.WordAddr := #pAnyIN2.ByteAddressLSB;
	#IN2End := #u2Addr + (#pAnyIN2.Length * 8);
	#pAnyIN2.Length := 1;
	
	// fault parameters
	IF (#IN1End - #u1Addr) <> (#IN2End - #u2Addr) THEN
	        #MEM_OR_AND:= TRUE;                         // errore dei parametri, valore di ritorno a uno
	        RETURN;
	END_IF;
	
	
	WHILE (#u1Addr < #IN1End) AND (#u2Addr < #IN2End) DO    // confronto fino alla fine dei bytes
	    #RetVal := BLKMOV(SRCBLK := #pIN1, DSTBLK => #Tst1);// legge i byte dal primo all'ultimo 
	    IF #RetVal <> 0 THEN
	        #MEM_OR_AND := TRUE;                       // errore di lettura, valore di ritorno a uno
	        RETURN;
	    END_IF;
	    #RetVal := BLKMOV(SRCBLK := #pIN2, DSTBLK => #Tst2);
	    IF #RetVal <> 0 THEN
	        #MEM_OR_AND := TRUE;                       // errore di lettura, valore di ritorno a uno
	        RETURN;
	    END_IF;
	    
	(*
	esamina l'AND o l'OR in funzione del parametro di ingresso per ripulire la seconda area o per aggiornare la seconda area come la prima
	*)
	   
	    IF #boAND_OR THEN
	        #Tst2 := #Tst1 OR #Tst2;
	    ELSE
	        #Tst2 := #Tst1 AND #Tst2;
	    END_IF;
	(*
	quindi rinfresca il byte ..... e aggiorna i parametri
	*)    
	    #RetVal := BLKMOV(SRCBLK := #Tst2, DSTBLK => #pIN2 );
	
	    #u1Addr := #u1Addr + 8;                     // incremento dei puntatori
	    #pAnyIN1.ByteAddressMSB := #u1.ByteAddrMSB;
	    #pAnyIN1.ByteAddressLSB := #u1.WordAddr;
	    #u2Addr := #u2Addr + 8;
	    #pAnyIN2.ByteAddressMSB := #u2.ByteAddrMSB;
	    #pAnyIN2.ByteAddressLSB := #u2.WordAddr;
	    
	END_WHILE;
	
	#MEM_OR_AND := FALSE;
	
	
	
	
	
END_FUNCTION

il richiamo invece è questo:

"boErroreParametri" := "MEM_OR_AND"(IN1 := P#DB235.DBX50.0 BYTE 30,
                                    IN2 := P#DB236.DBX50.0 BYTE 30,
                                    boAND_OR := "boAND");

da un punto di vista concettuale tu hai 2 aree bitmap che dedichi agli allarmi.

uno è quello degli allarmi attivi e l'altro è quello degli allarmi tacitati. L'esempio verifica 30 bytes fra le DB235 e DB236

 

buon divertimento

Link al commento
Condividi su altri siti

questo è il blocco MEMCP

 

FUNCTION "MEMCMP" : Bool
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
   VAR_INPUT 
      IN1 : Any;
      IN2 : Any;
   END_VAR

   VAR_TEMP 
      RetVal : Int;
      IN1End : DInt;   // End addresses for memory areas
      IN2End : DInt;
      Tst1 : Byte;
      Tst2 : Byte;
      MemPtr : DInt;   // Current memory pointer
      pIN1 : Any;   // DB address ANY pointer - used for accessing DB data
      pAnyIN1 AT pIN1 : Struct   // Diassembled ANY pointer structure
         S7Code : Byte;   // Code for S7 (fixed at 16#10)
         DataType : Byte;   // Code for data type
         Length : Int;   // Repetition factor = Send/receive length
         DBNumber : Int;   // Data block Number
         MemoryArea : Byte;   // Specified memory area = 0x84 = data block
         ByteAddressMSB : Byte;   // Byte address most significant bits
         ByteAddressLSB : Word;   // Byte address least significant bits
      END_STRUCT;
      u1Addr : DInt;   // Union pointer for calculation of byte offset address
      u1 AT u1Addr : Struct   // This is equivalent to a union in 'c' dword goes in and word / byte LSB / byte MSB come out
         ByteAddrLSBPad : Byte;   // Not Used
         ByteAddrMSB : Byte;   // Byte address most significant bits
         WordAddr : Word;   // Byte address least significant bits
      END_STRUCT;
      pIN2 : Any;   // DB address ANY pointer - used for accessing DB data
      pAnyIN2 AT pIN2 : Struct   // Diassembled ANY pointer structure
         S7Code : Byte;   // Code for S7 (fixed at 16#10)
         DataType : Byte;   // Code for data type
         Length : Int;   // Repetition factor = Send/receive length
         DBNumber : Int;   // Data block Number
         MemoryArea : Byte;   // Specified memory area = 0x84 = data block
         ByteAddressMSB : Byte;   // Byte address most significant bits
         ByteAddressLSB : Word;   // Byte address least significant bits
      END_STRUCT;
      u2Addr : DInt;   // Union pointer for calculation of byte offset address
      u2 AT u2Addr : Struct   // This is equivalent to a union in 'c' dword goes in and word / byte LSB / byte MSB come out
         ByteAddrLSBPad : Byte;   // Not Used
         ByteAddrMSB : Byte;   // Byte address most significant bits
         WordAddr : Word;   // Byte address least significant bits
      END_STRUCT;
   END_VAR


BEGIN
	(*
	confronta un numero variabile di bytes in modo indiretto facendo un loop col WHILE
	utilizza la funzione AT che permette l'accesso all'area precedente con il formato dell'area successiva:
	nel primo richiamo si accede all'area pIN1 dichiarata come ANY con il formato pAnyIN1 che è una struttura formattata con 
	i parametri ANY
	
	
	I puntatori ANY formattati hanno la struttura del puntatore ANY di 10 byte.
	Questo è sovrapposto alla variabile pointer ANY usando il comando AT.
	Ciò consente di utilizzare un puntatore ANY ed estrarre i singoli elementi di dati del tipo di puntatore ANY. 
	È vero anche il contrario; è quindi possibile modificare i singoli elementi di dati del tipo di puntatore ANY e quindi utilizzare il puntatore ANY risultante.
	
	L'indirizzo utilizzato nel tipo di puntatore ANY è codificato a bit e byte. Vale a dire accedere alla memoria byte per byte, 
	devi rendere l'indirizzo un multiplo di 8. L'accesso ai byte è obbligatorio altrimenti il BLKMOV non funziona
	a meno che tu non stia spostando byte completi. Si noterà che l'indirizzo è composto da 32 bit (2 parole), 
	ma in realtà vengono usati solo 19 bit (i primi 13 bit sono sempre zeri). 
	Quindi l'indirizzo massimo a cui è possibile accedere è 2 ^ 21 bit = 2097152 bit o 2 ^ 18 byte (2097152/8) = 262144 byte. 
	Per calcolare l'indirizzo per un byte definito, dovremmo prendere l'indirizzo di byte e il bit spostarlo a destra 
	di 3 per convertirlo in un indirizzo bit, quindi creare le parole da inserire nella posizione dell'indirizzo del puntatore ANY. 
	Questo sarebbe un lavoro arduo perché significherebbe spostare i bit shiftati da una parola e copiarli alla successiva. 
	La soluzione quindi è di creare un'altra struttura sovrapposta (u1) che si sovrapponga a 24 bit (un byte e una parola) 
	su una variabile DINT (u1addr), quindi il lavoro è già fatto. 
	
	La prima cosa è caricare la variabile u1addr con l'indirizzo di base (start) dell'indirizzo di input in questo modo: -
	u1.ByteAddrMSB: = pAnyIN1.ByteAddressMSB;
	u1.WordAddr: = pAnyIN1.ByteAddressLSB;
	u1addr sarà uguale all'indirizzo di base (avvio) mappata bit a bit.
	Esegue anche gli indirizzi finali semplicemente utilizzando i dati forniti dal valore della lunghezza del puntatore 
	ANY pAnyIN1.Length (prima di cambiarlo). Quando puntato su un DB, questo verrà impostato sulla dimensione del DB in byte 
	(viene fatto in automatico). Quindi semplicemente moltiplicare questo valore per 8 per convertirlo in indirizzo bit a bit 
	e quindi aggiungerlo all'indirizzo di base (avvio) calcolato sopra
	
	Ora tutto quello da fare è incrementare la variabile u1addr byte a byte (in multipli di 8) e poi si otengono i valori di 
	indirizzo disponibili in u1.ByteAddrMSB e u1.WordAddr da caricare nel parametro ANY uguale alla struttura dell'indirizzo puntatore 
	(rispettivamente  pAnyIN1.ByteAddressMSB e pAnyIN1.ByteAddressLSB) per impostare il puntatore ANY per accedere al nuovo indirizzo.
	Quindi la linea:
	pIN1: = IN1;
	Carica l'input del puntatore di memoria (nel tuo caso un indirizzo DB) nel pointer ANY pIN1, 
	che può essere un accesso / manipolato dal puntatore ANY mappato pAnyIN1.
	
	Il ciclo termina quando l'intervallo di input di origine o di destinazione coincidono (consentendo di confrontare 
	i DB di dimensioni o sottotipi diversi all'interno di altri tipi). Se non si desidera eseguire questa operazione e si desidera 
	confrontare solo tipi identici, è possibile aggiungere un controllo per verificare se le due dimensioni non sono uguali, 
	quindi restituire false immediatamente prima di avviare il ciclo. Così:
	IF (IN1End - u1addr) <> (IN2End - u2addr) THEN
	MEMCMP: = FALSE;
	RETURN;
	END_IF;
	
	*)
	
	
	
	
	#pIN1 := #IN1;                                  // appoggia il puntatore
	#pAnyIN1.DataType := 16#02;                     // forza il formato dei byte
	#u1.ByteAddrMSB := #pAnyIN1.ByteAddressMSB;     // aggiorna i puntatori
	#u1.WordAddr := #pAnyIN1.ByteAddressLSB;
	#IN1End := #u1Addr + (#pAnyIN1.Length * 8);     // aggiorna la fine shiftata dei 3 bit del puntatore 
	#pAnyIN1.Length := 1;                           // confronta solamente un byte alla volta
	
	#pIN2 := #IN2;                                  // idem per area di confronto
	#pAnyIN2.DataType := 16#02;
	#u2.ByteAddrMSB := #pAnyIN2.ByteAddressMSB;
	#u2.WordAddr := #pAnyIN2.ByteAddressLSB;
	#IN2End := #u2Addr + (#pAnyIN2.Length * 8);
	#pAnyIN2.Length := 1;
	
	
	WHILE (#u1Addr < #IN1End) AND (#u2Addr < #IN2End) DO    // confronto fino alla fine dei bytes
	    #RetVal := BLKMOV(SRCBLK := #pIN1, DSTBLK => #Tst1);// legge i byte dal primo all'ultimo 
	    IF #RetVal <> 0 THEN
	        #MEMCMP := FALSE;                       // errore di lettura, valore di ritorno a zero
	        RETURN;
	    END_IF;
	    #RetVal := BLKMOV(SRCBLK := #pIN2, DSTBLK => #Tst2);
	    IF #RetVal <> 0 THEN
	        #MEMCMP := FALSE;                       // errore di lettura, valore di ritorno a zero
	        RETURN;
	    END_IF;
	    IF #Tst1 <> #Tst2 THEN
	        #MEMCMP := FALSE;                       // differenza di byte, valore di ritorno a zero
	        RETURN;
	    END_IF;
	    #u1Addr := #u1Addr + 8;                     // incremento dei puntatori
	    #pAnyIN1.ByteAddressMSB := #u1.ByteAddrMSB;
	    #pAnyIN1.ByteAddressLSB := #u1.WordAddr;
	    #u2Addr := #u2Addr + 8;
	    #pAnyIN2.ByteAddressMSB := #u2.ByteAddrMSB;
	    #pAnyIN2.ByteAddressLSB := #u2.WordAddr;
	    
	END_WHILE;
	
	#MEMCMP := TRUE;
	
	
	
	
	
END_FUNCTION

tutto questo l'ho fatto per puro esercizio, alla fine non mi è mai servito, chissà mai se serve a qualcuno di voi......
Certo ci sarà il modo di farlo anche più semplice. E se le critiche sono costruttive, benvengano.

 

Link al commento
Condividi su altri siti

15 ore fa, stefano_PLC ha scritto:

Ti ringrazio ma non ci capisco nulla di quello che dovrebbe fare sto codice, e più che PLC mi sembra molto c#.

😁😁😁 SCL e lo puoi inserire nel tuo 1200 (non uso il 1200 ma se non erro non dovrebbero esserci problemi).

Quanto a capire il codice, non fosse che metto commenti su commenti non ci capirei più nulla pure io. 😁

Modificato: da pigroplc
Link al commento
Condividi su altri siti

Buongiorno,

ti sconsiglio di legare l'uscita del cicalino ad una memoria gestita con set/reset, ma di gestirla tramite bobina.

Se vuoi che dopo un certo tempo debba smettere (perchè è fastidioso...) inserisci al limite un temporizzatore.

Se l'avaria non è stata risolta, dopo alcuni minuti puoi farla tornate a bippare.

 

Ad esempio:

- Attiva per 5 sec

- Pausa 5 minuti

- Attiva per 5 sec

...

Puoi farlo anche in ladder con gli opportuni temporizzatori

 

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