Vai al contenuto
PLC Forum


Snap7, S7-1200 E Vc++


Messaggi consigliati

Innanzitutto complimenti a Dan64100 per l'ottimo lavoro svolto: sto provando la libreria con il 1200 in Client e devo dire che è veramente notevole.

Sto avendo qualche dubbio e volevo chiedere lumi; la prima domanda è se è meglio utilizzare la classe TS7Client (quindi con "new") oppure direttamente le funzioni corrispondenti con prefisso "Cli_".

La seconda cosa riguarda la lettura/scrittura di variabili da DB; nel DB una word è definita come intero (quindi 2 byte con segno) ed ho provato con diverse funzioni (Cli_DBRead, Cli_ReadArea e Cli_ReadMultiVars), ma ottengo sempre e solo i byte swappati; se li inverto nel codice PC funziona anche quando vado a scrivere; invece, è peggio ancora se cerco di usare una variabile Real, che non riesco proprio a leggere o scrivere correttamente. Dove sto sbagliando ?

L'ultima domanda riguarda il parametro Amount, sia in lettura che scrittura: se definisco una azione su di S7WLDword o S7WLReal, mi aspettavo di dover inserire un Amout di 2 (2 word), ma se lo faccio, la funzione mi segnala "Address out of range".

Grazie e ancora complimenti

Drugo

Link al commento
Condividi su altri siti


Ciao Drugo e grazie per i complimenti ;)

Rispondo in ordine:

1)

Per utilizzare una libreria binaria in qualunque sistema operativo, è necessario scrivere un "wrapper", cioè un pezzo di codice d'interfaccia scritto nello stesso linguaggio del progetto che permette di accedere alle funzioni di libreria seguendo le convenzioni di chiamata.

Tutte le librerie in genere vengono distribuite con vari wrapper, anche prodave, libnodave ecc..

Snap7 fa un passo avanti fornendo dei wrapper ad alto livello, cioè delle classi (nei linguaggi object-oriented ovviamente) che incapsulano le chiamate alle librerie, oltre alla possibilità di lavorare in modo procedurale puro cioè con le funzioni.

Sul sito di Snap7 (http://snap7.sourceforge.net) c'è un capitolo intero dedicato ai wrapper con vari esempi.

L'utilizzo delle classi (TS7Client) o delle funzioni dirette Cli_xxx è solo una tua scelta di comodità, sono due metodi perfettamente equivalenti, nel primo caso la classe memorizza internamente il riferimento all'oggetto client creato, nel secondo caso devi passarlo sempre come primo parametro alle funzioni. In C++ puoi scegliere, in C puoi solo utilizzare le funzioni, in C# puoi solo usare le classi.

2)

Non stai sbagliando nulla, questo comportamento è normale, PC e PLC memorizzano i dati in modo differente, il PC li memorizza Little-Endian mentre il PLC Big-Endian. Il protocollo S7Protocol non è sensibile all'ordine, si preoccupa solo di trasferire blocchi di memoria.

La distinzione interna byte, word, dword influenza solo il formato, con byte trasferisce un ottetto, con word trasferisce due byte e così via, non preoccupandosi di invertirli (anche perché ci sono architetture hardware tipo Motorola che hanno lo stesso ordine Big-Endian).

Snap7 a sua volta non può arbitrariamente scambiare l'ordine perché lavora su blocchi non tipizzati, di cui cioè non conosce la struttura.

Mi spiego meglio, se tu hai una struttura composta da un byte, una word ed un real dici al client di leggere o scrivere 7 byte, lui riceve solo puntatore e dimensione e non ha modo di sapere che deve invertire due bytes a partire dal secondo e 4 a partire del quarto.

Anche informazioni tipo S7WLDword o S7WLword sono abbastanza "deboli" per prendere una decisione.

In conclusione è giusto che tu inverta i byte prima della scrittura o dopo la lettura. Dato che programmi in C++ in snap_sysutils.cpp trovi elle funzioni già pronte che puoi copiare nel tuo codice.

Stavo pensando (dato che ho ricevuto molte richieste) di aggiungere delle funzioni di conversione di formato alla libreria, probabilmente nella prossima release, tempo permettendo...

3)

Per convenzione nella libreria "size" indica la quantità di bytes da trasferire, "amount" la quantità di elementi da trasferire, per cui se lavori con dword in amount scrivi quante dword vuoi che vengano trasferite, quindi amount=1 => 1 dword => 2 bytes.

Spero di esserti stato utile.

Davide

Link al commento
Condividi su altri siti

Ciao Davide.

Ho visto che sul sito di Snap7 c'è il simbolo di Python.

Esiste un wrapper o un esempio di utilizzo di Snap7 in Python ?

bigalex :blink:

Link al commento
Condividi su altri siti

Che dire: sei un mito !!

1)

L'ho immaginato, ma ho preferito chiedere: il C# lo capisco ancora poco (sono un vecchio affezionato al C++), ma appena sono pronto darò un occhio anche ai sorgenti; onestamente sono molto curioso e anche un po' invidioso, se vogliamo dirla tutta.

2)

Non avevo visto quelle funzioni in sys_utils: il problema saranno i REAL, che a volte io utilizzo.

Grazie ancora

Drugo

Link al commento
Condividi su altri siti

@Bigalex

C'è phyton-snap7 un progetto indipendente che trovi qui : https://github.com/gijzelaerr/python-snap7

ci trovi il wrapper e gli esempi.

@drugo66

con SwapWord e SwapDword puoi fare tutto ;) i real e i dint S7 sono a 32 bit e li puoi "castare" tranquillamente su una DWORD (di Windows). Stesso discorso per gli int (16 bit) che puoi castare su una word. Le regole di swap lavorano solo sull'ordine dei bytes ignorando la formattazione del contenuto.

Se hai perplessità, copia SwapDword come SwapReal e sostituisci in tutta la funzione longword con float.

Link al commento
Condividi su altri siti

Sì, adesso funziona tutto, byte, word dword e real.

Ho provato anche le funzioni asincrone, ma non riesco a farle andare: ho chiamato SetAsCallback(), poi eseguo AsMBRead(), ma sembra che la esegua una volta sola (errori non ne ritornano).

Nella funzione callback c'è solo la scrittura del risultato a schermo, mentre effettuo una sola chiamata a AsMBRead(): provando in debug vedo che entra nella funzione di callback una volta sola.

Non capisco cosa ho combinato ...

Grazie ancora

Drugo

Link al commento
Condividi su altri siti

Figurati se lo capisco io senza vedere il codice che hai scritto :lol:

Le funzioni asincrone permettono lanciare il job e rientrano immediatamente, nel frattempo puoi eseguire altre attività. Poi hai necessità di sincronizzarti per capire se il job è completo, in genere nella callback potresti settare un semaforo di sistema da leggere con WaitForSingleObject o più semplicemente una variabile che puoi testare in un loop oppure se hai lanciato molti client con un massiccio trasferimento dati (motivo quasi unico per utilizzare le callback) devi usare un InterlockedIncrement su una variabile.

Ti assicuro che funzionano ;) ma non sono semplicissime e devi avere una buona preparazione sulla programmazione concorrente, inoltre hai scelto anche di usare il metodo più performante ma complicato, io lo utilizzo solo per trasferire contemporaneamente le ricette a 64 PLC su una linea di produzione.

Ti consiglio di prendere pratica con le funzioni base lavorando in modalità semplice come se fosse libnodave, poi magari inizia col modificare qualche demo e soprattutto leggi la documentazione !!!, ci sono anche i diagrammi di flusso che spiegano se, quando e come usare le funzioni asincrone.

Fammi sapere

Link al commento
Condividi su altri siti

Le callbak le ho già usate ma ho preso la classica cantonata; ero stanco e dopo una buona doccia e un pò di riposo, ho visto subito tutto più chiaro.

Adesso è tutto funzionante al meglio.

Ti ringrazio per tutto e rinnovo i complimenti.

Saluti

Drugo

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