Comparación de cadenas de caracteres en Step 7

cadenas de caracteres en step 7Esta semana vamos a realizar un ejercicio práctico de cómo comparar dos cadenas de caracteres en Step 7 bien que sean alfanuméricos o dos cadenas cualesquiera de datos.

Si lo que queremos comparar son dos strings como tal, Step 7 proporciona de origen un FC con el que poder comparar cadenas de caracteres en forma de string. Se trata del bloque FC 10 EQ_STRNG que puedes encontrar desde el editor en Librerias-> Standard Library -> IEC Function Blocks.

Bien. Lo lógico es usar esta función o cualquier otra de las que te ofrece Step 7 si se ajusta a tus necesidades.

Pero lo que vamos a realizar hoy es poder comparar cualquier cadena de bytes de dos DB y ver si son iguales o no. Da igual el tipo de datos que tengamos en ese área de memoria.

Comparar dos cadenas de caracteres en Step 7

La idea es simple: poder comparar dos areas de memoria consecutiva de dos DB (o del mismo) y saber si ambas áreas son iguales.

¿Para qué sirve eso?

Pues por ejemplo si tienes una comunicación en la cual envias X bytes a otro PLC, Scada o lo que sea y quieres saber que realmente lo que envias y lo que el interlocutor está leyendo es lo mismo por ejemplo para activar una orden de actuación.

Entonces, la forma de operar es que un PLC escribe en un DB digamos DB1 y el interlocutor copia ese DB a un DB2 que te lo envía de vuelta.

La forma de saber que lo que uno escribe, el otro lo recibe es comparando ambos DB, cosa que puede ser muy simple si intercambias digamos un DW, pero bastante engorrosa si estás intercambiando 100 bytes.

¿Qué necesitaremos para comparar las cadenas de caracteres en Step 7?

Pues vamos a necesitar tener ciertos conocimientos de:

Como ves, nada que no hayamos visto con anterioridad en el blog.

¿Y cómo vamos a hacer la comparación de las cadenas de caracteres en step7?

Básicamente vamos a realizar un FC donde pasaremos como variables de entrada:

  • Los números de los DB
  • Los números de byte de origen de los datos de ambos DB
  • La longitud a comparar en bytes

Por otra parte, y como salida del FC, obtendremos una salida booleana indicativa de si ambas cadenas son iguales o no.

En cuanto a el programa en sí, y como referencia, la idea sería la siguiente:

  • Poner una marca booeana a cero indicando inicialmente que ambas cadenas originalmente son iguales
  • Hacer un FOR-NEXT con el número de bytes a comparar
  • Crear los punteros correspondientes a cada posición
  • Comparar cada byte entre ambos DB haciendo un XOR
  • Si el resultado se mayor que cero, hacer un SET de la booleana indicando que no son iguales
  • Si el resultado es cero, no hacemos nada.
  • Continuamos con el FOR
  • Finalmente igualamos la booleana a la salida del bloque.

Seguidamente te dejo con el código fuente del FC para que le vayas echando un vistazo:

FUNCTION “Comparador de cadenas” : VOID
TITLE =
VERSION : 0.1
VAR_INPUT
NumDB1 : INT ; //Número del primer DB a comparar
NumDB2 : INT ; //Número del segundo DB a comparar
Byte1 : INT ; //Número del primer byte de la cadena del DB1
Byte2 : INT ; //Número del primer byte de la cadena el DB2
Longitud : INT ; //Longitud de bytes a comparar
END_VAR
VAR_OUTPUT
Resultado : BOOL ; //Resultado final de la comparación.
END_VAR
VAR_TEMP
Comparacion : BOOL ; //Resultado temporal de la comparación
IndiceForNext : INT ;
PunteroOffSet : DWORD ;
DBNum1 : INT ;
DBNum2 : INT ;
ResultadoXOW : INT ;
END_VAR
BEGIN
NETWORK
TITLE =
//Inicializamos la variable Comparacion
SET ;
R #Comparacion;
// Transferimos los valores de los DB a las variables.
// Hay que hacerlo así porque no se puede leer directamente como IN
L #NumDB1;
T #DBNum1;
L #NumDB2;
T #DBNum2;
NETWORK
TITLE =
//Hacemos un for-next con el número de bytes de longitud ya que vamos a comparar
//byte a byte.
L #Longitud;
NEXT: T #IndiceForNext;

// Generamos un puntero OffSet
L #IndiceForNext; // Cargamos el indice
ITD ; // Lo pasamos a doble
L P#1.0; // Cargamos un puntero de un byte
*D ; // Multiplicamos en doble para general el puntero origen
T #PunteroOffSet; // Obtenemos el OffSet

// Generamos el puntero del DB1
L #Byte1; // Cargamos el byte de inicio
ITD ; // Pasamos a doble (como los punteros)
L P#1.0; // Cargamos un puntero de un byte
*D ; // Multiplicamos en doble para generar el puntero origen
LAR1 ; // Lo cargamos en el AR1
L #PunteroOffSet; //Cargamos el offset de este loop
+AR1 ; // Se lo sumamos al AR1

// Generamos el puntero del DB2
L #Byte2; // Cargamos el byte de inicio
ITD ; // Pasamos a doble (como los punteros)
L P#1.0; // Cargamos un puntero de un byte
*D ; // Multiplicamos en doble para generar el puntero origen
LAR2 ; // Lo cargamos en el AR2
L #PunteroOffSet; //Cargamos el offset de este loop
+AR2 ; // Se lo sumamos al AR2

AUF DB [#DBNum1]; // Abrimos el DB1
AUF DI [#DBNum2]; // Abrimos el DB2
L DBB [AR1,P#0.0]; //Cargamos el valor del primer puntero
L DIB [AR2,P#0.0]; //Cargaos el vaor del segundo puntero
XOW ; //Hacemos un XOR de palabra
T #ResultadoXOW;
// Toma de decisión
L #ResultadoXOW; // Si el resultado es cero, no hacemos nada porque de momento son iguales
L 0; // Comparamos con cero, si son iguales, saltamos sin hacer nada
==I ;
SPB EXIT;
SET ; // Si no son iguales, continuamos y ponemos a uno la variable
S #Comparacion;

EXIT: NOP 0;

L #IndiceForNext; // Hacemos el next cargando el valor del indice
LOOP NEXT;
UN #Comparacion; // tomamos el valor de la comparacion y le cambiamos el signo
= #Resultado; // Igualamos a la salida
END_FUNCTION

Todo esto, será llamado desde el OB1:

CALL “Comparador de cadenas”
NumDB1 :=1
NumDB2 :=2
Byte1 :=0
Byte2 :=0
Longitud :=10
Resultado:=M100.0

Bien, no quiero que te agobies porque tengo preparado como siempre el…

Video de cómo comparar dos cadenas de caracteres en Step 7

Pues eso, que te dejo con la explicación de cómo funciona además de lo arriba expuesto.

¿Qué te ha parecido?

Espero que te haya sido de utilidad lo que te he contado hoy. En cualquier caso, aunque no lo uses para lo que está pensado, piensa que esta comparación de cadenas de caracteres en Step 7 está compuesta como hemos visto de operaciones interesantes.

Esta entrada entre otras están incluidas en el curso “Cómo programar Step 7 y no morir en el intento

Acerca de Iñigo Gútiez

Ingeniero industrial por la Escuela de Ingenieros Superiores de Bilbao. Trabajo como ingeniero de proyectos y automatización en Guardian Industries

Te puede interesar

multiinstancias en step 7

Multiinstancias en Step 7

Las multiinstancias en Step 7 fueron unas de las cosas que se quedaron en el …

3 Comentarios

  1. Hola Íñigo:

    Siempre me había preguntado como resguardar la integridad de los datos en un sistema distribuido, sí, los mandamos, pero ¿qué es lo que se recibe por parte del interlocutor?, una vez más, mostrando como se hacen las cosas. Saludos.

  2. hola,
    gran aporte, pero me surge una duda.
    por que uno lo tratas como B y el otro como I?

    AUF DB [#DBNum1]; // Abrimos el DB1
    AUF DI [#DBNum2]; // Abrimos el DB2

  3. Hola Guillermo,

    Para poder abrir dos DB hay que usar la apertura mediante AUF DB y la otra mediante AUF DI. Si haces dos AUF DB, lo que haces es abrir el primero y luego abrir el segundo pero cerrando el primero. Es decir, con AUF DB abres uno exclusivamente y haces las operaciones con el ultimo abierto. Si quieres combinar operaciones entre dos, no te que da más remedio que abrirlo con DI.
    Salvo qua abras uno, vuelques la información a una variable temporal, abras otra vez y vuelques a una variable … etc.

    Saludos