Condicionales y pulsadores

 

  • Veremos un sencillo pulsador de entrada y sus caracteristicas.
  • Presentaremos los circuitos Pull up y Pull down y porque son necesarios.
  • Mostraremos como leer una entrada digital GPIO de la Raspberry Pi.
  • Presentaremos el Cobbler.
  • Escribiremos un programa sencillo que lea el estado de un pulsador desde nuestra Raspberry. [/three-fourth] [clear/]
  •  

     Material requerido.

    Vista mayor Raspberry Pi 3 o equivalente
    Img_3_4 Una Protoboard.
    componente Un diodo LED.
    Img_5_1  Un pulsador.
    Img_3_6 Algunos cables de Protoboard..

    Raspberry Pi y los pulsadores.

     

    En capítulos previos hemos visto cómo usar los GPIO de nuestras Raspberry Pi para activar señales digitales al exterior, como por ejemplo encender o apagar un LED. Es decir hemos visto cómo usar los GPIO como puertas de salida digitales.

    En este capítulo vamos ver cómo usar los GPIO para leer señales digitales del exterior, es decir usarlas como entradas digitales, y para ello nada mejor que ver cómo podemos hacer para leer un humilde pulsador digital.

    Estos pulsadores son de lo más sencillos y simplemente pueden adoptar dos estados posibles abiertos cuando no están pulsados y cerrados cuando lo están.

    Aparentemente nada hay más inocente que un pulsador, pero pronto iréis viendo que estos componentes son diabólicos y consiguen marearte con una facilidad que suele sorprender a los novicios despistados. Pero hacedme caso. La capacidad de un humilde pulsador para generarte dolores de cabeza es proverbial.

    Aunque parecen componentes inocentes, pueden marearte de mil formas distintas y por eso procuraremos ir viendo paso a paso alguno de los problemas típicos que aparecen y también las soluciones clásicas para evitar discos problemas

    Esta sesión va, pues, de cómo leer señales del exterior y de paso como vamos a usar un pulsador para generar esas señales a leer, ver cómo usarlos con un mínimo de problemas.

     

    Hablemos de pulsadores

     

    Cuando un pulsador se activa, lo normal es que cierre un circuito y si el otro extremos está conectado a digamos tensión, leemos ese valor, y consideramos un HIGH en la lectura.

    Esquema de pulsador

    Muchos de estos pulsadores que podemos encontrar en el mercado disponen de un par de contactos unidos internamente, como en la imagen que os pongo arriba. Al pulsar el contacto el circuito se cierra y con nuestra Raspberry podemos leer el valor que hay en RPI, para reconocer que el botón ha sido activado. Tenemos una medida clara de tensión alta o Vcc.

    Hasta aquí no hay problema, pero ¿Qué pasa cuando dejas de pulsar el botón? Como el contacto está abierto no leemos tensión y por tanto suponemos que la lectura es 0V o tensión Low.

    Pero queridos amigos, este es uno de esos casos en los que suponer cosas puede marearte porque lo que leemos en el caso de pulsador abierto no tiene por qué ser 0. Es lo que en la jerga llamamos contacto flotante y su valor de lectura es imprevisible y poco más o menos aleatorio.

    ¿Te resulta difícil de creer? Claro, porque todos pensamos que la ausencia de tensión es 0, pero no. Esto es rotundamente falso. Lo cierto es que ese hilo RPI, al no estar conectado al GND del circuito del botón, está flotando, es decir baila alegremente de tensión provocado por influencias externas como emisiones de radio o simple electrostática, y las lecturas que hagas tienen más que ver con el azar que con un valor real.

    Recuerda que necesitamos asegurar que el GND de todos los componentes es el mismo, so pena de quemar algo. Y esto nos lleva a la vieja cuestión de las medidas de tensión son como las medidas de altura del agua, que dependen de donde lo midas, porque necesitas una referencia de base (¿Qué altura tiene el agua en una bañera de un 5º piso?)

    Todo este rollo viene a que si queremos tener una medida clara leyendo un pulsador, necesitamos asegurar que no hay un contacto flotante y para eso se suele usar un circuito más o menos así:

    Leyendo un boton

    Fíjate que si el pulsador está abierto, el input será HIGH o 5V porque forzamos la lectura de la tensión a través de R1 y R2. Pero si pulsas el contacto, la entrada leerá 0V o LOW, porque la tensión se desviará a GND impidiendo que la tensión suba en R2 (Por eso hemos puesto R1, para evitar un corto)

    En la jerga, cuando conectamos R1 a Vcc, decimos que es un circuito con resistencia Pull Up, porque cuando está abierto leemos valor alto (De ahí lo de Up).Pero también podemos invertir los 5V y GND, con lo cual crearíamos un circuito de Pull Down, ya que leeríamos GND o 0 al estar abierto y HIGH al pulsar.

    Aunque te pueda parecer un poco raro ahora, dale una pensada y verás como lo ves claro enseguida, es más, si te resulta extraño, prueba a montar esos circuitos y lo compruebas.

    Para leer un pulsador siempre necesitamos un circuito de Pull Up o Pull Down, lo que resulta bastante engorroso y más aún, las resistencias adicionales cuestan pasta, por lo que si a ti te molesta, no te digo a los que fabrican electrónica a gran escala.

    Por eso casi todos los controladores modernos como Arduino o Raspberry Pi incluyen un truco para evitar ese engorro y pueden activar ellos mismos resistencias internas de Pull up que te evitan incluirlas en tu circuito.

    ¿Y porque no hemos empezado por ahí, en lugar de contarme toda esa historia de miedo? Pues básicamente porque si no entiendes la necesidad de los Pull Up, no entenderás cuando debes usarlos y te vas a llevar más de un chasco con los botones (Y otras cosas).

    Pero no te creas que los problemas de los pulsadores se acaban ahí, ¡Para nada! Otra de las malas costumbres de los pulsadores, es que el contacto no se cierra sin más cuando pulsas, No señor.

    Más bien rebotan varias veces, haciendo positivos y negativos repetidos hasta que se estabilizan y ya marcan un valor estable. Si esto te suena raro, es porque nosotros somos demasiado lentos para apreciarlo, pero tu Arduino o Raspberry pueden detectarlos porque son varios miles de veces más rápidos que tú y yo, y pueden contar esos rebotes y si lo haces te llevaras una sorpresa.

    Por eso hay que limpiar un poco el rebote (Bouncing en inglés) y a la técnica para limpiarlo se llama debouncing en la jerga habitual del gremio.

    En esta sesión vamos a ver como leer correctamente un pulsador con su Pull Up y como hacer el debouncing del mismo. Pero no te asustes que usaremos las resistencias internas de la Raspberry para ello en lugar de usar resistencias externas.

     

    Leyendo un pulsador

     

    Vamos a empezar por proponeros un pequeño circuito con un pulsador y un Led. La idea es poder ver como el Led se ilumina cuando pulsamos el botón o al revés. Y para ello podemos montar algo como esto:

    Raspberry y pulsador

    He usado la nomenclatura BCM para los pines y ahora ya podemos pasar a ver el programa, pero antes conviene que hablemos de lo que son los Cobbler, para evitar que nuestra Raspberry pase a mejor vida.

     

    El Cobbler

     

    En el último ejemplo hemos sacado 3 cablecitos de nuestra Raspberry, pero a medida que vuestros montajes se vayan complicando la cosa va a empeorar y complicarse más. Hemos ido conectando los diferentes pines a las conexiones que nos interesaban, pero naturalmente hay un problema que consiste en que la Raspberry no rotula el nombre de los pines en la placa, lo que nos obliga a contar los GPIO donde conectamos.

    Esto es algo que en el futuro procuraremos evitar, porque ciertos errores a la hora de contar pines pueden llevarnos a un pequeño chispazo y un entierro lamentable de nuestra buena  amiga la Raspi y al precio que van, conviene reducir las defunciones al mínimo.

    El caso es que yo tengo aprecio a mi Raspberry, porque lleva conmigo muchas batallas y por eso cuando vayamos a conectar más allá de 3 o 4 GPIO a nuestro proyecto, voy a usar a partir de ahora un Cobbler como este:

    Detalle de conexiones

    Su uso no es imprescindible, claro está, pero tiene la ventaja de que podemos sacar un conector plano de nuestra Raspberry y pasarlo al Cobbler que lo insertamos en la protoboard y desde ahí sacar los cables a nuestros circuitos.

    No es a prueba de errores, pero normalmente los Cobbler llevan rotulados los nombres de los pines a usar lo que ayuda a no equivocarse, por lo que es un aditamento que os recomiendo sin reservas porque seguramente os ahorrara cambiar de Raspberry cada tanto tiempo.

    Nosotros podemos publicar los circuitos que vayamos probando sin dibujar directamente el Cobbler, pero creedme, yo siempre lo uso en medio para evitar desgracias.

    En mi caso el circuito ya montado con todo, Led y pulsador queda más o menos así:

    diagrama de conexion

    Bueno pues una vez dicho esto y evitado en la medida de lo posible un inútil derramamiento de Raspis, podemos seguir con los programas para leer el pulsador

     

    Programas para leer el pulsador

     

    Para poner en marcha el programa vamos a presentar una nueva instrucción de Python 3 llamada if. Si estáis habituados a cualquier otro lenguaje, los condicionales con if son similares en Python (Aunque también tiene sus ventajillas, como no)

    Para quienes os acerquéis por primera vez a la programación, vale la pena comentar que en muchas ocasiones en tus programas necesitas comprobar si una condición dada se cumple o no. Y en función de ello tomar un curso de acción u otro. Y ese es el caso para saber si un botón ha sido pulsado.

    La instrucción if tiene en su forma más básica algo parecido a esto:

    If condición:
       Instrucción 1
       Instrucción 2
       ....

    Si la condición se cumple (Es evaluable a True) se ejecutan las instrucciones que vienen en el bloque a continuación (Fíjate que acaba en : como siempre que puede ir un bloque de instrucciones) y en caso contrario ignora el bloque y continua la ejecución a partir de este.

    Como es nuestro primer uso no voy a complicar más el tema por ahora, pero en otro momento veremos que tiene más opciones disponibles.

    Empezamos el programa con los import precisos que ya conocemos de sesiones previas:

    import RPi.GPIO as GPIO
    import time
    GPIO.setmode(GPIO.BCM)

    Ahora tenemos que informar a nuestra Raspberry que vamos a usar nuestro pin 24 como entrada:

    GPIO.setup(24, GPIO.IN)

    Esta es la forma más habitual de definir un pin de la Raspberry como de entrada, pero tiene el molesto inconveniente de necesitar usar una resistencia de Pull up o pull down para operar correctamente, como ya comentábamos arriba.

    Afortunadamente, nuestra Raspberry incluye una orden para activar estas resistencias de Pull up internamente y olvidarnos de hardware adicional, haciendo la definición del pin de marras de esta manera

    GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)

    Que puedes leer como: Define el pin 24 como de entrada y para leerlo activa una resistencia interna de pull up. En Raspberry, a diferencia de Arduino, que solo permitía activar resistencias internas de pull up, también podemos activarlas de pull down usando el asombroso comando:

    GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    Y ahora para leer nuestro botón, basta con leer el GPIO 24 y asignarlo a una variable como Status con la instrucción:

    Status = GPIO.input(24)

    El programa completo puede quedar algo parecido a esto:

    import RPi.GPIO as GPIO
    import time
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    
    while True:
        Status  = GPIO.input(24)
        if Status  == False:    
            print(”Botón pulsado.”)
            time.sleep(0.2)

    Después de las definiciones, usamos un bucle while para que lea de forma continua el valor del GPIO y se asigna a la variable Status.

    Como hemos activado una resistencia de pull up para leer el botón, devolverá un valor HIGH cuando este sin pulsar y False cuando se pulse. Por eso lo que hacemos con el if es comprobar si el status es False, y en caso afirmativo sacamos un mensajito diciendo que hemos pulsado sin más.

    Para los que vienen de C++ o Java, de nuevo fijaros que marcamos el bloque simplemente como un indentado después del símbolo : . Y al igual de en C++, para comprobar si Status es False la instrucción es:

    if Status  == False:

    Y no esto otro:

    if Status  = False:

    Algo que da a los novatos muchos dolores de cabeza al principio. La primera instrucción comprueba si Status es True o False, pero la segunda asigna el valor False a Status si o si, y una vez hecho decide si es verdadero o Falso el valor. Y como acabamos de hacer que Status es False la condición no se cumplirá nunca y nunca veréis escrito el resultado de que han pulsado el botón

    Dicho así parece un trabalenguas, por lo que os animo a que le dediquéis un momento a pensarlo y a ser posible que hagáis el programa con estas dos líneas para que veáis el resultado. Es más fácil de lo que parece.

    Por último, los lectores avispados, se habrán percatado de que hay una instrucción sospechosa al final del bloque:

            time.sleep(0.2)

    La idea es que para evitar rebotes, dormimos a nuestra Raspberry durante 2 décimas de segundo para impedir que pueda leer repetidamente la entrada GPIO y detectando los correspondientes rebotes.

    Al dormir un poco la lectura le impedimos que le dé tiempo a ver los rebotes que suelen tardar menos de esos 0,2 segundos que le dormimos.

    Cuando probéis el circuito, veréis que cunado pulsas el botón te saca un simple mensaje de se ha pulsado el botón y poco más.

    ¿Cómo hacemos para que además el LED indique el estado del contacto? Esto ya deberías saber hacerlo tomando instrucciones de las últimas sesiones y te recomiendo que intentes hacerlo por ti mismo, pero por si acaso aquí está una solución:

    import RPi.GPIO as GPIO
    import time    
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
    GPIO.setup(23, GPIO.OUT )
    
    while True:
        input_state = GPIO.input(24)
        if input_state == False:
            GPIO.output(23, True)      # Enciende el LED
            print('Botón pulsado')
            time.sleep(0.3)
            GPIO.output(23, False)     # Apaga el LED

    Aquí os dejo un pequeño vídeo con el resultado.

    Deja una respuesta