En esta nueva entrada sobre direccionamiento indirecto es con la que terminamos el curso. En ella vamos a ver la segunda parte de cómo automatizar y recorrer zonas de memoria para trabajar con ellas de forma indirecta y recursiva. Lo primero que has de hacer es leer el direccionamiento indirecto en Step 7 (I) si no lo has hecho ya.[divider]
Contenido
Registro de direcciones
Como sabes, cuando se carga un valor, hay dos registros, el ACU1 y el ACU2. Pues también existen dos registros de direcciones, el AR1 y el AR2 para usarlos en el direccionamiento indirecto.
La forma de cargar y transferir los valores a los registros son de la siguientes 3 maneras:
- Cargar directamente el puntero en el AR1
- Cargar el puntero y transferirselo al AR1
- Cargar el valor numérico de bits y transferirselo al AR1
Cargar directamente el puntero
Es el más rápido si se sabe qué hay que cargar:
LAR1 P#1.0
Lo que cargará en el AR1 el puntero 1.0
Cargar el puntero y transferirlo al AR1
L P#1.0
LAR1
Al igual que el anterior, cargamos el puntero P#1.0 en el AR1
Cargar el valor numérico de bits y transferirlo al AR1
o, como dijimos en direccionamiento indirecto (I), podemos crear al puntero diciendo cuántos bits tiene la dirección
L 8
LAR1
Hará exactamente lo mismo que los casos anteriores. Hay que puntualizar que si queremos acceder a una dirección que tenga más de 32768 bits (16 bits) la carga debería ser del estilo:
L L#80000
TAR1
De tal forma que cargaremos la dirección 10000.0
Un poco altita la dirección aunque esa sería la forma. A decir verdad, lo suyo es jugar siempre con números en doble palabra como ya veremos más adelante aunque hacerlo como enteros también es válido aunque limitado a la capacidad de una palabra frente a la doble.[divider]
Direccionamiento Indirecto por Registro e Intraárea/Interárea
La diferencia fundamental entre el registro e Intraárea y registro e Interárea es:
- Intraárea: No se especifica el área de memoria
- Interárea: Vamos a especificar el área de memoria (el tipo, por así decirlo)
¿Y esto qué significa en cristiano?
Pues a la hora de la verdad, y para nosotros, no mucha cosa. En resumen, y que permitan los puristas, lo que vamos a hacer es o bien:
LAR1 P#50.0 // Cargar el puntero
L MW [AR1, P#10.0] // Decir el operando (en este caso de carga), el tipo de área (marcas) y la dirección.
O también podemos hacer:
LAR1 P#M50.0 // Cargar el puntero CON la zona de memoria
L W [AR1, P#10.0] // Decir el operando y la dirección.
¿Resultado?
Pues básicamente el mismo. La diferencia es que en el direccionamiento de tipo intraárea, el contenido del AR1 va a tener la misma pinta que el direccionamiento por memoria que veíamos en el capítulo I. No tiene el área de memoria asignado (marcas en nuestro caso).
¿Qué se usa más?
Personalmente intraárea, pero supongo que es cuestión de gustos. Además imaginemos que mezclamos las cosas y hacemos lo siguiente:
LAR1 P#E50.0
L MW[AR1,P#10.0]
Como veis hemos indicado el área en la carga del registro AR1 y luego hacemos una carga de MW… ¿vamos a mandar la CPU a Stop o crearemos un agujero espacio-tiempo?
Pues no. No sé si lamentablemente, pero no.
Simplemente del AR1 tomaremos la dirección, pero no la zona de memoria y ejecutaremos el operando de carga MW.
Por tanto, y a mi juicio, es mejor siempre usar el intraárea. Me parece más metódico ya que siempre vas a construir los punteros de la misma forma, independientemente del uso que le vayas a dar posteriormente.
Muy bien, me parece estupendo… pero me he perdido en el L MW [AR1, P#10.0]… ¿qué significa?
Muy sencillo. Lo que hay entre corchetes es la dirección inicial más un desplazamiento. De tal forma que en nuestro ejemplo, realmente estamos leyendo la MW60 (50 del AR1 +10 del offset por así decirlo).
¿Es obligatorio poner ese offset siempre?
Si. Siempre. Sin excepción. Pones un P#0.0 si no lo quieres y listo.
¿Qué pasa si cargo un P#50.0 en el AR1, cargo un offset P#0.1 y hago una lectura MB, MW o MD?
Pues que estarías provocando un bonito error de runtime. Ya que para hacer una lectura de byte, word o doble word, necesitas que el bit del puntero sea 0 (ojo, el bit, no el byte). No puedes crear un MW50.1 como puedes imaginar. Así que cuidadín con eso.[divider]
¿Qué más puedo hacer con los registros?
Como no sólamente del AR1 vive el hombre, existe también un segundo registro, el AR2 . Con esta pareja, podemos jugar indistintamente para cargar nuestros punteros e incluso combinarlos en las operaciones.
Así, para seguir con el ejemplo anterior, podríamos hacer:
LAR1 P#50.0
LAR2 P#10.0
L MW[AR1,AR2] : No se puede usar ambos AR para hacer este tipo de direccionamiento
L MW[AR1,p#0.0]
T MW[AR2,P#10.0]
¿Qué operaciones puedo hacer con los registros?
LARn : Cargar el contenido del ACU1 en el registro ARn, siendo n=1 o 2.
Offtopic: Y no, no es un 102, es un 1 O 2. A la RAE le ha parecido buena idea no tener que acentuar desde hace un tiempo la O entre números. Qué país.
TARn: Transferir desde el registro n, su contenido al ACU1.
+ARn: Sumar al contenido del ARn, el contenido del ACU1.
Pero como hemos visto, podemos hacer cargas y transferencias directas:
LARn <Dirección>: Cargamos la dirección al ARn. Por ejemolo LAR1 P#50.0
TARn <Dirección>: Cargamos el contenido del ARn en la dirección. Por ejemplo TAR1 MD50
+ARn <Puntero>: Añadimos al ARn el puntero que queramos. Por ejemplo, +AR1 P#10.0
Para rizar el rizo, podemos copiar la información entre los AR haciendo:
LAR1 AR2, con lo que cargaremos en el AR1 el contenido del AR2
TAR1 AR2, con lo que recuperamos el contenido del AR1 y se lo cargamos en el AR2.
Como ves las combinaciones son unas cuantas si bien se pueden resumir en asignación y suma.[divider]
¿Y todo esto, ya sirve para algo?
Pues aunque pueda parecer lo contrario, el direccionamiento indirecto sirve para muchas cosas, pero sobre todo para recorrer información y tratarla.
En el siguiente video os voy a mostrar cómo se usa el direccionamiento indirecto, especialmente con bucles LOOP (for-next), como ya vimos.
Recordarte finalmente que si estás interesado en formarte en Step 7, puede que te interese adquirir el libro «Cómo programar en Step 7 y no morir en el intento» donde puedes encontrar no sólamente el curso completo gratuito, sino muchas más entradas del blog que como sabes se irán actualizando para los que lo adquieran de forma gratuita. Si estás interesado, puedes echarle un vistazo a este enlace donde se explica qué es lo que contiene el libro, el precio y los métodos de pago.
Referencias:
Enseño a programar PLC de Siemens a través de mis cursos.
Más información sobre mi aquí
Puedes seguirme en cualquiera de las siguientes redes sociales.
31 Comentarios
No me permite utilizar la instrucción «L MW[AR1,AR2]» (Error de sintaxis en AR2).
lo primero que está en las explicaciones es que eso no se puede hacer!!!
Hola Carlos,
Cuando lo he leído he pensado: «como que eso no se puede hacer»… lo que no me había fijado, es que lo había puesto como ejemplo. Se me debió ir la olla al poner ejemplos.
Efectivamente el Offset no puede ser otra variable o registro, sino que tiene que ser fijo.
Pero ya veo que estáis atentos jeje. Siento el error.
Un saludo,
Hola Íñigo:
Ensayando el direccionamiento indirecto estaba preguntándome el como hacerlo a diferentes elementos dentro del mismo DB. Por ejemplo, quiero transferir un resultado que va a ir variando y cada vez, o cada cierto tiempo, quiero almacenarlo paulatinamente en diversos enteros que he puesto en un DB. En S7-1200 conozco la función «FieldWrite» para hacerlo, ¿pero cómo se haría con un S7-300?. He estado buscando informaciones, pero no encuentro nada. Gracias por anticipado por responder. Un saludo.
Hola,
No te sigo muy bien. Pon un ejemplo de qué querrías hacer please.
Si, imagina que tengo una función que me va a dar un resultado diferente en un entero dependiendo de unas condiciones, y yo quiero tener almacenado en un DB los diversos resultados cada cierto tiempo (o cada vez que yo determine), o sea, imagina que tengo el resultado en una MW200 (Int) y quiero ponerlo paulatinamente en DB1.DBW0, luego en DB1.DBW2…3…4 y así paulatínamente, pero claro, lo que quiero saber es si se puede hacer el direccionamiento indirecto de esa última parte, del DB1.DBW… Ya que según veo no me deja hacer, por ejemplo:
L 2
T MW0
L MW200
T DB1.DBW[MW0]
No me deja hacerlo y me da un error de sintaxis
Por cierto, buenas noches 😉
No se puede hacer ese tipo de direccionamiento.
Una marca, la mw0 en este caso con un índice solo sirve para hacer referencia a la llamada de fc, fb, temporizadores o abrir db. Todo aquello que este indexado. Numerado.
Tu quieres acceder a una posición de memoria.
Tendrías que crear un puntero. Si en el db quieres cargarlo en la segunda posición tendrás que cargar algo asi
L p#2.0
T MD0 (no mw)
L mw200
Auf db1
T dw[md0]
A ver si se me ocurre un ejemplo y se lo dedico una semana.
Efectívamente.
Esta noche te garantizo que voy a dormir más tranquilo 🙂
No será por que no lo has explicado en las entradas sobre direccionamiento indirecto.
Que sería de mi sin los ejemplos… No es lo mismo verlo…
Bueno, como siempre, gracias.
Me alegro haber resuelto la duda.
El direccionamiento indirecto es realmente útil en ciertos casos, pero tampoco hay que abusar porque es difícil de seguir cuando quieres encontrar un problema o fallo.
Saludos
Hola de nuevo Íñigo:
Veo mi comentario y es curioso, pero también voy a tener que depurar el comentario…
Donde dije DB1.DBW2…3…4…, debía ser DB1.DBW2…4…6…
Lo de
L 2
T MW0
L MW200
T DB1.DBW[MW0]
MD0 en vez de MW0 era lo de menos, pese a que me alegro del patinazo, ya se sabe, no hay más para que no vuelvas a cometer un error que haberlo cometido ya…
En todo caso la idea era saber como direccionar indirectamente a elementos dentro de un DB, eso me hizo descuidar todo lo demás. Por cierto ¿alguna explicación que merezca la molestia de darla de por qué no se puede hacer T DB1.DBW[MD0] y hay que hacerlo como has dicho OPN DB1 y T DW[MD0]?
Saludos y gracias.
No se puede hacer un T DB1.DBW[MD0]
¿La razón «tessnica»? Pues mas menos NPI. Entiendo que habrá que abrir previamente un área de memoria antes de posicionarse sobre él.
¿Absurdo? Pues sí. Pero lo cierto es que es un requerimiento previo.
Lo cierto es que tienes que hacer una apertura del DB y luego hacer la carga o la lectura.
Bien haciendo:
AUF DB1
T DW[MD0]
o bien, usando
AUF DI 1
T DIW[MD0]
Y sí, la única forma más fácil de no equivocarse es haberse equivocado con anterioridad. De eso no hay duda. En mi caso a veces, varias veces 😉
Hola Iñigo, mi pregunta es pq es necesario utilizar el comando AUF , o cuando se utiliza y porque. Yo puedo acceder a los datos de un DB y no entiendo muy bien cuando utilizarlo.Gracias y felicidades por tu web
Hola Adolfo,
Hasta donde yo sé, creo que no hay forma de realizar un puntero a un DB de una forma directa, es decir, no se puede hacer algo del estilo:
L DB1.DBX[MD0]
Por tanto hay que realizar la apertura previamente a la lectura o escritura sobre el DB en cuestión.
Cuando quieras hacer una lectura/escritura directa, lógicamente puedes hacer un
L DB1.DBW8
T DB1.DBW10
Aunque también podrías hacer:
AUF DB1
L DBW8
T DBW10
Ambos casos realizarían lo mismo.
Apreciado Iñigo.
Creo ver un error en el direccionamiento en BITs, en el video anterior el bit 10.0, es en realidad el bit 81 y no el 80. Ya que esta relacion entre Byte y bits, se puede expresar como: Byte . bit = (Byte x 8) + (bit + 1).
Por ejemplo. 10.0, donde Byte = 10 y bit = 0
el bit correspondiente es: (10×8 ) + (0+1) = 80 + 1 = 81
El bit correspondiente a la direccion: 9.7
Seria: (9×8) + (7+1) = 72 + 8 = 80, este si corresponde al bit 80 del Ejemplo.
Gracias.
Esta bien. Creo que no estas contando con el valor cero, que ya es el primer bit.. El 0.0. Por tanto 80 bits es el 10.0
O de otra forma 80 unidades son 81 posiciones de memoria, porque hay que contar el cero.
Si 0 es el 0.0 – >8 es el 1.0 y por tanto 80 el 10.0
Saludos!
Amigo Iñigo.
Tengo un problema de direccionamiento indirecto.
En OB1, cargue un FB, y hago un loop, donde comparo valores con una Variable interna del OB. La que coinciden quiero guardarlas en el DB de instancia del FB.
No encuentro la manera de usar el «Indice» usado en el loop, para direccionar las memorias del DB donde deben ser ingresados los valores coincidentes.
Las diferentes sintaxis que he probado me da error, podrias ayudarme a este tipo de direccionamiento ????
Gracias.
Zeno Martorana.
Aclaratoria al anterior Comentario.
Cuando los valores coinciden con la Variable de comparacion, hago que el valor de lavariable sea guardado en el DB de instancia. Usando para ello una instruccion MOVE a la direccioin DBxx.DBW [indice, P#0.0].
Donde la variable indice se va incrementando en el loop y deberia direccionar la palabra de memoria donde debe ser ingresado el valor de la variable.
Pero me da error de Sintaxis.
No hagas eso.
Prueba a hacer esto, en vez de DBXX.DBW[Indice,P#0.0]…
Suponiendo que el indice tenga el número de bits de la dirección…
L #indice
LAR1
AUF DBXX
L (Valor que quieras guardar)
T DBW[AR1,P#0.0]
O bien: Solución 2
Supongamos que el índice como digo es la dirección y además es una DOBLE palabra.
Entonces:
AUF DBxx
L (Valor que quiero Guardar)
T DW[#indice]
Esta segunda solución es más sencilla y compacta. Pero ambas son válidas e igual de funcionales.
Saludos
APRECIADO IÑIGO.
TE AGRADEZCO MUCHO TU AYUDA. AQUI TE DOI EL RESULTADO DE HABER PROBADO LAS DOS SOLUCIONES QUE ME SUGERISTE.
ESTA SOLUCION NO ME FUNCIONO……….
AUF «DB82» //ABRO BLOQUE DB82
L (#OB82_MDL_ADDR_WORD) //VALOR QUE SE QUIERE GUARDAR, ES LA
VARIABLE INTERNA DEL OB82
T DW[#PNTR] //EL INDICE ES LA VARIABLE INTERNA DEL
DB, LLAMADA #PNTR
EN LA INSTRUCCION LOAD, ME DICE QUE HACE FALTA UN OPERANDO ????? Y EN LA INSTRUCCION TRANSFER, ME DICE QUE HAY UN ERROR DE SINTAXIS EN #PNTR
ESTA SOLUCION …….SI ME FUNCIONO PERFECTAMENTE.
L #PNTR //CARGO EL REGISTRO AR1 CON EL VALOR
DE #PNTR
LAR1
AUF DB82 // ABRO EL BLOQUE OB82
L #OB82_MDL_ADDR_WORD //CARGO LA VARIABLE A SALVAR EN ACC1
T DBW[AR1,P#0.0] //LA TRANSFIERO AL LUGAR DEL DB
INDICADO POR EL AR1 CON UN OFF-SET DE
P#0.0
GRACIAS AMIGO …… SIEMPRE OPORTUNO.
ZENO MARTORANA.
Otra preguntita, para mantener el contacto …….
Quiero cargar el ACC1, ACC2, AR1 o AR2 con un valor o una variable …… pero usando el lenguaje KOP ……. es posible hacerlo??????
Gracias.
Zeno Martorana
A ver, de lo que no te ha funcionado,
En el Load, no pongas paréntesis, solo la variable
L #OB82_MDL_ADDR_WORD
y en el segundo como ya indiqué #PNTR tiene que ser un DOBLE word. Por tanto, si es un entero, vuelcalo a un dobleword antes de hacer la operación.
Saludos
No. El direccionamiento indirecto no se puede hacer con FUP/KOP.
Saludos
Gracias mi amigo. Todo muy bien.
Zeno.
Muy bueno todos tus ejemplos y comentarios Iñigo, de verdad muchas gracias por ayudar a enseñar y a contribuir a hacer un pueblo culto entre los que programamos con Step 7. Saludos
Gracias Franklin!
hola lñigo, un gusto saludos desde nicaragua:
mi consulta me dejaron una tarea de hacer arrancar un variador vlt5000 via profibus, pero en el programa en la red profibus tiene que ser un vlt5000 pero fisicamente se instalo un fc302 ya que tiene un tarjeta convertidora que hace que el ste 7 manager lo vea como un vlt5000, toda la parte del hardware y la configuracion profibus lo tengo bien sin errores la cpu (315-2DP) no esta en error y tiene cargado toda la configuracion, pero no se como empezar para empezar a hechar arrancar el variador ya sea la parte de arranque, stop y la variacion de velocidad todo esto via profibus.
no se si me explico en la programacion estoy en cero ya que no se por donde empezar.
podrias ayudarme????
Lo siento, pero es una configuración demasiado particular como para saber cuál es la problemática y la solución.
Hola a todos,
Actualmente tengo un problema con un sistema nuevo en el que estoy trabajando.
actualmente estoy dando soporte a un área de plating antes de conocer estas líneas nunca había batallado tanto con un programa de step 7. el problema radico en que estoy buscando algunas direcciones o registros que guardan datos las cuáles las envía una HMI
estas llegan a un db. el problema es que no están en el programa al menos no aparecen por ningún lado … son muchas las que tengo que encontrar, pero no sé cómo buscarlas si alguien tiene alguna idea se los agradecería
Si no están en las referencias cruzadas, puede que se estén usando de forma indirecta, y no hay forma de encontrarlas salvo que sepas cómo se está usando.
Hola
Tengo una situacion en PLC s7 300 de siemen. podrias darme soporte en linea. como podriamos hacerlo?
Hola,
No me dedico a dar ese tipo de soporte, lo siento.