Cesare Nicola Inserito: 28 agosto 2019 Segnala Share Inserito: 28 agosto 2019 Qualcuno mi può spiegare con un esempio pratico (a parole, non intendo un software di esempio) quando e perché utilizzare l'istruzione AT, che non conosco? Quali vantaggi ha? Grazie Link al commento Condividi su altri siti More sharing options...
toni_unitn Inserita: 28 agosto 2019 Segnala Share Inserita: 28 agosto 2019 io la trovo utile in SCL se hai una variabile "var1" dichiarata DWORD e una variabile var2 definita "Array [0..31] AT Var1" puoi fare var2[5] per accedere al bit 5 di var1. Link al commento Condividi su altri siti More sharing options...
pigroplc Inserita: 28 agosto 2019 Segnala Share Inserita: 28 agosto 2019 (modificato) Ciao Nicola, è un po' che non ci sentiamo, a livello pratico serve a spacchettare una area di ingresso definita come puntatore. Un esempio pratico è il codice di BitCounter qui sotto riportato. T fai la sorgente SCL e te la importi in TIA. Il codice è a disposizione di tutti, ciò che chiedo è di non rimuovere il nome dell'autore. FUNCTION "BitCounter" : Byte { S7_Optimized_Access := 'FALSE' } AUTHOR : pigroplc VERSION : 0.1 VAR_INPUT IN : Any; END_VAR VAR_OUTPUT i32BitCounter : DInt; END_VAR VAR_TEMP RetVal : Int; Tst : Byte; INEnd : DInt; // End addresses for memory areas pIN : Any; // DB address ANY pointer - used for accessing DB data pAnyIN AT pIN : 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; END_VAR BEGIN (* conta i bit che sono = 1 in un'area dichiarata come parametro di ingresso e restituisce un byte di errore in caso di parametro in ingresso errato la sintassi del richiamo è nel seguente esempio: "byteError":= "BitCounter"(IN:=P#DB235.DBX50.0 BYTE 30, i32BitCounter=>"ConteggioBit"); dove "byteError" è il byte di errore se diverso da zero = errore "ConteggioBit" numero di bit = 1 P#DB235.DBX50.0 BYTE 30 = controlla la DB235 dal byte 50 compreso per 30 bytes *) #i32BitCounter := 0; // azzera il contabit in default #pIN := #IN; // copia nell'area interna IF #pAnyIN.DBNumber = 0 THEN #BitCounter := 1; // errore di parametro numero di DB RETURN; END_IF; IF #pAnyIN.MemoryArea <> 16#84 THEN #BitCounter := 2; // errore di parametro di DB RETURN; END_IF; #u1.ByteAddrMSB := #pAnyIN.ByteAddressMSB; // aggiorna i puntatori #u1.WordAddr := #pAnyIN.ByteAddressLSB; #INEnd := #u1Addr + (#pAnyIN.Length * 8); // aggiorna la fine shiftata dei 3 bit del puntatore #pAnyIN.Length := 1; // confronta solamente un byte alla volta // adesso legge 1 byte alla volta indicizzato dinamicamente e controlla come prima cosa che non ci siano errori // quindi confronta il byte con zero WHILE (#u1Addr < #INEnd) DO // confronto fino alla fine dei bytes #RetVal := BLKMOV(SRCBLK := #pIN, DSTBLK => #Tst);// legge i byte dal primo all'ultimo IF #RetVal <> 0 THEN #BitCounter := 3; // errore di lettura, valore di ritorno a zero #i32BitCounter := 0; // azzera il numero di bit perché non valido RETURN; END_IF; IF #Tst <> 0 THEN #Tst := SHR(IN:=#Tst, N:=1); // controlla se il byte non è zero lo shifta e incrementa il contatore #i32BitCounter := #i32BitCounter + 1; END_IF; #u1Addr := #u1Addr + 8; // incremento dei puntatori #pAnyIN.ByteAddressMSB := #u1.ByteAddrMSB; #pAnyIN.ByteAddressLSB := #u1.WordAddr; END_WHILE; #BitCounter := 0; // NO errore di parametro DB END_FUNCTION Un'altro esempio di utilizzo potrebbe essere la gestione di bit diversamente posizionati in una word o byte. A tal proposito guarda il prossimo blocco che ho fatto tempo addietro per capirne il funzionamento. Non l'ho mai utilizzato realmente su un impianto ma mi sono divertito a farlo...... FUNCTION "SpecchiareBit" : Void { S7_Optimized_Access := 'FALSE' } AUTHOR : pigroplc VERSION : 0.1 VAR_INPUT MyByteInput : Byte; END_VAR VAR_OUTPUT MyByteOutput : Byte; END_VAR VAR_TEMP MyByteInput_interno : Byte; ProvareInput AT MyByteInput_interno : Array[0..7] of Bool; MyByteOutput_interno : Byte; ProvareOutput AT MyByteOutput_interno : Array[0..7] of Bool; END_VAR BEGIN (* Esempio per capire come funziona la sovrapposizione variabili con AT Nell'esempio viene specchiato il byte di ingresso nel byte di uscita attribuendo i bit uno a uno La funzione AT è possibile nella FC solamente se non è flaggato l'accesso ottimizzato al blocco *) (* copiare il byte in parametro interno perché altrimenti non funziona AT negli ingressi *) #MyByteInput_interno := #MyByteInput; (* specchia i bit uno a uno. Notare che i bit "ProvareInput[x]" NON sono stati modificati direttamente ma sono modificati mediante i bit dell'array sovrapposto *) #ProvareOutput[0] := #ProvareInput[7]; #ProvareOutput[1] := #ProvareInput[6]; #ProvareOutput[2] := #ProvareInput[5]; #ProvareOutput[3] := #ProvareInput[4]; #ProvareOutput[4] := #ProvareInput[3]; #ProvareOutput[5] := #ProvareInput[2]; #ProvareOutput[6] := #ProvareInput[1]; #ProvareOutput[7] := #ProvareInput[0]; (* copiare il byte interno nel parametro di uscita. Notare che il parametro "MyByteOutput_interno" NON è stato modificato direttamente ma è stato modificato mediante i bit dell'array sovrapposto *) #MyByteOutput := #MyByteOutput_interno; END_FUNCTION Modificato: 28 agosto 2019 da pigroplc Link al commento Condividi su altri siti More sharing options...
Cesare Nicola Inserita: 29 agosto 2019 Autore Segnala Share Inserita: 29 agosto 2019 OK, grazie toni_unitn e grazie pigro, tengo presente e vediamo se nel progetto che dovrò affrontare salterà fuori l'occasione di utilizzarla. 22 ore fa, pigroplc scrisse: è un po' che non ci sentiamo, E' vero. Ti faccio il riassunto delle attività a cui mi sono dedicato dall'ultima volta che ci siamo sentiti: lavoro bambini Immagino non si discostino molto dalle tue. 😂😂😂😂😂 Link al commento Condividi su altri siti More sharing options...
pigroplc Inserita: 29 agosto 2019 Segnala Share Inserita: 29 agosto 2019 56 minuti fa, Cesare Nicola scrisse: vediamo se nel progetto che dovrò affrontare salterà fuori l'occasione di utilizzarla. Io con il contabit faccio lampeggiare la torretta degli allarmi attivi, in precedenza utilizzavo il codice di Batta fatto a suo tempo con lo Step7. Per un altro cliente ho gestito facilmente la funzione che accende la sirena al comparire di un allarme non tacitato. In sé la funzione è banale, ho una doppia bitmap, una di allarmi attivi e l'altra di allarmi tacitati. Confronto byte a byte e se almeno uno è differente accendo la sirena. Col fronte di salita della tacitazione faccio l'OR delle aree quindi al ciclo macchina successivo saranno uguali. Per default invece faccio l'AND qui se un allarme scompare, scompare per entrambe le aree. 1 ora fa, Cesare Nicola scrisse: Ti faccio il riassunto delle attività idem, a parte che i miei sono meno "bambini" dei tuoi ..... Link al commento Condividi su altri siti More sharing options...
Cesare Nicola Inserita: 29 agosto 2019 Autore Segnala Share Inserita: 29 agosto 2019 7 minuti fa, pigroplc scrisse: Io con il contabit faccio lampeggiare la torretta degli allarmi attivi Io il contabit lo faccio così (il codice è in ST di Mitsubishi, non trovo in questo momento quello in SCL). Il codice va messo in una funzione da richiamare dove serve (FUN per Mitsubishi, FC per Siemens) (* DESCRIZIONE Questa funzione fornisce come valore di ritorno il numero di allarmi attivi. Gli allarmi a bit devono essere scritti in un array che viene passato come parametro di ingresso alla funzione. E' possibile definire quanti allarmi controllare. Ad esempio, se il parametro IN_primo è impostato a 10 ed il parametro IN_ultimo a 30, vengono controllati solo gli allarmi da 10 a 30. ULTIMA MODIFICA *) FUN_conteggio_allarmi := 0; FOR _i := IN_primo TO IN_ultimo DO FUN_conteggio_allarmi := BOOL_TO_INT(IN_array[_i]) + FUN_conteggio_allarmi; END_FOR; Queste sono le variabili in gioco: Link al commento Condividi su altri siti More sharing options...
leleviola Inserita: 29 agosto 2019 Segnala Share Inserita: 29 agosto 2019 per verificare gli allarmi attivi o meglio per verificare che non ci siano nuovi allarmi e quindi attivare la segnalazione a torretta io faccio un caricamento in dei registri dedicati dei bit allarmi attivi al momento del reset generale allarmi o acquisizione allarmi, poi faccio sempre in continuo un EXOR tra bit allarmi attuali e il registro in cui ho caricato al momento del reset, se dal risultato dell EXOR risulta un bit o più bit attivi (cioè diverso da 0) è il segnale che è arrivato un nuovo allarme da quando ho fatto l'ultimo e reset e perciò faccio attivare la segnalazione di presenza nuovo allarme. Più difficile a spiegarsi che a farsi Link al commento Condividi su altri siti More sharing options...
pigroplc Inserita: 29 agosto 2019 Segnala Share Inserita: 29 agosto 2019 3 ore fa, Cesare Nicola scrisse: (il codice è in ST di Mitsubishi oramai hai gli occhi a mandorla, una volta eri fan della famosa marca tedesca ... ah ah ah Link al commento Condividi su altri siti More sharing options...
Cesare Nicola Inserita: 29 agosto 2019 Autore Segnala Share Inserita: 29 agosto 2019 (modificato) 1 ora fa, pigroplc scrisse: oramai hai gli occhi a mandorla, una volta eri fan della famosa marca tedesca ... ah ah ah E' solo opportunismo, che poi è il vero sport nazionale! Prima ero milanista, ma da quando il figlio si dichiara juventino, lo sono un po' anch'io! 😂😂😂 Comunque inizierò oggi un progetto con tutto Siemens; ogni tanto c'è bisogno di trovare una amante, ma poi si torna sempre dalla moglie. 😉 Modificato: 29 agosto 2019 da Cesare Nicola Link al commento Condividi su altri siti More sharing options...
walterword Inserita: 19 settembre 2019 Segnala Share Inserita: 19 settembre 2019 un milanista che diventa juventino o peggio ancora interista è da ammazzare Link al commento Condividi su altri siti More sharing options...
Cesare Nicola Inserita: 20 settembre 2019 Autore Segnala Share Inserita: 20 settembre 2019 21 ore fa, walterword scrisse: un milanista che diventa juventino o peggio ancora interista è da ammazzare Ho detto "un po' juventino" 😀 Guarda, in realtà, l'essere poco tifoso come me è una situazione privilegiata, che ha solo vantaggi: ti guardi le partite, quella che vuoi, godendoti lo spettacolo e senza che ti vengano acidità di stomaco. Da provare, fidati! 🙂 😂😂🤣 Fine dell'off-topic, mi scuso. Link al commento Condividi su altri siti More sharing options...
Messaggi consigliati
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 accountAccedi
Hai già un account? Accedi qui.
Accedi ora