Una forma de leer y copiar información dinámica es realizarlo mediante punteros con formato ANY.
Lo que vamos a ver es por un lado cómo se crean a mano los punteros, y luego darle una aplicación práctica.
Pero antes de eso, tenemos que ver un poco (o refrescar) qué es el formato ANY.
Según la documantación de Siemens, [..] se utiliza cuando el tipo de datos del parámetro actual no se conoce o cuando se puede utilizar cualquier tipo de datos. [..]
STEP 7 almacena los datos del tipo de parámetro ANY en 10 bytes. Al estructurar un parámetro del tipo ANY, los 10 bytes deben quedar ocupados, ya que el bloque llamado evalúa todo el contenido del parámetro. Si, por ejemplo, especifica un número de DB en el byte 4, deberá indicar también explícitamente el área de la memoria en el byte 6.
STEP 7 gestiona los datos de los tipos de datos simples y compuestos de forma diferente a la de los tipos de parámetros.[..]
¿A que ahora ya te has quedado más tranquilo?
Bueno, pues en cristiano, lo que quiere venir a decir es que con un ANY lo que defines es un área de la memoria (marcas, entradas, db..) y defines la longitud de ese área. Además, el puntero con formato ANY tiene obligatoriamente 10 bytes de longitud y tienes que rellenar los 10 bytes sean necesarios o no. Así por ejemplo, puedes definir el área definido en un DB en concreto y que sea de un ancho de 24 bytes… por poner un ejemplo.
Contenido
¿Cómo creamos un puntero con formato ANY?
Bueno, vayamos por partes para entenderlo bien. En la siguiente figura tienes un resumen de cómo hay que rellenar los 10 bytes que forman un ANY en el caso de los tipos de datos simples y compuestos.
Vayamos por tanto a repasar cada byte:
Byte 0: Hay que cargar siempre un 10H. Una constante que le sirve a Step 7 para indicar que es un ANY.
Byte 1: Tipo de datos .
Tendrás que cargar en hexadecimal en el byte 1 el número según la tabla para indicar qué tipo de datos quieres usar.
Word 2 (Byte 2 y 3): Factor de repetición, es decir, la cantidad de items
Word 4 (Byte 4 y 5): número de DB. Si no es de un DB el área de memoria, pones un bonito 0.
Byte 6: Área de memoria. Es decir, el tipo. Lo indicamos en la siguiente tabla:
Byte 7, 8 y 9: La dirección se almacena en formato byte.bit. La dirección de byte se deposita en los bits 0 a 2 del byte 7, en los bits 0 a 7 del byte 8 y en los bits 3 a 7 del byte 9, mientras que la dirección de bit se deposita en los bits 0 a 2 del byte 9.
En el puntero nulo del tipo de datos NIL, todos los bytes estarán ocupados con 0 a partir del byte 1.
Pero también se puede crear un puntero ANY con informacion sobre un temporizador, contador o bloque. Es parecido pero no es del todo igual. Veámoslo.
Formato ANY en los tipos de parámetros
En el caso de los tipos de parámetros, STEP 7 almacena el tipo de datos y la dirección de los parámetros. El factor de repetición es siempre 1. Los bytes 4, 5 y 7 son siempre 0. Los bytes 8 y 9 indican el número del temporizador, del contador o del bloque.
La tabla siguiente muestra la codificación de los tipos de datos para el formato ANY en el caso de los tipos de parámetros.
¿Y para qué usamos un puntero con formato ANY?
Bueno, pues después de todo este rollo (que está bien saber por otro lado) vamos a ver si podemos darle una utilidad.
Lo que nos va a permitir esto es poder leer áreas de los diferentes tipos de memoria y poder escribirla en otro área de memoria de forma dinámica.
¿Una aplicación práctica para esto?
Pues por ejemplo, en los hornos de curvar parabrisas con los que trabajo, la información de la pauta hay que volcarla en diferentes momentos sobre la zona donde se está curvando. Es decir, en cada zona del horno, se lee la información de potencias de esa potencia para un determinado cajón el cual va cambiando. Es decir, tienes una zona que es dinámica y un carro que es dinámico.
Como ves, aunque no lo vayas a aplicar todos los días, es bastante útil cuando toca.
Copiar áreas de memoria usando los puntero con formato ANY
Como ejemplo vamos a analizar un bloque para copiar dos áreas de memoria. De un DB a otro DB.
Te dejo la fuente AWL comentada para su mejor entendimiento y estudio:
[box type=»shadow» align=»aligncenter» class=»clase1″ width=»»]
FUNCTION «Copiar areas MB–>DB» : VOID
TITLE =TRANSFER MB -> DB
VERSION : 0.0
VAR_INPUT
MBSOURCE : INT ; //DB ORIGEN
DBTARGET : INT ; //DB DESTINO
DBWTARGET : INT ; //DBW DESTINO
NBBYTE : INT ; //NUMBERO DE BYTES A TRANSFERIREND_VAR
VAR_TEMP
SOURCE : ANY ; //ANY ORIGEN
TARGET : ANY ; //ANY DESTINO
RET : INT ; //TEMPÒRAL RETURN
END_VAR
BEGIN
NETWORK
TITLE =COMPUTE ANY POINTER FOR SOURCE
LAR1 P##SOURCE; // CARGAMOS EN EL AR1 LA DIRECCION DEL ORIGEN
L B#16#10; // SYNTAXIS PARA S7 (SIEMPRE ES IGUAL)
T LB [AR1,P#0.0]; // -> SE LO CARGAMOS AL ANY EN SU BYTE 0
L B#16#2; // CARGAMOS EL TIPO DE DATO: BYTE
T LB [AR1,P#1.0]; // -> SE LO CARGAMOS AL ANY EN SU BYTE 1
L #NBBYTE; // NUMBERO DE BYTES A TRANSFERIR
T LW [AR1,P#2.0]; // -> SE LO CARGAMOS AL ANY EN SU WORD 2
L 0; // COMO NO ES UN DB, CARGAMOS UN CERO
T LW [AR1,P#4.0]; // -> SE LO TRANSFERIMOS AL ANY EN EL WORD 4
L B#16#83; // CODIGO DE TIPO DE MEMORIA PARA MB
T LB [AR1,P#6.0]; // -> SE LO TRANSFERIMOS AL ANY EN SU BYTE 6
L B#16#0; // LA DIRECCION DE LOS 3 BITS SUPERIORES
T LB [AR1,P#7.0]; // -> SE LO TRANSFERIMOS AL ANY EN SU BYTE 7
L #MBSOURCE; // LEEMOS EL NÚMRO DE MB ORIGEN
SLW 3; // DESPLAZAMOS 3 POSICIONES A LA IZQUIERDA
T LW [AR1,P#8.0]; // -> SE LO TRANSFERIMOS AL ANY EN SU WORD 8
NETWORK
TITLE =COMPUTE ANY POINTER FOR TARGET
LAR1 P##TARGET; // CARGAMOS EL DESTINO EN EL AR1
L B#16#10; // SYNTAXIS PARA S7 (SIEMPRE ES IGUAL)
T LB [AR1,P#0.0]; // -> SE LO CARGAMOS AL ANY EN SU BYTE 0
L B#16#2; // CARGAMOS EL TIPO DE DATO: BYTE
T LB [AR1,P#1.0]; // -> SE LO CARGAMOS AL ANY EN SU BYTE 1
L #NBBYTE; // NUMERO DE BYTES A TRANSFERIR
T LW [AR1,P#2.0]; // -> SE LO CARGAMOS AL ANY EN SU WORD 2
L #DBTARGET; // NUMERO DE DB DESTINO
T LW [AR1,P#4.0]; // -> SE LO TRANSFERIMOS AL ANY EN EL WORD 4
L B#16#85; // CODIGO DE TIPO DE MEMORIA PARA DB
T LB [AR1,P#6.0]; // -> SE LO TRANSFERIMOS AL ANY EN SU BYTE 6
L B#16#0; // LA DIRECCION DE LOS 3 BITS SUPERIORES
T LB [AR1,P#7.0]; // -> SE LO TRANSFERIMOS AL ANY EN SU BYTE 7
L #DBWTARGET; // DBW TARGET
SLW 3; // DESPLAZAMOS 3 POSICIONES A LA IZQUIERDA
T LW [AR1,P#8.0]; // -> ANY POINTER
NETWORK
TITLE =EXECUTE TRANSFER
CALL «BLKMOV» (// BLOCK MOVE
SRCBLK := #SOURCE,// ORIGEN
RET_VAL := #RET,// ERROR
DSTBLK := #TARGET);// DESTINO
NETWORK
TITLE =END OF BLOCK
BEA ;
END_FUNCTION
[/box]
¿Qué te ha parecido?
Ya sé que este tipo de cosas no se usa todos los días, pero no está demás conocerlas, saber que existe, y que es realmente potente dependiendo de lo que necesites hacer.
¿lo has usado alguna vez?
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.
13 Comentarios
Es un poco complicadillo pero muy potente. Yo lo he visto en mi fábrica para cargar las posiciones , según la pieza a trabajar, a los variadores que posicionan los ejes unas cotas que se definen en un bloque de datos. Por ejemplo la pieza N°1 toma los datos que están en un DB del byte 0 al 9. La pieza N°2 de byte 10 al 19 y así sucesivamente. Así de forma indirecta cargo las posiciones y puedo cambiar las cotas si lo necesito directamente en el DB no viéndome limitado pues el variador en si sólo puedo definir 64 posiciones o 256 según el modelo. Se podía poner un ejemplo sobre ello. Saludos!!!
Buenas tardes Iñigo, necesito transferir datos de un db a una sóla mw, o sea ir cargando y pisando esos datos de 97 alarmas de un db a una sola mw para poder pasarla a través de un dp dp coupler a otra máquina y así poder ver las alarmas de ambas máquinas en un solo hmi, pero no consigo que lo haga, ¿podrías orientarme? gracias.
Vale ya he conseguido volcar los datos. Lo he hecho a través de un puntero y un contador que escanea el db. Gracias. Saludos.
Hola
Tengo una duda. He visto como haces el direccionamiento en «Area Interna» P#0.0
Pero como lo hago en «Area cruzada» P#dbx0.0
Tengo algo así:
L P#dbx0.0
T #DBW_Origen
L #DBW_Origen
T LD [AR1,P#6.0]
y funciona si pero quiero hacer una referencia cruzada con «P#dbx0.0»
P#DBX [MD0] —-> esto no lo permite pero necesito algo así…
Tendrás algún ejemplo para basarme
Tienes que hacerlo con los áreas de registro AR1 y AR2. Algo así como U DBX[AR1,P#0.0] Siendo el AR1 la dirección y el puntero P#0.0 el offset respecto a la dirección AR1 si fuera necesario.
Hola a todos, super bien explicado este tema. Les dejo el ejemplo del apuntador que desarrolle con este curso. Saludos.
LAR1 P##Temp_DB // carga el apuntador ANY a utilizar
//Syntaxis-ID = 10 Para punteros tipo ANY, se carga al Byte 0 del puntero
L B#16#10 // carga 10 en el acumulador
T LB [AR1,P#0.0] // Transfiere 10 al byte 0 del apuntador
// Tipo de dato a usar, 2=byte, 3=char, 4=word, 5=Int…… Se carga en el byte 1
L B#16#2 // carga 2 en el acumulador, para usar tipo de dato byte
T LB [AR1,P#1.0] // transfiere 2 al byte 1 del apuntador
// Tamaño de memoria que usara el puntero, en este caso 1400 Bytes, se carga en el Word 2 del puntero
L 1400 // carga 1400 en el acumulador
T LW [AR1,P#2.0] // transfiere 1400 al word 2 del apuntador, se usa LW
// Numero de DB al que apuntara nuestro DB. gurada en el Word 4
L #Pallet_ID // numero de pallet introducido
L 1000 // el numero de db es el pallet + 1000
+I
T LW [AR1,P#4.0] // se transfiere el resultado de la suma en el word 4 del apuntador
// Numero de para tipo de memoria 81=In, 82=Out, 83=Memorias, 84=DB, …. Se carga en el Byte 6, 0 para byte 7, 8 y 9
L DW#16#84000000 // carga 84=DB en byte 6 y 0 en bytes 7, 8 y 9.
T LD [AR1,P#6.0] // transfiere 84 al byte 6 y 0 en bytes 7, 8 y 9.
Solo un pequeño apunte que me acaba de pasar al trabajar con DB’s grandes. En el área señalada como «00000bbb» correspondiente al byte 7 de la estructura any, los bits bbb muchas veces se dejan a cero.
Esto es por que casi siempre el desplazamiento requerido en la dirección final apuntada no es muy grande, de manera que basta con los 13 bits de los bytes 8 y 9. (podremos pues desplazarnos 2^13 = 8192 bytes, ya que los ultimos 3 bits son para apuntar a un bit dentro de esas 8192 posibles direcciones).
Si usamos esos tres bits bbb, podremos crear punteros any con desplazamientos mayores. Para ello, mi solución ha sido coger una vez mas el desplazamiento buscado «X» y desplazarlo 13 veces a la derecha, con lo que los 3 bits mas altos quedan justo encima alineados con los bits bbb, hacemos una OW con la word 6 de la estructura any para no machacar lo que haya en el byte 6. Saludos
Muy buena explicasion, aunque no he podido comprender todo completamente con el ejemplo. Eres es un buen elemento.
Gracias Daniel.
Muchas gracias por la ayuda
Como hago para introducir un puntero ANY de datos en la interface de un FB y luego usarlo adentro del FB para enviarlo con el FB15 Y FB15 (PUT GET). Porque cuando en las entradas del FB pongo una variable ANY y por afuera introduzco P#DB500.DBX0.0 BYTE2, andentro del FB no me deja usar la variable ANY en los FBs de comunicación. Tendría que meter por entradas el numero de DB y la cantidad de bytes y luego adentro del FB armar el puntero? Como armo ese puntero adentro del FB?
E visto que ingenieros arman de la siguiente manera
L 16
T B0
L B#16#2
T B1
L #numero_bytes
T W2
L #numero_DB
T W4
L 0
T D6
SLD 16 //DESPLAZO 16 A LA IZQ
SRD 13 //DESPLAZO 13 A LA DER
T D6
L B#16#84
T D6
Pero como es que de esta manera el step7 sabe que tiene que depositarlo en los bytes correspondientes a la variable ANY si yo no veo que lo especifiquen o lo carguen previamente, sin embargo para funcionar, el codigo en AWL lo hacen super sencillo. porque le pusieron un 16 en el byte 0?
En SCL, ¿como programar un FB, para realizar esto mismo de modo repetitivo?
No se muy bien a qué te refieres. Si quieres leer/escribir de forma dinámica en SCL, echa un vistazo a PEEK/POKE