Vai al contenuto
PLC Forum


Puntatori S7 300 , Non Funzionano


coquinati

Messaggi consigliati

:toobad::toobad: ho la massima necessita di imparare ad usare i puntatori con grande dimestichezza, avevo gia una infarinatura ( li usavo in maniera un pò banale) , ho deciso di riprendere in mano la situazione da zero per cercare di formarmi in maniera piu corretta possibile , mi sono imbattuto su un esrcizio di Federico Milan su puntatori a 32bit. che consiste che su un blocco dati di 10 variabili di tipo byte me ne analizza una per una, e mi crea la media di 2 varibili per volta e il risultato lo inserisce nella prima , ecco il programmino :

L 10 // numero di loop max
next: T #CONT_LOOP
L 10
ITD
-D
L 8
*D //CALCOLO L'INDRIZZO BIT DA PUNTARE(costante 1)
T #PUNT
L 8
+D
T #PUNT_1 //CALCOLO IL SECONDO INDRIZZO BIT DA PUNTARE (+8)(costante2)

AUF DB 2

L DBB [#PUNT] //punto il primo
L DBB [#PUNT_1] // punto il secondo
+I //sommo le 2 costanti
L 2
/I //divido per 2
T DBB [#PUNT] //trasferisco il risultato nella prima costante

L #CONT_LOOP
LOOP next

la cpu mi entra in stop, subito mi da un errore ( da buffer di diagnistica) ERRORE LUNGHEZZA DI CAMPO DI LETTURA, copio il link della guida dell'evento :

Cause:

· Il valore indirizzato dall'indirizzo di accesso è escluso, completamente o in parte, dal campo di operandi ammissibile (grandezza specifica della CPU).

· A causa di un errore di calcolo dell'indirizzo, il valore indirizzato è > 65535. In caso di indirizzamento indiretto può risultare, con un calcolo errato, un valore maggiore di 65535. Questo valore non può più essere registrato correttamente nell'informazione dettagliata dell'evento. Come indirizzo di accesso verranno così registrati e visualizzati il valore 0 per la S7-300 e per la S7-400 il valore calcolato modulo 65535

Rimedio:

· Scegliere l'indirizzo di accesso in modo tale che il valore indirizzato sia compreso interamente nel corrispondente campo di operandi ammissibile.

· Controllare il programma utente


leggendo questo errore da quanto dice step 7 il mio puntatore ha un indirizzo troppo grande...ma sicuramente l'ho inteso male.....il vostro . è ben accetto,, grazie in anticipo , e buonanotte

Link al commento
Condividi su altri siti


Ciao.

Dunque, ragionandoci un attimo si vede che carichi 10 in ACC1 e lo trasferisci in #CONT_LOOP,

poi carichi di nuovo 10 in ACC1 di conseguenza il vecchio valore di ACC1 va in ACC2, che è 10,

dopo trasformi il valore 10 in ACC1 da intero a doppio intero, poi sottrai il valore di ACC1 dal Valore di ACC2,

qui ovviamente il tuo risultato sarà sempre 0, 10-10=0

Quindi alla fine avrai sempre 0 su #PUNT e 8 su #PUNT1

Alla fine fine l'istruzione LOOP non l'ho mai usata su S7, quindi non so se è corretto.

Per evitare che la CPU ti vada in Stop, carica l'OB121, così puoi vedere il tuo ciclo girare e capire meglio cosa succede

e trovare il problema.

P.S. Certo che a quell'ora della notte non deve essere facile ragionare sui puntatori... :P :P :P

Modificato: da beppo
Link al commento
Condividi su altri siti

qui ovviamente il tuo risultato sarà sempre 0, 10-10=0

in teoria non è cosi , perchè l'istruzione loop conta nel mio caso da 10 a 1 e il numero del loop lo tiene sempre presente attraverso la variabile #CONT_LOOP.esempio da quello che ho capito:

10-10=0 punto alla variabile 0 del mio blocco dati

10-9=1 punto alla variabile 8(sempre inteso in bit)

e cosi via..

poi arriva a l'ultimo loop che farà

10-1 =9 punta alla varibile bit 72.0

poi chiaramente prima di saltare decrementa il loop vede 0 e non salta più.

Per evitare che la CPU ti vada in Stop, carica l'OB121, così puoi vedere il tuo ciclo girare e capire meglio cosa succede

e trovare il problema.

provato , e vedo che mi punta la variabile 0.0 e 1.0 ma si blocca... sembra che non riesce puntarmi...strano perchè non vedo niente di errato nella sequenza.

P.S. Certo che a quell'ora della notte non deve essere facile ragionare sui puntatori... :P :P :P

lo so :thumb_yello: purtoppo io parto nel studiare calcolando il tempo che mi serve senza nessun imprevisto. e dopo va finire che sono costretto a stare li ore per cercare di capire un problema,,e non ho ancora concluso nulla :toobad:

impara SCL , i puntatori non servono a nula quando si ha un linguaggio chiaro e semplice come SCL o ST

si walter proprio ieri ho visto esempi di puntatori su questo linguaggio , e devo dire che sembrava quasi banale usarli, però non tutti i programmatori lo usano :( , come nel mio caso se mi capita un programma da analizzare in AWL non mi resta che studiare,

Link al commento
Condividi su altri siti

fai prima a rifare l aparte di codice in SCL , l'importante e' sapere cosa devi fare piuttosto che come funzionano i puntatori ,

Link al commento
Condividi su altri siti

A mio avviso c'è qualcosa che non va in quell'esempio. Tieni presente chenio contatore loop viene decrementato dalla cpu da 10 fino a 0, le prime istruzioni sottraggono 10 a questo contatore, quindi il primo giro lo fa correttamente perché 10-10=0 quindi viene effettuata la media tra il byte 0 e il byte 1, ma il secondo giro il contatore loop è a 9, sottraendo 10 farebbe -1 che il sistema interpreta come 65535 intero unsigned. Quando prova a caricare il byte 65535 va in stop.

Link al commento
Condividi su altri siti

Il programma corretto è:

      L     10                          // numero di loop max
next: T     #CONT_LOOP
      L     L#10
      L     #CONT_LOOP
      -D    
      L     8
      *D                                //CALCOLO L'INDRIZZO BIT DA PUNTARE(costante 1)
      T     #PUNT
      L     8
      +D    
      T     #PUNT_1                     //CALCOLO IL SECONDO INDRIZZO BIT DA PUNTARE (+8)(costante2)

      AUF   DB     2

      L     DBB [#PUNT]                 //punto il primo
      L     DBB [#PUNT_1]               // punto il secondo
      +I                                //sommo le 2 costanti
      L     2
      /I                                //divido per 2
      T     DBB [#PUNT]                 //trasferisco il risultato nella prima costante

      L     #CONT_LOOP
      LOOP  next

Link al commento
Condividi su altri siti

C'è anche un altro modo di usare i puntatori:

      AUF   DB     2
      L     P#DBX 0.0                   // Prepara AR1 per puntare al primo byte
      LAR1  

      L     10                          // numero di loop max
next: T     #CONT_LOOP
      L     DBB [AR1,P#0.0]             // Leggo primo byte
      L     DBB [AR1,P#1.0]             // leggo secondo byte
      +I                                // sommo le 2 costanti
      L     2
      /I                                // divido per 2
      T     DBB [AR1,P#0.0]             // trasferisco il risultato nel primo byte

      +AR1  P#1.0

      L     #CONT_LOOP
      LOOP  next

Questo fa esattamente la stessa cosa, per me è molto più chiaro...

Posso anche modificrlo rapidamente per lavorare con word anzichè bytes:

      AUF   DB     2
      L     P#DBX 0.0                   // Prepara AR1 per puntare al primo word
      LAR1  

      L     10                          // numero di loop max
next: T     #CONT_LOOP
      L     DBW [AR1,P#0.0]             // Leggo primo word
      L     DBW [AR1,P#2.0]             // leggo secondo word
      +I                                // sommo le 2 costanti
      L     2
      /I                                // divido per 2
      T     DBW [AR1,P#0.0]             // trasferisco il risultato nel primo word

      +AR1  P#2.0

      L     #CONT_LOOP
      LOOP  next
Modificato: da JumpMan
Link al commento
Condividi su altri siti

... posso scrivere i risultati in un altra DB (DB3) lasciando inalterati i valori in DB2:

      AUF   DB     2
      AUF   DI     3

      L     P#DBX 0.0                   // Prepara AR1 per puntare al primo word
      LAR1  

      L     10                          // numero di loop max
next: T     #CONT_LOOP
      L     DBW [AR1,P#0.0]             // Leggo primo word
      L     DBW [AR1,P#2.0]             // leggo secondo word
      +I                                // sommo le 2 costanti
      L     2
      /I                                // divido per 2
      T     DIW [AR1,P#0.0]             // trasferisco il risultato nel primo word

      +AR1  P#2.0

      L     #CONT_LOOP
      LOOP  next

Modificato: da JumpMan
Link al commento
Condividi su altri siti

in teoria non è cosi , perchè l'istruzione loop conta nel mio caso da 10 a 1 e il numero del loop lo tiene sempre presente attraverso la variabile #CONT_LOOP

Ah ok, sinceramente l'istruzione loop non l'avevo neanche mai vista su Step7 :P

... posso scrivere i risultati in un altra DB (DB3) lasciando inalterati i valori in DB2:

Bello questo codice.

Leggero ma molto funzionale.

Link al commento
Condividi su altri siti

jumpman mi scuso se rispondo ora ma è stato un weekend difficile , solo ora riesco dedicare un po di tempo a step 7, riguardo al primo esempio ho capito, un mio errore nel tenere conto degli accumulatori, ho risolto subito, caricato il programma , ma resta in stop , ora ho visto che arriva a puntare il bit 2.0( piccolo miglioramento), sul db sto utilizzando un array da 1 a 10 , ma il problema non dovrebbe essere qua a parere mio, essendo la prima volta che li uso mi sto aspettando di tutto..

ho letto che come io uso i puntatori sarebbe un metodo molto spartano, il metodo più efficace e come hai detto te è nell'esempio 2 , cioè usare i registri del accumulatore che se non sbaglio sono (AR1 e AR2), cosa che mi sono messo subito a studiare ma il sonno ha preso il sopravvento ( sembra un argomento molto difficile) quindi rinvio tutto a domani e vedo se riesco scrivere una sequenza utilizzando questi ultimi come hai fatto te.

grazie

Link al commento
Condividi su altri siti

ciao

ma come non ti funziona, li ho provati tutti prima di postare e funzionano, compreso l'#8

Hai fatto copia-incolla del codice?

AR1 (AR2 non lo usare) non è niente di difficile, è un registro a 32 bit che funziona come i puntatori che usi tu solo che ha delle istruzioni dedicate in più e una costante offset regolabile a piacere (molto utile per spostare il puntatore avanti/indietro senza variarlo).

Link al commento
Condividi su altri siti

rispondo ora perchè mi sono ritirato nel poco tempo libero nei meandri della camera a studiare,e sono riuscito a capire qualcosa forse

L P#DBX 0.0 // Prepara AR1 per puntare al primo word
LAR1

praticamente carichi il valore del pointer di accu 1 nel registro AR1 .

L DBB [AR1,P#0.0] // Leggo primo byte

qua carichi ar1 che è preimpostato ad aprire l'indirizzo in un blocco dati

+AR1 P#2.0

qua sommi due byte, su AR1, quindi poi riprendi da qua:

L DBW [AR1,P#2.0] // Leggo primo word
L DBW [AR1,P#4.0] // leggo secondo word

la cosa che mi manda più in confusione che prima lavoravo in BIT . ora devo usare dei BYTE,

AR1 (AR2 non lo usare) non è niente di difficile, è un registro a 32 bit che funziona come i puntatori che usi tu solo che ha delle istruzioni dedicate

intendi operazioni matematiche ?

una costante offset regolabile a piacere

in questo caso :P#0.0 ?

scusa se ti faccio tutte queste domande , e che voglio essere sicuro, i puntatori mi puntano paura :P

grazie mille per ora, ti ho inviato un MP. grazie ancora e notte a PLC Forum

Link al commento
Condividi su altri siti

Credo che tu abbia capito il mio esempio.

Le istruzioni di AR1 sono LAR1, TAR1 che servono solo per leggere e scrivere il registro (come L e T fanno per ACCU 1)

L'istruzione +AR1 è molto utile perchè permette di incrementare il registro di uno "step" che può essere:

- di un bit (P#0.1) per puntare al bit successivo

- di un byte (P#1.0) per puntare al byte successivo

- di 2 byte (P#2.0) per puntare alla word successiva

- di 4 byte (P#4.0) per puntare alla dword successiva

- di n bytes (P#n.0) per puntare dove si vuole...

Come potrai notare l'istruzione non influenza ACCU 1 e quindi si può usare tranquillamente nei loop senza preoccuparsi di andare a sporcare gli ACCU (e quindi i calcoli in corso)

Non ho capito cosa ancora non ti è chiaro, forse il fatto che i puntatori siemens contengono sia l'indirizzo del byte che quello del bit ?

La parte che va a finire in AR1 sono i bytes 2-3-4-5 nell'immagine qui sotto (è simile anche per gli altri puntatori e questo spiega perchè si usa l'operazione SLD 3 , per far posto ai 3 bit usati per il puntamento a bit)

p.s. ho visto ora il tuo messaggio privato, ti ho risposto

post-2480-0-98607000-1399576996_thumb.jp

Modificato: da JumpMan
Link al commento
Condividi su altri siti

Come potrai notare l'istruzione non influenza ACCU 1 e quindi si può usare tranquillamente nei loop senza preoccuparsi di andare a sporcare gli ACCU (e quindi i calcoli in corso)

infatti, ma obbligatoriamente io dovro specificare attraverso l'accu la mia area di memoria per esempio:

L P#DBX 0.0 // Prepara AR1 per puntare al primo word

LAR1

oppure:

L P#MW 0.0 // Prepara AR1 per puntare al primo byte

LAR1

Non ho capito cosa ancora non ti è chiaro, forse il fatto che i puntatori siemens contengono sia l'indirizzo del byte che quello del bit ?

si , perche io sul mio primo esempio usavo un puntatore specificando solo l'indirizzo in bit, ora devo usare usare i byte.bit , ero convinto che su siemens i puntatori funzionassero solo a bit,per esempio voglio punTare al byte 10, scrivo:

L DBB [#80] //punto

invece se uso quesa istruzione:

L P#DBX 0.0 // Prepara AR1 per puntare al primo word

LAR1

posso fare cosi:

L DBB [AR1,P#10.0]

. guardando la tabella che mi hai allegato è riferita a un formato pointer, che necessita di un indirizzo BITE.BIT , e sono quelli(sempre se ho capito) contrasegnati dalla lettera P# ,quindi la prima istruzione che usavo (L DBB [#80] //punto ) non è un formato pointer, ma un puntataore qualsiasi

La parte che va a finire in AR1 sono i bytes 2-3-4-5 nell'immagine qui sotto (è simile anche per gli altri puntatori e questo spiega perchè si usa l'operazione SLD 3 , per far posto ai 3 bit usati per il puntamento a bit)

sinceramente essendo alle prime armi con i puntatori non ho mai avuto modo di utillizare questa istruzione, praticamente azzera il 5 byte,ma per riuscire a fare cosa?

ma il 3 byte resta inutilizzato?

comunque mi scuso per le mia domande stupide, e che voglio imparare, ti ringrazio per la diponibiltà , ho risposto amche io a mp, grazie e notte!

Link al commento
Condividi su altri siti

L P#DBX 0.0 // Prepara AR1 per puntare al primo word

LAR1

Meglio cosi (non tocchi ACCU1):

LAR1 P#DBX 0.0 // Prepara AR1 per puntare al primo word

L DBB [#80]

Questa è errata, casomai:

L DBB[MD80]

ma solo dopo aver caricato in MD80 una costante pointer, questo si può fare con una costante pointer:

L P#5.0

T MD80 // prepara MD80 per puntare al byte 5

L DBB[MD80] // leggo il byte DBB5

Oppure con delle istruzioni

L 5

SLD 3

T MD80

L DBB[MD80] // leggo il byte DBB5

Lo stesso risultato lo ottieni usando il registro AR1:

LAR1 P#5.0

L DBB[AR1, P#0.0] // leggo il byte DBB5

ma con il vantaggio di leggere e scrivere anche altro variando l'offset:

L DBB[AR1, P#1.0] // leggo il byte DBB6

T DBB[AR1, P#2.0] // scrivo il byte DBB7

sinceramente essendo alle prime armi con i puntatori non ho mai avuto modo di utillizare questa istruzione, praticamente azzera il 5 byte,ma per riuscire a fare cosa?

ma il 3 byte resta inutilizzato?

questo te lo spiego un altra volta, ora devo andare, ciao

Link al commento
Condividi su altri siti

ciao jump man.

devo ammettere che quello di scrivere la media delle due variabili su un altro blocco dati e davvero comoda, molto più chiaro come esercizio.

Questa è errata, casomai:

L DBB[MD80]

noto che anche siemens sugli esempi usa una doppia parola, questo perchè usi un puntatore a 32 bit?

grazie.

Link al commento
Condividi su altri siti

i due registri dei puntatori AR1 e AR2 sono piu veloci in quanto registri vicini al processore.

Puoi usare comunque qualsiasi doppiaword DW che essendo in ram implica qualche cosa in piu in termini di tempo , comunque irrisori per applicazioni plc

L'indirizzo di una variabile contenuto in un puntatore altro non e' che un numero di offset nella memoria la cui dimensione e' memorizzabile in una DW

Modificato: da walterword
Link al commento
Condividi su altri siti

L'indirizzo di una variabile contenuto in un puntatore altro non e' che un numero di offset nella memoria la cui dimensione e' memorizzabile in una DW

ora penso di avere capito , visualizzando la tabella postata da jump man si nota che utilizza 32 bit, per quello DW , o puntatore a 32 bit.

L P#5.0

T MD80 // prepara MD80 per puntare al byte 5

L DBB[MD80] // leggo il byte DBB5

praticamente cosi prepari il puntatore a ricevere indirizzi a bit , giusto?

grazie a walter e jumpman

Link al commento
Condividi su altri siti

praticamente cosi prepari il puntatore a ricevere indirizzi a bit , giusto?

no! il puntatore è sempre byte.bit

Se carica byte o bit o word o dword dipende solo dalle istruzioni successive:

L DBB[MD80]

U M[MD80]

L DBW[MD80]

L DBD[MD80]

Link al commento
Condividi su altri siti

ma quindi hai scelto 5 per puntare solo al byte 5, volendo scrivo L p#1.0 e punto al byte 1.

L 5

SLD 3

facendo cosi passi i 3 bit del indirizzo bit al byte 4 del pointer , cosi punti a Byte 5

grazie ragazzi

Modificato: da coquinati
Link al commento
Condividi su altri siti

  • 1 month later...

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