Vamos a ver cómo copiar datos de forma dinámica en Step 7 para que si tienes diferentes bloques de información homogéneos en su estructura (pero no en sus datos) y los quieres copiar a un boque final en función de un parámetro cualquiera.
Por ejemplo, tenemos diferentes DB con información de ciertos productos que en función del producto, lo tenemos que copiar a un DB.
Podrías decir, bueno, en función del producto, hago una copia del DB del producto al DB final y ya está…
Hombre, pues sí, pero digamos, que es mucho trabajo y poco elegante. Porque si en vez de ser 10, ¿son 100?
Cómo copiar datos de forma dinámica en Step 7
Pues resulta que la solución es realmente fácil usando direccionamiento indirecto en Step 7.
Imaginemos que los DB donde tenemos la información son del estilo DB100 + Número de producto, es decir:
- DB101 para el producto 1
- DB102 para el producto 2
- DB103 para el producto 3 …
Y así con todos.
Imaginemos, a su vez, que el DB destino es el DB1 (por poner un ejemplo) y que queremos copiar 50 bytes.
Bien.. ¿cómo copiar datos de forma dinámica? Pues realmente de una forma muy sencilla.
Lo primero que debemos tener en cuenta que para realizar este tipo de ejercicios podemos usar la apertura de los db de dos formas:
- AUF DB
- AUD DI
Sí, porque de esta manera, la solución es realmente sencilla.
Una vez sepamos el número de producto a copiar, tan solo deberemos usar la función SFC20 (Block Move) para solucionar nuestro problema.
L #NumeroProducto //Leemos nuestro número de producto que indica el DB que almacena la información
L 100
+ I
T #NumeroDB // Sumamos el número de producto 100 unidades para obtener el número de DB a usar
AUF DI[#NumeroDB] //Abrimos el DB
CALL «BLKMOV»
SRCBLK :=P#DIX 0.0 BYTE 50
RET_VAL:=MW0
DSTBLK :=P#DB1.DBX 0.0 BYTE 50
¡Y ya está!
Como ves, en la solución, manejamos 2 conceptos:
- Apertura de los bloques con AUF DI para abrir el bloque origen, y luego el puntero lo hacemos relativo a esa apertura simplemente leyendo 50 bytes del bloque abierto con AUF DI
- Puntero absoluto de 50 bytes al DB1 destino
¿El destino podría ser dinámico a su vez?
Claaaaro. Si en vez de haber usado, el DB1, quisieramos usar un #DBDestino, podríamos hacer análogamente:
L #NumeroProducto //Leemos nuestro número de producto que indica el DB que almacena la información
L 100
+ I
T #NumeroDB // Sumamos el número de producto 100 unidades para obtener el número de DB a usar
AUF DI[#NumeroDB] //Abrimos el DB origen
AUF DB[#DBDestino] // Abrimos el DB destino
CALL «BLKMOV»
SRCBLK :=P#DIX 0.0 BYTE 50
RET_VAL:=MW0
DSTBLK :=P#DBX 0.0 BYTE 50
Como ves, esto de cómo copiar datos de forma dinámica en Step 7 es muy útil si quieres pasar información entre bloques.
¿Qué te ha parecido? ¿Te parece útil?
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.
15 Comentarios
Supongo que el SFC20 tendrá sus limitaciones en el ancho de memoria que va a mover!
Pues a decir verdad, la ayuda de Siemens no dice la longitud máxima. Yo lo he usado y he copiado bloques muy grandes sin problemas.
Funcionará con DBs optimizados? No me adapto a estos nuevos DBs!
A ver, es AWL, y los 300/400 no admiten bloques optimizados. El 1500 sí, y la ayuda de Siemens dice esto:
Descripción
La instrucción «Copiar área» permite copiar los contenidos de un área de memoria (área de origen) en un área de memoria diferente (área de destino). La operación de copia se realiza por orden ascendente de direcciones. Las áreas de origen y destino se definen mediante VARIANT.
Nota
Las variables de la instrucción solo se pueden usar en los bloques de datos en los que no está ajustado el atributo «Acceso optimizado al bloque». Si la variable se ha declarado con el ajuste de remanencia «Ajustar en IDB», la variable también se puede usar «con acceso optimizado».
Buenos días, ¿cómo podría copiar dato a dato y pasarlo a una misma mw. Pasar todos los datos enteros de un db, por ej. 100 datos, a una misma mw, para luego pasarla a través de un dp dp a otra máquina. O sea que haga un barrido en bucle dl db y pase los datos uno a uno y los vaya pisando. Gracias.
Hola José. Tendrías que hacer un bucle que vaya leyendo el DB, y vaya recorriendo este paso a paso con un disparador. Leyera la posición X y la mandara a la salida Y (que sería la marca).
Saludos
Eso funciona para S7-300, pero en S7- 1500, me dice que el dato está incompleto, es decir, que aun cuando abro antes el bloque, me pide poner el prefijo DB, esto es: P#DB101. DBX 0.0 BYTE 50 y así ya no me sirve porque necesito que el Bloque de datos sea variable.
Sal U2
Efectivamente, el ejemplo es para S7 tradicional, y la serie 300 y 400.
Las series 1200 y 1500, son en muchos aspectos diferentes, entre ello, los bloques de datos.
¿Los bloques los has configurado como no optimizados? Si no los configuras así, no funciona el sFC20 correctamente.
Otra opción que tienes, seguramente más práctica, es usar SCL para realizarlo en TIA Portal.
Saludos
El largo del db es posible hacer que varie??
Si, jugando con los punteros puedes hacer el ancho sea dinámico también.
Tendrás que jugar con la definición del puntero para que el ancho sea una variable de entrada.
Hola Gútiez
Una pregunta. Tomando en cuenta la estructura «P#0.0 BYTE 50» hay alguna manera para que ese «0.0» y «50» sea variable? es decir poder cambiar el tamaño de la estructura y el puntero inical?
Sí, tienes que configurar el puntero como tu quieras. Mira esta entrada: https://programacionsiemens.com/domina-los-punteros-con-formato-any/
Muchas gracias por tu pronta respuesta!!
Para configurar el puntero ANY al inicio de tu código dice
LAR1 P##Source
Según tu definición de variables
Source = type ANY
Pero siempre se pone rojo mi código. No me deja colocar ese código inicial
Ya cambié “Source” a tipo INT, DInt, Pointer, ANY me da error
Y quedó
Perdón =)
El código del ejemplo es un source de AWL. La idea es que cojas ese código y lo estudies para que veas como se hace, no que lo pegues tal cual, porque no te va a funcionar seguramente.
Tienes que crear un FC, e ir implementando poco a poco el código, entendiendo cada parte de lo que se explica en el texto.
Para empezar, por ejemplo, asegúrate que la variable SOURCE, que es de tipo ANY, la llamas SOURCE, y no #SOURCE, y la declaras en la sección de temporales.
Esto debe funcionar sí o sí, porque no tiene más en un PLC S7-300 programado con S7 clásico.