bclose

Condicionales y botones

La instruccion if

Objetivos

.

 
    • Lógica digital y algebra de Bool.
    • Los condicionales.Instrucción if.
    • Botones, pulsadores y pullups.
    • Debouncing.

 

Material requerido.

 

  Tienda España Tienda Mexico
Kit Arduino Uno  Kit inicio UNO Kit inicio UNO
Kit Arduino MEGA Kit Inicio Mega Kit Inicio Mega

 

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.

 

 

 

 

Para porder realizar consultas a nuestros expertos, tienes que ser suscriptor. Suscribiendote nos ayudas a mantener este proyecto en marcha.

¡ Quiero Suscribirme !

Si ya eres premium y no puedes comentar haz login. Hacer login

(145) Comments

  • Avatar for Charly
    • Ivan Uriarte

    Hola, si te fijas el programa sólo comprueba el pulsador al principio de la secuencia, luego si lo tocas en medio no se entera. Puedes intercalar ese if entre la secuencia o trabajar con interrupciones, que es ya un poco más lío.

  • Avatar for Charly
    • Marcos

    Buenas tardes!
    He instalado un pulsador con 3 Blinkin LEDs alternantes, y a la hora de iniciar la secuencia va perfecto. El problema es que una vez inicio el loop de blinks, para detenerlo, a menos que mantenga pulsado el pulsador hasta que coincida con el final de la secuencia de loop o que pulse exactamente en el mismo final, no se apaga el circuito.
    No sé si me estoy explicando… básicamente, no me recoge el INPUT del pulsador hasta que no termina la secuencia entera programada de ejecutarse al completo. Y solo lo acepta si intercalo ese INPUT entre loop y loop. ¿Qué estoy haciendo mal?

    Os dejo el programa que estoy utilizando:
    int boton = 12 ;
    int LED1 = 6 ;
    int LED2 = 7 ;
    int LED3 = 8 ;
    bool estado = false ;

    void setup() {
    // put your setup code here, to run once:
    pinMode ( boton , INPUT ) ;
    pinMode ( 6 , OUTPUT );
    pinMode ( 7 , OUTPUT );
    pinMode (8, OUTPUT);
    digitalWrite(6,LOW);
    digitalWrite(7,LOW);
    digitalWrite(8,LOW);
    }

    void loop() {
    // put your main code here, to run repeatedly:
    bool valor = digitalRead ( boton ) ;//PULLUP
    if ( valor == false ) //pulsado boton
    {estado = !estado ;
    delay(500);}

    if ( estado == true)
    { digitalWrite(LED1,HIGH);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,HIGH);
    delay(500);
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED3,LOW);
    delay(500);}
    else
    digitalWrite(LED1,LOW);
    digitalWrite(LED2,LOW);
    digitalWrite(LED3,LOW);
    }

  • Avatar for Charly
    • Ivan Uriarte

    Hola José Antonio, depende uin poco cómo hayas progrtamado el cronómetro, pero en teoría con que metas en el loop un conidicional if en el que leas el botón y dentro sumes 1 a la variable minutos, o 60 a la variable segundos debería ser suficiente.

  • Avatar for Charly
    • Jose Antonio

    Buenos días.
    Tengo una consulta, estoy intentando realizar un cronómetro descendente (el código del cronometro ya lo tengo hecho y funciona), pero quiero poder aumentar los minutos antes de que empiece la cuenta, para poder personalizarlo. Estoy intentando hacerlo basándome en lo que usted ha publicado, para que cuando se pulsa el botón minutos se aumente en 1, pero me estoy volviendo loco, no se si sería tan amable de ayudarme.
    Gracias.
    Saludos.

  • Avatar for Charly
    • Juan carlos macho mangas

    Hola Salvador, depende un poco del tipo de secuencia que estes usando, pero si es un for que empieza en un valor digamos cero, puedes hacerle empezar desde una variable p, que controlas cuando quieres empezar a meda secuencia ¿Vale?

  • Avatar for Charly
    • Salvador

    Hola, si tengo leds que prendenen una secuencia y al presionar un boton se inicie la secuencia y al volverlo a presionar, se quede encendido el led en el momento que se presiono el boton y que al presionar otra vez continue la secuencia donde la paramos, ¿que haria para parar y continuar la secuencia?

  • Avatar for Charly
    • Juan carlos macho mangas

    Hola Zoe, Tienes un ejemplo en los tutos de como hacer un receptor a distancia con mando infrarrojo y el emisor es muy similar

  • Avatar for Charly
    • Zoé Rendón

    Hola, tengo un enorme problema:
    Quiero que al presionar un un botón un LED infrarrojo emita una señal a un fototransistor, estoy tratando de hacer un mando a distancia, no se nada de programación :(, me encontré en la librería de IRremote un ejemplo para el protocolo Sony (IRsendDemo) y es el mismo que viene en tutoriales pero no logro que al presionar el botón el led mande la señal. Te agradecería mucho que me ayudaras con el código, estoy muy desesperada :(.
    Te deje una imagen de como tengo la conexión del led infrarrojo

  • Avatar for Charly
    • Ivan Uriarte

    Gracias por el aporte Alexius.

  • Avatar for Charly

    Si quieres que al pulsar n veces solamente cuenta n veces que pulsas el botón y con un condicional puedes hacer que se encienda el led ejemplo
    Int numero_de_pulsaciones;
    Bool boton_pulsado = 0;
    Bool led_encendido = 0;
    If((boton_pulsado == 1)&&(led_encendido == 0)){
    Numero_de_pulsaciones++;
    Int n;
    Const int buffet_de_pulsaciones = 100;
    N = número_de_pulsaciones%2;
    If(numero_de_pulsaciones == n){
    Led_encendido = 1;
    }Else{ led_encendido = 0;}
    If(numero_de_pulssciones == buffer_de_pulsaciones)
    Numero_de_pulsaciones == 0;
    }
    Espero que te sirva este ejemplo que solo encenderá en números pares

  • Avatar for Charly
    • Ivan Uriarte

    Hola Antonio, mete dentro del primer condicional un contador, es decir una variable en la que sumes 1 cada vez que hayas pulsado el botón. Y dentro de ese condicional mete otro anidado en el que compares la variable con el número de pulsaciones que buscas. Cuando se cumpla enciende el LED y pon a 0 la variable. Un saludo.

  • Avatar for Charly
    • Antonio

    Hola
    Nesesito ayuda
    Quiero prender un led presionando (n) veces el push button.

  • Avatar for Charly
    • Ivan Uriarte

    Hola José, lo primero fíjate si tienes el pulsador montado en pull-up o en pull-down. y después es mejor que utilices una condición como está para leer el estado del interruptor que quieres montar (en este caso con la resistencia pull-up)

    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) ;
    }

    De ahí no tienes más que leer si estado está a HIGH y entonces leer el sensor. Un saludo.

  • Avatar for Charly

    hola, tengo un pequeño código para intentar hacer funcionar o empezar el estado de lectura de un sensor PIR. Lo que quiero hacer con esto es que si el botón esta en Alto, se coloca el digitalRead del sensor pero cuando presiono el botón es como si el sensor no detectara nada
    Nota: uso 2 leds uno para saber que el botón esta en alto y otro para saber si el sensor esta en alto también (el led del sensor nunca prende).

    int estado =0; //guarda el estado del boton 
    int salida =0; // 0 = LED apagado / 1 = LED prendido
    int estadoant =0;

    void setup() {
    pinMode(2, INPUT); //boton Simple
    pinMode(3, OUTPUT); //LED del Boton (indica que el boton funciona)
    pinMode(5,OUTPUT); //LED del PIR (indica que el PIR detecta)
    pinMode(4,INPUT); //PIR
    }

    void loop() {

    estado = digitalRead(2);

    if ((estado ==HIGH) && (estadoant ==LOW)) { //condicional para el boton precionado leido

    digitalRead(4);

    salida = 1 – salida;

    delay(10);

    if (4 ==HIGH) {
    digitalWrite(5,HIGH);
    delay(50);
    digitalWrite(5,LOW);
    }
    else {
    digitalWrite(5,LOW);
    }

    }

    estadoant = estado; //guardamos el valor actual

    if(salida ==1) { //Estado esta en alto
    digitalWrite(3,HIGH); //prende el led
    }

    else {
    digitalWrite(3,LOW); //De lo contrario lo apagamo
    }

    }

  • Avatar for Charly
    • Ivan

    Hola Luis, para conectar los pulsadores hay que conectarlos por medio de una resistencia, en forma de pull-up o pull-down. Échale un ojo a esta sesión donde lo explicamos. https://www.prometec.net/entradas-digitales/
    Un saludo.

  • Avatar for Charly
    • Luis Melo

    Hola, necesito ayuda para crear un codigo, tengo 2 pulsadores, uno NA y uno NC, los cuales activan una salida del arduino, ejemplo:
    Si presiono el NA, se activa la salida
    Si presiono el NC, se apaga la salida
    Intente con un par de codigos, pero funcionaba cuando queria, tambien queria saber como irian conectados los pulsadores, yo los tengo conectados de la siguiente forma, un extremo del pulsador a los 5V del arduino y el otro extremo a una entrada del arduino y el otro pulsador esta conectado de la misma manera, esta bien?, ojala puedan ayudarme, saludos.

  • Avatar for Charly
    • Chopi

    Muy interesante el tema, gracias

  • Avatar for Charly
    • Ivan

    Hola Rodrigo, controlar una tira de leds desde el arduino es bastante sencillo, se manejan igual que un diodo rgb normal.

    Para activar o desactivar estos efectos deberías usar el pulsador como un interruptor, como hacemos en esta sesión y activar o desactivar todo en función del estado de la variable.

  • Avatar for Charly
    • Ivan

    Hola Rodrigo, la verdad es que no tengo mucha idea de guitarras, o al menos de cómo son por dentro, yo soy más de batería y bajo jejeje. Lo del kill switch supongo que no deberia ser más que poner un pulsador en la o las línea por la que vaya el sonido y que al pulsarlo se abra. Lo del efecto lo-fi y las itinerancias de led no estoy muy seguro de entender qué es. Voy a ver si lo miro un poco, o si no si pudes explícamelo un poco. Un saludo.

  • Avatar for Charly
    • Rodrigo

    Si, lo es. Pero ademas queiro poner un efecto, para lo cual necesito un boton on-off qur actie el efecto y ademas unos led en los que estoy trabajando, todo esto es con botones arcade. supongo que no habria problema ya que el nivel elecrtico que produce el mic de la guitarra es muy bajo (bajo 1V) y la arduino es de 3.3V y/o 5V (ocupo una mini) por lo cual no debería tener problemas.

    saludos y gracias

Para porder realizar consultas a nuestros expertos, tienes que ser suscriptor. Suscribiendote nos ayudas a mantener este proyecto en marcha.

¡ Quiero Suscribirme !

Si ya eres premium y no puedes comentar haz login. Hacer login