Zob Inserito: 5 febbraio 2016 Segnala Inserito: 5 febbraio 2016 Ciao a tutti, sto buttando giù qualche idea per realizzare in SCL una ricerca all'interno di una DB di una stringa (nome utente) passata da pannello. Documentandomi un poì in rete ho appreso come la cosa "migliore" sia affrontare il problema tramite puntatori ANY e BLKMOV (SFC20). Sequenzialmente le operazioni da fare sarebbero: login da hmi in cui salvo il nome utente inserito: salvataggio della stringa inserita da pannello, fin qui nessun problema. Questra stringa sarà poi passata come parametro alla FB. ricerca del nome utente all'interno della DB con tutti i nomi utente: creo due puntatori ANY a cui accedo tramite AT, in modo da poterli parametrizzare facilmente a mio piacimento. primo passo) Leggo i-esimo nome utente dalla DB utenti e lo sposto in una locazione di memoria fissata (in modo da usare sempre la stessa stringa per il confronto al passo successivo) tramite BLKMOV. secondo passo) Effettuo il confronto tra la stringa in ingresso alla funzione e quella appena spostata. trovato il nome caricare i dati macchina per tale utente per visualizzarli a pannello in una determinata pagina: se il confronto da buon esito riparametrizzo gli stessi puntatori che utilizzo poi per spostare i dati utente dalla propria db verso quella visibile da pannello operatore. Se il confronto non da buon esito continuo la ricerca all'interno della DB utenti. Evidentemente qualcosa mi sfugge in quanto la FB itera correttamente ma non sposta mai la stringa al primo passo), di conseguenza il confronto non da mai buon esito. Lascio in allegato ciò che ho prodotto. Qualche idea a riguardo sui possibili errori e/o soluzioni alternative? (********************CODICE***********************) FUNCTION_BLOCK FB150 VAR_TEMP // Variabili temporanee j,i,k:INT; //credo una struttura per accedere ai puntatori in maniera più semplice pAnySource: ANY; pSource AT pAnySource: STRUCT S7Code:BYTE; //codice fisso a 16#10 DataType:BYTE; //codice per il tipo di dato da indirizzare //16#01=BOOL, 16#02=BYTE, 16#03=CHAR, 16#04=WORD, 16#05=INT, //16#06=DWORD, 16#07=DINT, 16#08=REAL, 16#09=DATE, 16#0A=TOD, //16#0B=TIME, 16#0C=S5TIME, 16#0E=DT, 16#13=STRING Lenght:INT; //fattore di ripetizione DBNumber:INT; // numero della db MemoryArea:BYTE; //codice area da puntare //16#81=Input area (I), 16#82=Output area (O), 16#83=Bit memory area (M), //16#84=Shared Data Block (DB), 16#85=Instance Data Block (DI), //16#86=Local data (L stack), 16#87=Previous local data (V) ByteAddressMSB:BYTE; //byte indirizzamento più significativo //da lasciare sempre a zero a meno che non si vogliano indirizzare //db con più di 8192 byte ByteAddressLSB:WORD; //byte indirizzamento meno significativo END_STRUCT; pAnyDest: ANY; pDest AT pAnyDest: STRUCT S7Code:BYTE; DataType:BYTE; Lenght:INT; DBNumber:INT; MemoryArea:BYTE; ByteAddressMSB:BYTE; ByteAddressLSB:WORD; END_STRUCT; END_VAR VAR tempUser: STRING[12]; indice:INT:=0; UserDB:INT; ScanRange:INT:=0; END_VAR VAR_INPUT CurrentUser:STRING[12]; DB_Base:INT; ActualParametersDB:INT; END_VAR VAR_OUTPUT //utente attualmente loggato (codice numerico) UserLogged:INT:=0; UserLoggedNotInDB:BOOL:=false; END_VAR VAR_IN_OUT NewLogin:BOOL; NewLogout:BOOL; END_VAR //***************OPERAZIONI ESEGUITE SOLO AL LOGIN**************** IF NewLogin=true THEN UserLoggedNotInDB:=false; indice:=0; scanrange:=228; //creo il puntatore iniziale che poi andrò a variare mano a mano pSource.s7code:=16#10; //fisso pSource.DataType:=16#13; //indirizzo stringhe pSource.Lenght:=1; //quante stringhe pSource.DBNumber:=210; //db dove sono salvati gli users pSource.MemoryArea:=16#84;//codice per le db pSource.ByteAddressMSB:=0; pSource.ByteAddressLSB:=0;//parto dal primo bit della db //il puntatore appena creato equivarrebbe a: P#DB210.DBX0.0 STRING 1 //il secondo puntatore lo faccio puntare sempre allo stesso punto, ad //ogni iterazione trasferisco la stringa puntata da pSource nel punto //puntato da pDest pDest.s7code:=16#10; //fisso pDest.DataType:=16#13; pDest.Lenght:=1; pDest.DBNumber:=211; //db dove salvare la stringa (al momento non il db di istanza) pDest.MemoryArea:=16#84;//codice per le db pDest.ByteAddressMSB:=0; pDest.ByteAddressLSB:=0; //il puntatore appena creato equivarrebbe a: P#DB211.DBX0.0 STRING 1 //ricerco l'user inserito all'interno della db degli utenti FOR i:=0 TO 9 BY 1 DO //ricalcolo indice pSource //la db degli user è strutturata: nome user (14byte) + psw user (14byte) //quindi ad ogni iterazione bisogna aggiungere al LSB 228 (28*8 bit) indice:=0 + (i*scanrange); pSource.ByteAddressLSB:= INT_TO_WORD(indice); j:=BLKMOV(srcblk:=pSource, dstblk:=pDest); //confronto tra stringhe //UserScanner.UserScanned = P#db211.dbx0.0 STRING 1 IF CurrentUser=UserScanner.UserScanned THEN UserLogged:=i+1; UserDB:=DB_Base+UserLogged; //carico la db dello user trovato nella db200 //riparametrizzo i puntatori per il trasferimento pSource.s7code:=16#10; //fisso pSource.DataType:=16#02; //indirizzo dei byte pSource.Lenght:=300; //quanti byte pSource.DBNumber:=UserDB; //db utente pSource.MemoryArea:=16#84;//codice per le db pSource.ByteAddressMSB:=0; pSource.ByteAddressLSB:=0; pDest.s7code:=16#10; //fisso pDest.DataType:=16#02; //indirizzo dei byte pDest.Lenght:=300; pDest.DBNumber:=DB_Base; pDest.MemoryArea:=16#84;//codice per le db pDest.ByteAddressMSB:=0; pDest.ByteAddressLSB:=0; k:=BLKMOV(srcblk:=pSource, dstblk:=pDest); i:=10; //esco dal ciclo for quando ho trovato l'utente NewLogin:=false; END_IF; IF i=9 AND NewLogin=true THEN UserLoggedNotInDB:=true; NewLogin:=false; END_IF; END_FOR; END_IF; END_FUNCTION_BLOCK Grazie mille
FabioS.PLC Inserita: 6 febbraio 2016 Segnala Inserita: 6 febbraio 2016 Ciao, credo di aver capito cosa vuoi fare dalla descrizione iniziale che hai fatto, ma poi leggendo il codice non riesco proprio a capire alcune cose: prima dici: Quote #pSource.DBNumber := 210; //db dove sono salvati gli users poi, subito dopo invece trovo: Quote #UserDB := #DB_Base + #UserLogged; .... #pSource.DBNumber := #UserDB; //db utente ovvero prima dici che tutti gli user sono salvati nel DB numero 210 e subito dopo invece sembra che ogni user abbia un suo DB. inoltre potresti spiegare cosa c'è nel DB "UserScanner" e perchè lo usi? Grazie, Ciao Fabio
walterword Inserita: 6 febbraio 2016 Segnala Inserita: 6 febbraio 2016 generalmente in SCL , non si può usare una stringa per confrontarla direttamente con un'altra.Il problema si risolve utilizzando una variabile locale di appoggio per memorizzare la stringa .Meglio se la variabile d'appoggio intermedia si trova in un DB globale in quanto lo stack limitato dei una funzione potrebbe creare problemi non indifferenti
FabioS.PLC Inserita: 7 febbraio 2016 Segnala Inserita: 7 febbraio 2016 Quote generalmente in SCL , non si può usare una stringa per confrontarla direttamente con un'altra.Il problema si risolve utilizzando una variabile locale di appoggio per memorizzare la stringa .Meglio se la variabile d'appoggio intermedia si trova in un DB globale in quanto lo stack limitato dei una funzione potrebbe creare problemi non indifferenti Ciao, si quello l'avevo capito, ed è il motivo per cui utilizza il DB 211. Per quanto riguarda UserScanner ho visto dopo che sarebbe il db211: Quote //UserScanner.UserScanned = P#db211.dbx0.0 STRING 1 La mia domanda principale era però un'altra, ovvero ogni user ha il suo DB? come fa pensare la seguente: Quote #UserDB := #DB_Base + #UserLogged; .... #pSource.DBNumber := #UserDB; //db utente oppure c'è un DB dove sono presenti tutti gli user? Quote #pSource.DBNumber := 210; //db dove sono salvati gli users inoltre potresti spiegare cosa è DB_base? Nella dichiarazione delle variabili non è presente alcuna descrizione, quindi diventa abbastanza difficile capire.
Zob Inserita: 8 febbraio 2016 Autore Segnala Inserita: 8 febbraio 2016 Ciao, allora seguo con una descrizione un po' più dettagliata delle DB in gioco (scusatemi se non l'ho fatto prima): DB 210 DB Users: è la db dove sono presenti tutte le associazioni utente+psw. E' la db che scandisco per vedere se l'utente inserito a pannello è presente tra quelli salvati in questa db. DB 211 DB_Scanner: è la db che utilizzo come appoggio, ogni elemento che scandisco dalla db 210 lo colloco qua e dopodichè faccio il confronto con il nome utente inserito da pannello. DB 200 DB Base: è la db che utilizzo per far vedere a pannello i dati macchina dell'utente attualmente loggato. Praticamente, a seguito dell'esito della ricerca eseguita sulla DB 210, in questa db vengono caricati i dati di una delle db DB 201--> DB 209. Queste ultime sono appunto le db che contengono i dati macchina aggiornati all'ultima sessione di lavoro dell'utente in questione. Spero di essere stato un po' più chiaro!
walterword Inserita: 8 febbraio 2016 Segnala Inserita: 8 febbraio 2016 io non ho mai usato e mai userò le porcherie di librerie inutili e casinose , metto a fuoco il problema e risolvo con la mia testa con funzioni veloci , funzionanti e stabili . Ci metto meno tempo che star li a capire tutte le libro-porcherie di quei dementi di tedeschi che non hanno niente da fare che stare in ufficio a bere caffè e scrivere minkiate inutili.I problemi di stringhe , elaborazioni su di esse, tabelle , strutture , calcoli , ricerche , inserimenti etc , li ho sempre risolti in SCL con DB globali fatti ad hoc .Lo scanner lo utilizzo connesso ad un pc che programmo in C# .Quando mi son capitati scanner da connettere al plc ordinavo il loro convertitore profibus .Alcuni di essi , gli scanner più marcioni , mi davano i dati in due colpi avendo un buffer piccolo per quello che mi interessava , cosi che creavo una piccola macchina a stati dove leggevo in due colpi il buffer sincronizzandomi con i bit messi a disposizione dal dispositivo stesso .In generale devi avere un DB che funge da buffer per la lettura del dispositivo , una funzione che processa i dati e li interpreta , un'area di deposito per i dati elaborati e poi la visualizzazione
Zob Inserita: 9 febbraio 2016 Autore Segnala Inserita: 9 febbraio 2016 Ciao, certo si che creando db globali ad hoc il problema si risolve in quattro e quattr'otto, la mia intenzione era di voler creare un qualcosa di riutilizzabile il più possibile e per tale motivo stavo provando una soluzione tramite puntatori any (di cui tutti "sponsorizzano" l'uso in scl per effettuare un'operazione del genere...ma poi nel dettaglio in pochi ti sanno aiutare veramente) Comunque non devo utilizzare nessuno scanner, il nome "DB Scanner" è solamente per identificare la db in cui metto ad ogni iterazione la stringa letta dalla db210
batta Inserita: 9 febbraio 2016 Segnala Inserita: 9 febbraio 2016 Quote certo si che creando db globali ad hoc il problema si risolve in quattro e quattr'otto, la mia intenzione era di voler creare un qualcosa di riutilizzabile il più possibile e per tale motivo stavo provando una soluzione tramite puntatori any Non credo che una strutturazione dei dati orientata all'utilizzo in SCL renda difficile un eventuale riutilizzo, anzi. Relativamente al problema, sinceramente non ho analizzato il codice, ma l'uso dei puntatori ANY mi pare solo una complicazione. Piuttosto, se proprio vuoi lavorare con i puntatori, vedi le istruzioni PEEK e POKE. Però non ne vedo il motivo. Creando array e strutture ad hoc risolvi tutto senza complicarti la vita.
walterword Inserita: 9 febbraio 2016 Segnala Inserita: 9 febbraio 2016 lavori con un DB globale e lo passi come IN/OUT alla tua funzione ....con il P# che non e' altro che "&" del C . Implicitamente una struttura piu o meno complessa passata come IN/OUT è un puntatore ad essa
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