Esta semana la entrada va a ser corta pero espero que interesante sobre el filtrado y enmascarado de bits.
Recientemente me he visto en la necesidad de realizar lo siguiente: tengo una serie de alarmas de una máquina A, y quiero pasar una única señal booleana a otra máquina B por profibus que indique que hay una alarma activa en la máquina A.
Podríamos hacer un OR bit a bit, pero sería un poco hacerlo a lo burro. Porque si son unas pocas bien, pero como sean unas cuantas el OR va a ser como la torre de Iberdrola de Bilbao (hay que tirar para casa).
Hasta ahí ningún problema. Las alarmas comienzan imaginemos en la M32.0 y terminan en la M37.7. Con ir haciendo OR de palabras seria suficiente.[divider]
Contenido
Cómo saber si hay una alarma activa (usando todas las alarmas)
SET –> Pongo a uno el RLO
R M100.0 –> Resteo el valor de la marca M100.0 que es la que voy a mandar a la máquina B. Inicialmente no hay alarma.
L MW32 –> Leo los primeros 16 bits
L MW34 –> Leo los siguientes 16 bits
OW –> Hago un OR de palabra con lo cual el resultado cargará en el ACU1 todos los bits que estén a uno haciendo OR bit a bit
L MW36 –> Cargo los útimos 16 bits
OW –> Hago un OR entre el contenido del ACU1 y la MW36 y lo transfiero nuevamente al ACU1
L 0 –> Cargo un cero en el ACU1 y por tanto el resultado del OR pasa al ACU2
==I –> Hago una comparación entre el cero del ACU1 y el contenido del ACU2
SPB EXIT –> Si es cero (el RLO está a 1), salto y no hago nada
SET –> Pongo el RLO a uno
S M100.0 –> Pongo a uno la marca M100.0 que será la que envíe a la máquina B
EXIT: NOP 0[divider]
¿No valdría con sumar y ya está?
Otra aparente fácil solución sería usando la misma estructura:
SET
R M100.0
L MW32
L Mw34
+I
L MW36
+I
L 0
<>0
SPB EXIT
SET
S M100.0
EXIT NOP 0
Tanto rollo con low OW… una suma y listo…[divider]
Ummmm en general sí…. en particular… no.
Este último ejemplo funcionará CASI siempre.[divider]
¿Descubres la razón?
Es realmente sencillo. Estamos sumando valores enteros…pero pueden ser positivos o negativos. Por tanto, en general funcionaría pero al hacer la suma, puede haber valores que hagan que MW32+MW34+MW36 = 0 ya que estos valores pueden tomar valores positivos o negativos.
El ejemplo de comparar con cero valdría si por ejemplo son 16 alarmas. Ahí no habría problema ya que no hay sumas, ni restas ni comparaciones ni nada de nada. Lo comparas con cero, y si no es cero, es que hay una alarma tocando los coj.. que hay una alarma activa.[divider]
Filtrado y enmascarado de bits
Vale. Ya hemos visto como podríamos saber si hay una alarma activa teniendo en cuenta todas las alarmas.
Pero imaginemos que no es el caso. Quiero pasar todas las alarmas salvo media docena que son alarmas que no interfieren con el proceso de la máquina B y por tanto no las quiero enviar.[divider]
Vale. ahora sí que sí hago un cojo-OR eligiendo los bits.
Hombre… no. Son unas cuantas.
Imaginemos que no queremos tener en cuentas los bits: 32.1, 35.7, 36.0, 36.1, 36.2 y 37.3 (por poner un ejemplo).
El primer método está claro que no me sirve. Las sumas, mucho menos… hacer un OR de cada bit dejando estas sin meter es un poco remedio básico… y aquí queremos ser los más chulos del barrio programando S7.[divider]
¿Cómo lo hacemos?
Pues creando máscaras… a que ahora entiendes que pinta Dar Vader en todo esto ¿eh?
Pero son máscaras de otro tipo: enmascarado de bits.
Vale, la idea es sencilla: crear un grupo de bits que sean los bits que nos queremos quedar y hacer un AND con las señales de tal forma, que el AND resultante, si es distinto de cero, es porque hay alarma.
Ejemplo:
Imagina que tienes la M32.1 y la M32.3 a uno y el resto del byte está a cero ¿Ok? Tendríamos que
MB32 = 0 0 0 0 1 0 1 0
¿sí? Sólamente el bit 1 y 4 empezando por la derecha sería unos (los 0.1 y .3 ya que empezamos en .0), y se lee de derecha a izquierda.
Vale. ¿Cómo podemos saber que hay una alarma descartando el M32.1 como queremos?
Pues haciendo un AND con el siguiente byte:
MB32 = 0 0 0 0 1 0 1 0
Mascara = 1 1 1 1 1 1 0 1
Resutado = 0 0 0 0 1 0 0 0
¿No se te eriza el bello?
Ya claro… pero ¿cómo cargo el enmascarado de bits? porque si tengo que calcular cuanto es el el resultado de cada máscara en decimal pasándolo de binario, me dan las uvas… pero está claro que no del 2013.
Muy fácil. Así:
L MB32 –> Cargo el primer byte
L 2#1 1 1 1 1 1 0 1 –> Cargo en binario mi número usando base 2.
Vale. Deja ya de aplaudir y prosigamos… que ahora estarás conmigo que es trivial:[divider]
SET
R M100.0 –> Como antes empezamos reseteando la señal
L MB32 –> Cargamos el primer byte
L 2#1 1 1 1 1 1 0 1 –> Cargamos el enmascarado de bits para el byte 32
UW –-> Hacemos el AND
L MB33 –> Cargamos el Byte 33
OW –> Hacemos un OR entre el resultado y el byte 33 que no hay que filtrar
L MB34 –> Cargamos el byte 34
OW –> Hacemos un OR entre el resultado del OR y el byte 34 que no hay que filtrar
T MW20 –> Una marca intermedia ya que vamos a necesitar almacenar el resultado
L MB33 –> Cargamos el byte 35
L 2#0 1 1 1 1 1 1 1 –> Cargamos la máscara para despreciar el 35.7
UW –> Hacemos el AND para quedarme con todo menos con el 35.7
L MW20 –> Cargamos el resultado hasta ahora
OW –> Hacemos un OR con el resultado
T MW20 –> Lo transferimos a la marca intermedia nuevamente
L MB36 –> Cargamos el Byte 36
L 2#1 1 1 1 1 0 0 0 –> Cargamos la máscara para el 36.0, 36.1 y 36.2
UW –>Realizamos el enmascarado de bits
L MW20 –> Cargamos lo que tenemos hasta ahora
OW –> Hacemos un OR
L MB 37 –> Cargamos el último byte
L 2#1 1 1 1 0 1 1 1 –> Cargamos la máscara del 37.3
UW –> Realizamos el enmascarado de bits
L MW20 –> Cargamos el temporal
OW –> Hacemos un OR
T MW20 –> Hacemos la última transferencia al MW20
L MW20 –> Cargamos el temporal con el resultado
L0 –> Cargamos un cero
==I –> Los comparamos
SPB EXIT -> Si el MW20 = 0, saltamos al final ya que no hay alarmas.
SET
S M100.0 –> Si no es cero, ponemos la señal de alarma a 1.
EXIT: NOP 0[divider]
¿Se podría hacer con words en vez de con bytes?
La respuesta es sí, pero no te lo recomiendo ya que vas a tener que manejar 16 cero o unos y además recuerda que hay que poner de derecha a izquierda los bits y primero el byte bajo y luego el byte alto … igual te lias un rato.
Son más instrucciones que con words, pero mucho más claro y mantenible sin llegar a tener que poner un OR de todos los bits cada uno por separado. En racimos de 8 creo que es razonable.[divider]
¿Y el vídeo del enmascarado de bits?
Esta semana, no hay vídeo. Quiero que repases esta teoría y lo practiques. Te va a ser útil el que le des unas cuantas vueltas al tema de los bits.
[divider]
¿Qué te ha parecido?
Espero que lo hayas visto útil. Si no es para esta aplicación seguro que tendrás en algún momento hacer un enmascaramiento como ya vimos por ejemplo con el display de 7 segmentos
Por otro lado voy dejando caer el tema de los saltos. En este caso sólo uno de los casos, que es el SPB que es el saltar hasta una meta dada si el RLO = 1. Vermos todos en su momento.
Como siempre invitarte a que te des una vuelta por masvoltaje.com si tienes que comprar algo de material eléctrico y que uses los cupones que hay en el foro ya que te valdrá para hacerte un descuento.
[divider]
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.
10 Comentarios
Gracias por la teoria, es fantastica la forma que tienes de pensar.
Buenísimo este post, muy útil y muy bien explicado. En general todo el blog me parece genial. Aunque a la hora de crear tus programas, suelo diferir bastante con la manera de hacerlos, siempre encuentro cosas útiles que me conviene repasar. Un blog muy recomendable para gente que intentamos abrirnos paso en este mundillo.
Espero que siga activo por mucho tiempo, un saludo y gracias por tu tiempo.
Hola Iñigo necesito una mano, como proyecto final tengo que hacer una señal senoidal con el PLC y monitorearla en Wincc, podrias hecharme una mano con eso, por donde empezar _??
Es bastante fácil.
Recuerda la formula: Y = A* SIN (t*2*PI/360)
Donde:
A = constante = Amplitud de la señal.
Y= MW20 (por poner un ejemplo).
t = tiempo, tomado por ejemplo cada 100 ms de tal forma que tengas un ciclo completo cada 3,6 segundos.
Es decir, en el OB35 haces que t vaya sumando y cuando llegue a 28800 (80 ciclos completos). Luego lo pones a cero. Deberia ser suficiente como ejemplo
Luego graficas la señal MW20.
Espero que te sirva de orientación.
¡Hola!Felices fiestas. He estado haciendo este ejercicio del enmascarado y he copiado literalmente el programa, pero he tenido que corregir un par de cosas para que me funcionara. El byte MB33 por MB35 en la 11ª instrucción y añadir «TMW20» en la 22ª instrucción. Por lo demas, me parece una manera muy practica para trabajar con muchas alarmas. Yo la verdad hasta ahora siempre las hacía OR bit a bit y era bastante latoso la verdad cuando tenía muchas. Gracias por compartir tus conocimientos a traves de la web Iñigo.
SET
R M 100.0
L MB 32
L 2#11111101
UW
L MB 33
OW
L MB 34
OW
T MW 20
L MB 35
L 2#1111111
UW
L MW 20
OW
T MW 20
L MB 36
L 2#11111000
UW
L MW 20
OW
T MW 20
L MB 37
L 2#11110111
UW
L MW 20
OW
T MW 20
L MW 20
L 0
==I
SPB exit
SET
S M 100.0
exit: NOP 0
Buena guía de aprendizaje, los errores que contiene la explicación sirven para los que revizamos el ejercicio. Excelente!
muy buena entrada gracias iñigo
Me ha faltado un video para ver la practica y como manejarlo , asi cuesta de entender es muy lioso, pero se agradecen tu blog ayuda bastante
L 2#0001111111111111
Buen día Iñigo
quiero cargar esta marca y me borra los ceros, en Step 7
Los ceros a la izquierda en binario, no valen para nada. Puedes poner 3, o 300, que da igual.