LÓGICA DIGITAL
Y ALGEBRA DE BOOL
En la sesión anterior presentamos el tipo de variable bool destacando
que solo puede tomar dos valores: True o False. Aunque para quienes no
estén acostumbrados al algebra booleana o binaria puede parecer excesivo
dedicar un tipo a algo tan simple, en la práctica buena parte de las
instrucciones de programación se apoyan o dependen de este tipo de variables.
La razón práctica es que con frecuencia hay que tomar
decisiones para seguir un camino u otro en función de que se cumpla una
condición dada; Esta condición se debe evaluar necesariamente, a True
o False para tomar una decisión sin duda posible.
Por ejemplo, en las sesión 4 usamos la instrucción for
y comentamos que la iteración se mantiene mientras se cumpla una
cierta condición. Esta condición debe ser evaluable a True o False, es
decir es un booleano.
Existen otras muchas instrucciones que se apoyan en los valores
booleanos, (como los condicionales if que veremos en esta sesión) pero en
un modo muy explicito toda la computación actual se basa en la lógica digital
de solo dos valores que solemos llamar 1 y 0, pero que con todo derecho podemos
llamar a estos valores True y False.
Los ordenadores modernos funcionan mediante la aplicación
del algebra de bool a variables booleanas y con un juego completo de operadores
lógicos como la negación, que vimos en la sesión anterior, mas operadores
lógicos como AND, OR, + y – .
LA INSTRUCCIÓN
IF
En este capítulo vamos a presentar unas instrucciones nuevas
de C++, que nos permitan tomar decisiones para hacer una cosa u otra.
La instrucción if es muy sencilla de usar, basta con pasarle
entre paréntesis una variable o condición que se evalúe a true o false. Si el
resultado es true se hace el bloque que viene a continuación y en caso
contrario se ejecuta el bloque que hay detrás del else si existe.
Si no existe la clausula del esle, entonces el bloque que
sigue al if, se ejecuta o no, en función de la condición y luego sigue con la
secuencia de instrucciones a continuación.
if ( condición)
{
instrucción 1 ;
instrucción 2 ;
................
}
else
{
instruccion20 ;
instruccion21 ;
..............
}
Recordemos que en el circuito de la sesión anterior
disponíamos de un pulsador y de un LED, en esta sesión vamos a continuar con el
mismo circuito y para conseguir que el LED se encienda o apague al pulsar el
botón. Para ello podríamos mantener la misma función setup() y escribir
el loop() diferente:
void
loop()
{
bool valor = digitalRead(boton) ;
if ( valor)
digitalWrite( LED, HIGH) ;
else
digitalWrite( LED, LOW) ;
}
·
Leemos primero el botón a una variable bool y
después decidimos si encender o apagar el LED dependiendo de qué su valor sea
True o False.
·
Recordemos que un bloque es un conjunto de
instrucciones encerrados entre llaves y que hay un caso particular en el que se
pueden omitir si y solo si, el bloque consta de una única instrucción como es
nuestro caso.
·
Se puede utilizar una instrucción if omitiendo
la cláusula de else si se desea, pues esta es opcional.
VOLVIENDO CON
LOS BOTONES
Vamos con un programa diferente. Queremos que el botón actúe
como un interruptor, que al pulsarlo una vez se encienda, y la próxima vez lo
apague. Podríamos plantear algo así y os recomiendo que lo probéis en vuestro
Arduino:
int LED
= 10 ; int boton = 6 ;
bool
estado = false ;
void
setup()
{
pinMode( LED, OUTPUT) ;
pinMode( boton , INPUT_PULLUP) ;
digitalWrite(LED , LOW) ; // Apagamos el LED al empezar
}
void
loop()
{
bool
valor = digitalRead(boton) ;
//leemos el botón: false = LOW
if ( valor
== false )
// esto es que han pulsado el botón
{
estado = ! estado
;
// cambiamos el estado
digitalWrite(LED,
estado) ; //
escribimos el nuevo valor
}
}
La idea es definir una variable llamada estado al principio
para guardar la situación del LED. El loop comprueba si se ha pulsado el botón,
y de ser así invierte su estado, y después escribe el valor de estado en
el LED. Si estaba encendido lo apaga. Si estaba apagado se enciende.
Aunque parece un plan perfecto, en la práctica no va a
funcionar. En el tiempo que nosotros tardamos entre pulsar y liberar el botón,
nuestro humilde Arduino es capaz de leer unos cuantos miles de veces el
pulsador e invertir el valor del LED otras tantas.
Por eso, si lee un número par de veces dejara el LED como
estaba y si lo lee un número impar de veces lo invertirá. En la práctica la
situación del LED se torna aleatoria, y si pulsáis repetidamente el botón
veréis que el resultado es impredecible.
Otra fuente de problemas es que en el mundo real un
interruptor no cambia de un estado a otro de forma perfecta, sino que suele
rebotar y causar varios conexiones y desconexiones muy rápidas antes de quedar
en un valor estable. A esto se le llaman rebotes (bouncing) y al procedimiento
para eliminar estos rebotes se le llama debouncing en la jerga electrónica.
El debouncing se puede hacer por hardware con un conjunto de
resistencia y condensador, o por software, mucho más frecuentemente (por más
barato) y para esto una solución es nuevamente frenar a Arduino y hacerle
esperar un tiempo entre 50 y 250 mili-segundos una vez que detecta que se ha
pulsado el botón, de modo que nos dé tiempo a liberar el pulsador:
void
loop()
{
bool valor = digitalRead(boton) ;
//leemos el botón: false = LOW
if ( valor == false )
// esto es que
han pulsado el botón
{
estado = ! estado
; //
cambiamos el estado
digitalWrite(LED, estado)
; // escribimos el
nuevo valor
delay(250) ;
}
}
·
Muy importante: Nótese que la condición es
(valor == false), con doble = . En C++ la comparación de dos valores usa ==, la
asignación de valor a una variable solo uno. Esto es fuente de errores
frecuentes al principio (entre novicios inexpertos).
Este lapso de 250 ms es suficiente para pulsar y liberar el
botón cómodamente. Si probáis esta variante veréis que ahora el LED invierte su
valor cada vez que pulsas, siempre y cuando no te demores demasiado en liberar
el botón.
Pero… ¿Qué pasa cuando dejas el botón pulsado?
Pues sencillamente que el LED invierte su estado cada 250 ms
(milisegundos) y tenemos otra variante del blinking LED.
Si queremos poder mantener pulsado sin que se produzca este
efecto hay que sofisticar un poco más el programa:
int LED
= 10 ; int boton = 6 ;
bool
estado = true ;
bool
estado_anterior = true ;
void
setup()
{
pinMode(boton, INPUT_PULLUP);
//Hemos eliminado R3
pinMode(LED, OUTPUT);
}
void
loop()
{
estado = digitalRead(boton);
if (estado != estado_anterior)
//hay cambio : Han pulsado o soltado
{
if (estado == LOW) //Al
pulsar botón cambiar LED, pero no al soltar
digitalWrite(LED,
!digitalRead(LED));
estado_anterior = estado ; //
Para recordar el ultimo valor
}
}
Ya dijimos que para comprobar si dos valores son iguales
usamos ==, Para comprobar si son diferentes usamos != , y existen otros
operadores relacionales
·
Igual que: ==
·
Distinto de: !=
·
Mayor que: >
·
Mayor o igual: >=
·
Menor que: <
·
Menor o igual: <=
Vale la pena comentar aquí que, a pesar de su aparente
inocencia, los botones tienen una sorprendente habilidad para complicarnos la
vida, y que en la práctica la combinación de rebotes y la necesidad de
corregirlos, junto al uso de pullups que garanticen la correcta lectura, pueden
hacer que su uso se pueda complicar mucho más de lo que parece, sino se estudia
el problema con calma.
Por último, una condición lógica se puede construir mediante
los operadores lógicos AND, OR, y NOT cuyos símbolos son respectivamente:
&&, || y !
Si usáramos un circuito dos pulsadores con pullups (True, si
no se pulsa) y un LED, dependiendo del comportamiento que se busque podemos
especificar diferentes condiciones:
·
If ( boton1 && boton2) Que ambos botones
estén sin pulsar
·
If ( !( boton1 && boton2)) Que ambos
estén pulsados.
·
If( boton1 || boton2 ) Que al menos uno este sin
pulsar, o ambos.
RESUMEN DE LA
SESIÓN
·
Hemos visto la instrucción if / else.
·
Vimos varios programas con pulsadores y como
hacer el debouncing.
·
Hemos presentado los operadores lógicos de
relación y comparación.
·
Continuamos escribiendo pequeños programas para
desarrollar la forma de pensar necesaria para escribir nuestras propias
aplicaciones.
Comentarios
Publicar un comentario