2 de agosto de 2010

Contando en Step7

En mis programas de Step7 siempre he hecho un uso muy escaso de las funciones integradas de contaje. De hecho, cuando necesito contar, suelo recurrir a hacer mi propio contador ad hoc. En mi opinión, las instrucciones de contaje Simatic no resultan muy útiles, tienen su propio formato en BCD y su mayor limitación reside en su limitado rango de contaje, de 0 a 999. Si necesitamos contar más siempre se pueden encadenar dos o más contadores, pero no es muy práctico tener un contador repartido entre varias variables.

Otra opción que tenemos es utilizar contadores según la norma IEC 1131–3, que en Step7 están implementados como bloques de función de sistema (SFB) en la biblioteca Standard Library, bajo el apartado System Function Blocks. El SFB0 "CTU" sirve para contar hacia adelante, el SFB1 "CTD" para contar hacia atrás y el SFB2 "CTUD" para contar en ambos sentidos. El tipo de variable de contaje es un entero de 16 bits con signo (INT) lo que nos da un rango entre -32 768 y 32 767. En la ayuda de Step7 vienen perfectamente documentados. Aunque este rango nos permite un mayor juego, se me antoja que para muchos posibles usos se queda corto. Por ejemplo, una aplicación típica sería un contador de piezas en una máquina: es habitual llevar la cuenta de piezas buenas y piezas malas, la cantidad de piezas procesadas según su referencia, etc. Y ciertamente en una aplicación así el rango de contaje podría ser mayor, con la posibilidad de contar, dependiendo de la máquina, incluso millones.

No existe en Step7 un contador que tenga un rango de 32 bits, o por lo menos yo no he encontrado ninguna referencia, así que tengo mi propio bloque de función (FB) que uso para poner contadores de piezas en mis máquinas. Está programado en AWL y el código es muy sencillo:


Actualización: también tienes el código de los contadores en este proyecto de Step7.

FUNCTION_BLOCK FB1
TITLE =CONTADOR SIMPLE DE 32 BITS
//CUENTA ENTRE 0 Y 2 147 483 647
VERSION : 0.1


VAR_INPUT
CONTAR : BOOL ; //INCREMENTA EL CONTADOR EN CADA FLANCO POSITIVO DE ESTA ENTRADA
REINIC : BOOL ; //REINICIALIZACIÓN DEL CONTADOR (PUESTA A CERO)
END_VAR
VAR_OUTPUT
CUENTA : DINT ; //VALOR DEL CONTADOR
CONTANDO : BOOL ; //SEÑAL ACTIVA CUANDO SE ESTÁ INCREMENTANDO EL CONTADOR
END_VAR
VAR
FP : BOOL ; //VARIABLE AUXILIAR PARA DETECTAR FLANCOS POSITIVOS
END_VAR
BEGIN
NETWORK
TITLE =CÓDIGO AWL
//NOTASDEAUTOMATIZACION.BLOGSPOT.COM
U #REINIC; // SI SE REINICIA EL CONTADOR
SPBN SLT0; // SE PONE LA #CUENTA A CERO,
L L#0; // SE RESETEA #CONTANDO
T #CUENTA; // Y SE FINALIZA EL BLOQUE
R #CONTANDO;
BE ;

SLT0: U #CONTAR; // SI SE DETECTA UN FLANCO POSITIVO
FP #FP; // EN LA SEÑAL DE CONTAJE
= #CONTANDO; // SE ACTIVA LA SALIDA #CONTANDO

UN #CONTANDO; // SI NO SE ESTÁ #CONTANDO
BEB ; // SE FINALIZA EL BLOQUE
L #CUENTA; // EN CASO CONTRARIO
L L#1; // SE INCREMENTA LA #CUENTA
+D ;
T #CUENTA;
BE ;
END_FUNCTION_BLOCK

NOTA: Para incorporarlo en un proyecto crea un fichero fuente AWL vacío en la carpeta Fuentes del árbol de proyecto de Step7. Abre dicho fichero y copia y pega el código anterior, cambia en la primera línea el número de FB que quieres que contenga el código y compila. Si todo va bien en la carpeta de bloques de programa aparecerá el código del contador en AWL con su interface y comentarios.

Lo que hace este sencillo contador es fácil de ver siguiendo el código comentado. Cada vez que se detecta un flanco positivo en la entrada #CONTAR se incrementa la #CUENTA, que es un entero con signo de 32 bits (DINT). Con la entrada #REINIC se reinicializa el contador (se pone su valor a cero). En la salida #CUENTA tenemos el valor del contador y la salida #CONTANDO se activa durante el ciclo de autómata en el que se incrementa la #CUENTA, y que se puede usar, por ejemplo, para llevar varios contadores simultáneos:


Otra aplicación donde encaja perfectamente un contador es en el control de piezas de desgaste, como por ejemplo para llevar la cuenta del número de operaciones sobre una cuchilla en una máquina de corte y poder avisar al operario de que es necesaria su sustitución. En este caso se puede usar un contador más completo, como el que presento en el siguiente código:

FUNCTION_BLOCK FB2
TITLE =CONTADOR INCREMENTAL - DECREMENTAL DE 32 BITS
//CUENTA ENTRE -2 147 483 648 Y 2 147 483 647
VERSION : 0.1


VAR_INPUT
INCREMENTAR : BOOL ;
DECREMENTAR : BOOL ;
REINICIALIZAR : BOOL ;
AJUSTAR : BOOL ;
VALOR_AJUSTE : DINT ;
UMBRAL_MAXIMO : DINT ;
UMBRAL_MINIMO : DINT ;
END_VAR
VAR_OUTPUT
CUENTA : DINT ;
ES_CERO : BOOL ;
INCREMENTANDO : BOOL ;
DECREMENTANDO : BOOL ;
CUENTA_MAYOR_UMBRAL_MAX : BOOL ;
CUENTA_ENTRE_UMBRALES : BOOL ;
CUENTA_MENOR_UMBRAL_MIN : BOOL ;
END_VAR
VAR
FP_INC : BOOL ;
FP_DEC : BOOL ;
END_VAR
BEGIN
NETWORK
TITLE =CÓDIGO AWL
//NOTASDEAUTOMATIZACION.BLOGSPOT.COM
U #REINICIALIZAR; // COMPRUEBO SI HAY QUE #REINICIALIZAR
SPBN SLT0; // EN CASO CONTRARIO VOY AL SALTO SLT0
R #INCREMENTANDO; // SI ESTOY REINICIALIZANDO NO ESTOY #INCREMENTANDO
R #DECREMENTANDO; // NI #DECREMENTANDO
S #ES_CERO; // LA #CUENTA #ES_CERO
L L#0; // CARGO UN CERO
T #CUENTA; // EN LA #CUENTA
SPA UMBR; // Y SALTO AL CÁLCULO DE UMBRALES

SLT0: U #AJUSTAR; // COMPRUEBO SI HAY QUE #AJUSTAR EL CONTADOR A UN VALOR
SPBN SLT1; // EN CASO CONTRARIO VOY AL SALTO SLT1
R #INCREMENTANDO; // SI ESTOY AJUSTANDO NO ESTOY #INCREMENTANDO
R #DECREMENTANDO; // NI #DECREMENTANDO
L #VALOR_AJUSTE; // CARGO EL #VALOR_AJUSTE
T #CUENTA; // LO TRANSFIERO A LA #CUENTA
SPA CERO; // Y SALTO A LA COMPROBACIÓN DE SI EL CONTADOR #ES_CERO

SLT1: U #INCREMENTAR; // SI EN LA ORDEN DE #INCREMENTAR
FP #FP_INC; // DETECTO UN FLANCO POSITIVO
= #INCREMENTANDO; // ESTOY #INCREMENTANDO

U #DECREMENTAR; // SI EN LA ORDEN DE #DECREMENTAR
FP #FP_DEC; // DETECTO UN FLANCO POSITIVO
= #DECREMENTANDO; // ESTOY #DECREMENTANDO

UN #INCREMENTANDO; // SI NO HAY QUE MODIFICAR LA #CUENTA
UN #DECREMENTANDO;
O( ;
U #INCREMENTANDO;
U #DECREMENTANDO;
) ;
SPB CERO; // SALTO A LA COMPROBACIÓN SI ES CERO

U #INCREMENTANDO; // COMPRUEBO SI ESTOY #INCREMENTANDO
SPBN SLT2; // EN CASO CONTRARIO VOY AL SALTO SLT2
L #CUENTA; // COMO ESTOY #INCREMENTANDO
L L#1; // SUMO UNO A LA #CUENTA
+D ;
T #CUENTA;
U ==0; // COMPRUEBO SI EL RESULTADO #ES_CERO
= #ES_CERO;
SPA UMBR; // Y SALTO AL CÁLCULO DE UMBRALES

SLT2: U #DECREMENTANDO; // COMPRUEBO SI ESTOY #DECREMENTANDO
SPBN UMBR; // EN CASO CONTRARIO VOY AL CÁLCULO DE UMBRALES
L #CUENTA; // COMO ESTOY #DECREMENTANDO
L L#1; // RESTO UNO A LA CUENTA
-D ;
T #CUENTA;
U ==0; // COMPRUEBO SI EL RESULTADO #ES_CERO
= #ES_CERO;
SPA UMBR; // Y SALTO AL CÁLCULO DE UMBRALES

CERO: L #CUENTA; // COMPRUEBO SI LA #CUENTA ES CERO
L L#0;
+D ;
U ==0;
= #ES_CERO;

UMBR: L #UMBRAL_MAXIMO; // SI EL #UMBRAL_MAXIMO
L #UMBRAL_MINIMO; // MENOS EL #UMBRAL_MINIMO
-D ; // ES UNA CANTIDAD NEGATIVA O CERO
U <=0; // LOS UMBRALES ESTÁN MAL ESPECIFICADOS
SPBN SLT3; // EN CASO CONTRARIO VOY AL SALTO SLT3
R #CUENTA_MAYOR_UMBRAL_MAX; // SI LOS UMBRALES ESTÁN MAL ESPECIFICADOS
R #CUENTA_ENTRE_UMBRALES; // TODOS LOS BITS RELATIVOS A LOS UMBRALES
R #CUENTA_MENOR_UMBRAL_MIN; // SE PONEN A CERO
BE ;

SLT3: L #CUENTA; // SI LA #CUENTA
L #UMBRAL_MAXIMO; // MENOS EL #UMBRAL_MAXIMO
-D ; // ES UNA CANTIDAD POSITIVA
U >0;
SPBN SLT4;
S #CUENTA_MAYOR_UMBRAL_MAX; // LA #CUENTA SUPERA EL #UMBRAL_MAXIMO
R #CUENTA_ENTRE_UMBRALES;
R #CUENTA_MENOR_UMBRAL_MIN;
BE ;

SLT4: L #UMBRAL_MINIMO; // SI EL #UMBRAL_MINIMO
L #CUENTA; // MENOS LA #CUENTA
-D ; // ES UNA CANTIDAD POSITIVA
U >0;
SPBN SLT5;
R #CUENTA_MAYOR_UMBRAL_MAX;
R #CUENTA_ENTRE_UMBRALES;
S #CUENTA_MENOR_UMBRAL_MIN; // LA #CUENTA ES MENOR QUE EL #UMBRAL_MINIMO
BE ;

SLT5: SET ;
R #CUENTA_MAYOR_UMBRAL_MAX; // EN EL CASO QUE FALTA
S #CUENTA_ENTRE_UMBRALES; // LA #CUENTA ESTÁ ENTRE LOS UMBRALES MÁXIMO Y MÍNIMO
R #CUENTA_MENOR_UMBRAL_MIN;
BE ;
END_FUNCTION_BLOCK

Este código tiene todo lo que, a mi parecer, se le puede pedir a un contador:
  • Rango de 32 bits.
  • Contaje hacia adelante y hacia atrás.
  • Puesta a cero e indicador de si el contador es cero.
  • Posibilidad de ajustar el valor del contador a un valor predefinido.
  • Umbrales máximo y mínimo para controlar que se encuentra por debajo, por encima, o dentro de un rango.
  • Y salidas que indican si está contando hacia adelante o hacia atrás (para encadenar contadores).

En el ejemplo que ponía antes de una máquina de corte, el uso del contador podría ser como sigue:


Para finalizar esta entrada sobre contadores voy a poner el código de dos contadores más de 32 bits, uno que cuenta hacia adelante y otro hacia atrás. Son versiones más sencillas del contador anterior.

El código del contador incremental es el siguiente:


FUNCTION_BLOCK FB3
TITLE =CONTADOR INCREMENTAL DE 32 BITS
//CUENTA ENTRE -2 147 483 648 Y 2 147 483 647 HACIA ADELANTE
VERSION : 0.1


VAR_INPUT
INCREMENTAR : BOOL ;
REINICIALIZAR : BOOL ;
AJUSTAR : BOOL ;
VALOR_AJUSTE : DINT ;
UMBRAL : DINT ;
END_VAR
VAR_OUTPUT
CUENTA : DINT ;
ES_CERO : BOOL ;
INCREMENTANDO : BOOL ;
UMBRAL_REBASADO : BOOL ;
END_VAR
VAR
FP : BOOL ;
END_VAR
BEGIN
NETWORK
TITLE =CÓDIGO AWL
//NOTASDEAUTOMATIZACION.BLOGSPOT.COM
U #REINICIALIZAR; // COMPRUEBO SI HAY QUE #REINICIALIZAR
SPBN SLT0; // EN CASO CONTRARIO VOY AL SALTO SLT0
R #INCREMENTANDO; // SI ESTOY REINICIALIZANDO NO ESTOY #INCREMENTANDO
S #ES_CERO; // LA #CUENTA #ES_CERO
L L#0; // CARGO UN CERO
T #CUENTA; // EN LA #CUENTA
SPA UMBR; // Y SALTO AL CÁLCULO DE UMBRAL

SLT0: U #AJUSTAR; // COMPRUEBO SI HAY QUE #AJUSTAR EL CONTADOR A UN VALOR
SPBN SLT1; // EN CASO CONTRARIO VOY AL SALTO SLT1
R #INCREMENTANDO; // SI ESTOY AJUSTANDO NO ESTOY #INCREMENTANDO
L #VALOR_AJUSTE; // CARGO EL #VALOR_AJUSTE
T #CUENTA; // LO TRANSFIERO A LA #CUENTA
SPA CERO; // Y SALTO A LA COMPROBACIÓN DE SI EL CONTADOR #ES_CERO

SLT1: U #INCREMENTAR; // SI EN LA ORDEN DE #INCREMENTAR
FP #FP; // DETECTO UN FLANCO POSITIVO
= #INCREMENTANDO; // ESTOY #INCREMENTANDO

U #INCREMENTANDO; // COMPRUEBO SI HAY QUE MODIFICAR LA #CUENTA
SPBN CERO; // EN CASO CONTRARIO SALTO A LA COMPROBACIÓN SI ES CERO
L #CUENTA; // COMO ESTOY #INCREMENTANDO
L L#1; // SUMO UNO A LA #CUENTA
+D ;
T #CUENTA;
U ==0; // COMPRUEBO SI EL RESULTADO #ES_CERO
= #ES_CERO;
SPA UMBR; // Y SALTO AL CÁLCULO DE UMBRAL

CERO: L #CUENTA; // COMPRUEBO SI LA #CUENTA ES CERO
L L#0;
+D ;
U ==0;
= #ES_CERO;

UMBR: L #UMBRAL; // SI EL #UMBRAL
L #CUENTA; // MENOS LA #CUENTA
-D ; // ES UNA CANTIDAD NEGATIVA
U <0; // SE HA REBASADO EL UMBRAL
= #UMBRAL_REBASADO;
BE ;

END_FUNCTION_BLOCK


Y finalmente, el código del contador decremental de 32 bits es este:


FUNCTION_BLOCK FB4
TITLE =CONTADOR DECREMENTAL DE 32 BITS
//CUENTA ENTRE -2 147 483 648 Y 2 147 483 647 HACIA ATRÁS
VERSION : 0.1


VAR_INPUT
DECREMENTAR : BOOL ;
REINICIALIZAR : BOOL ;
AJUSTAR : BOOL ;
VALOR_AJUSTE : DINT ;
UMBRAL : DINT ;
END_VAR
VAR_OUTPUT
CUENTA : DINT ;
ES_CERO : BOOL ;
DECREMENTANDO : BOOL ;
UMBRAL_REBASADO : BOOL ;
END_VAR
VAR
FP : BOOL ;
END_VAR
BEGIN
NETWORK
TITLE =CÓDIGO AWL
//NOTASDEAUTOMATIZACION.BLOGSPOT.COM
U #REINICIALIZAR; // COMPRUEBO SI HAY QUE #REINICIALIZAR
SPBN SLT0; // EN CASO CONTRARIO VOY AL SALTO SLT0
R #DECREMENTANDO; // SI ESTOY REINICIALIZANDO NO ESTOY #DECREMENTANDO
S #ES_CERO; // LA #CUENTA #ES_CERO
L L#0; // CARGO UN CERO
T #CUENTA; // EN LA #CUENTA
SPA UMBR; // Y SALTO AL CÁLCULO DE UMBRAL

SLT0: U #AJUSTAR; // COMPRUEBO SI HAY QUE #AJUSTAR EL CONTADOR A UN VALOR
SPBN SLT1; // EN CASO CONTRARIO VOY AL SALTO SLT1
R #DECREMENTANDO; // SI ESTOY AJUSTANDO NO ESTOY #DECREMENTANDO
L #VALOR_AJUSTE; // CARGO EL #VALOR_AJUSTE
T #CUENTA; // LO TRANSFIERO A LA #CUENTA
SPA CERO; // Y SALTO A LA COMPROBACIÓN DE SI EL CONTADOR #ES_CERO

SLT1: U #DECREMENTAR; // SI EN LA ORDEN DE #DECREMENTAR
FP #FP; // DETECTO UN FLANCO POSITIVO
= #DECREMENTANDO; // ESTOY #DECREMENTANDO

U #DECREMENTANDO; // COMPRUEBO SI HAY QUE MODIFICAR LA #CUENTA
SPBN CERO; // EN CASO CONTRARIO SALTO A LA COMPROBACIÓN SI ES CERO
L #CUENTA; // COMO ESTOY #DECREMENTANDO
L L#1; // RESTO UNO A LA #CUENTA
-D ;
T #CUENTA;
U ==0; // COMPRUEBO SI EL RESULTADO #ES_CERO
= #ES_CERO;
SPA UMBR; // Y SALTO AL CÁLCULO DE UMBRAL

CERO: L #CUENTA; // COMPRUEBO SI LA #CUENTA ES CERO
L L#0;
+D ;
U ==0;
= #ES_CERO;

UMBR: L #UMBRAL; // SI EL #UMBRAL
L #CUENTA; // MENOS LA #CUENTA
-D ; // ES UNA CANTIDAD POSITIVA
U >0; // SE HA REBASADO EL UMBRAL
= #UMBRAL_REBASADO;
BE ;


END_FUNCTION_BLOCK

No me he parado a explicar en detalle su funcionamiento, pero creo que siguiendo los comentarios se entienden perfectamente.

8 comentarios:

  1. Excelente articulo

    Lo incorporo a mi libreria de funciones

    Un saludo

    ResponderEliminar
  2. excelente, sigue contando...y aportando...

    gracias

    ResponderEliminar
  3. Como siempre un buen articulo!!!
    Saludos
    JM

    ResponderEliminar
  4. Muchas gracias, funciona a la perfeccion.

    ResponderEliminar
  5. Saludos:
    Muy bueno tu artículo, gracias, soy nuevo en esto de la programación con step 7 lo básico ya lo se hacer, se me pidió hacer un contador de objetos y que cuando llegara a 10 se detuviera, el aranque es fácil pero el contador no me salía encontré tu bloc y me pareció muy bueno pero lo quiero probar y no me me funciona me marca error el PLC me puedes orientar en como declarar el nombre del contador y que hay que hacer

    ResponderEliminar
  6. buenas,esta muy buena la explicacion pero a mi me sale un error de sintaxis cuando lo compilo. ahora luego que compilo sino me sale ningun error ,como hago para que me salga el bloque del contador ? yo supongo que a los que les sale el bloque del contador al darle click,visualizar me imagino que sale todo el codigo en awl de ese bloque .corrijanme si me equivoco por fa

    ResponderEliminar

Por favor, no pidas copias de programas comerciales, licencias o números de serie.