Leyendo una entrada del microcontrolador

Puede que ya podamos encender y apagar un Led cada cierto tiempo, pero ahora queremos que lo haga cada que pulsemos un botón.

Necesitaremos adicionar a nuestro circuito un switch pulsador con una resistencia de pull up, esta configuración de switch y resistencia sirve para mantener un estado lógico en 1 mientras el switch no se pulse y en 0 cuando sea pulsado.

El plano final se verá así:

No ha variado mucho con respecto al anterior, solo hemos conectado el switch con resistencia de pull up al pin 17 del microcontrolador, RA0.

Antes de pasar al código debemos entender que es un condicional y un ciclo.

Un condicional es una estructura que nos ayuda a comparar un valor o un estado con otro y nos arroja un resultado verdadero o falso, con el que podemos tomar acción y ejecutar un trozo de código según la necesidad.

El más básico de todos es la estructura “if/else”, esta estructura evalúa una condición y ejecuta un código según el resultado. Se escribe así:

if(condición){
              // Código si la condición es verdadera
}
else{
              // Código si la condición es falsa
}             // Final de la estructura

En la primera línea se evalúa una condición entre los paréntesis, podemos verificar si dos valores son iguales, diferentes o si uno es mayor o menor que el otro.

De resultar verdadera la condición se ejecutan las líneas de código que estén entre las llaves que se encuentran en la parte superior y luego el programa va al final de la estructura, si el resultado es falso se ejecuta el código que está entre las llaves luego del “else” y termina la estructura.

En la siguiente tabla vemos algunas de las comparaciones que se pueden hacer en la condición:

COMPARACIÓN SIMBOLOS
Igualdad ==
Diferencia !=
Mayor que >
Mayor o igual que >=
Menor que <
Menor o igual que <=

El resultado de estas evaluaciones siempre va a ser verdadero o falso, ningún otro, si nos fijamos bien, cuando vamos a asignar un valor a un registro usamos un solo igual (=), cuando vamos a hacer una comparación usamos dos iguales (==).

Ejemplo:

if(8 == 8){
	// Los números son iguales, se ejecuta lo que tengamos aquí
}
else{
	// Los números no son iguales, por tanto esta línea de código no se ejecuta.
}

Un ciclo es un código que se ejecuta constantemente siempre y cuando una condición sea verdadera, el ciclo termina cuando esta cambia a ser falsa.

El ciclo while es el más sencillo de entender, se escribe así:

while(condición){
	// Código que se ejecuta siempre que la condición sea verdadera.
}

En este punto la condición se evalúa de igual modo que con la estructura if/else, y el código se ejecutara siempre que la evaluación sea verdadera, a esta altura cabe añadir que el valor de estado lógico o el numero 0 (cero), es tomado como falso y el estado lógico 1, el numero 1 (uno) o cualquier número superior es tomado como verdadero, es por eso que en nuestros programas, la parte que necesitamos que se ejecute contantemente la ponemos dentro de un ciclo infinito de esta forma:

while(1){
	// Todo el programa a ejecutar constantemente.
}

Así la evaluación de la condición siempre va a ser verdadera y el código se repite indefinidamente, es lo que se conoce como un ciclo o bucle infinito.

Conociendo esto hagamos un nuevo proyecto en MPLAB X y copiemos el siguiente código desde la línea 1:

#include <xc.h>

#pragma config FOSC = XT        // Oscilador con cristal de cuarzo de 4MHz conectado en los pines 15 y 16
#pragma config WDTE = OFF       // Perro guardián (WDT) deshabilitado
#pragma config MCLRE = ON       // Master clear habilitado (pin reset)

#define _XTAL_FREQ 4000000      // Oscilador a 4MHz

void main(){
    TRISA = 255;                // RA0 como entrada
    TRISB = 0;                  // Puerto B como salida
    PORTB = 0;                  // Inicializa el Puerto B con todos los bits en 0
    ANSELA = 0;                 // Puerto A Digital

    while(1){                   // Programa que se ejecuta continuamente
        if(RA0 == 0){           // Preguntamos si el estado lógico de RA0 es 0
            while(RA0 == 0){    // Si es así entraremos a un ciclo antirebote
                                // El programa permanecerá aquí hasta que se suelte el botón
            }                   // Cuando RA0 regrese a estado lógico 1, sale del ciclo
            RB0 = !RB0;         // El signo de admiración se usa como negación, si RB0 tiene un 0
                                // al negarlo lo cambia por un 1 y asigna el nuevo valor al mismo bit
                                // de este modo cambia el estado cada que pulsemos y soltemos el botón
        }
    }
}

Al principio es igual primero, expliquemos sus variaciones, hemos configurado todo el puerto A como entrada, al escribir el valor decimal 255, es como si le hubiéramos escrito el valor binario 11111111, es decir todos los bits del puerto A como entrada. Un nuevo registro aparece como el nombre de ANSELA al cual le asignamos el valor de 0 (cero), por ahora no nos ocupemos de su significado solo mantengámoslo ahí.

En la línea 15 llega nuestro ciclo infinito, dentro de el encontramos una estructura if en la que se evalúa el estado de RA0, es decir, el pin donde va conectado el switch, notamos que solo será verdadera si es pulsado, de lo contrario en RA0 habrá un 1 haciendo que la condición sea falsa.

Cuando presionamos el botón, RA0 se hace igual a 0, de modo que la condición se cumple y entramos a ejecutar el código dentro de las llaves del if.

Según el comentario escrito en la línea 17, entramos en un ciclo antirebote, este se usa cuando usamos switches mecánicos que pueden generar ruido mientras son pulsados y se estabilizan, es decir, que una vez presionamos el botón este puede enviar varias señales al microcontrolador, que este a su vez por la velocidad en la que ejecuta el programa, puede interpretar una sola pulsación del botón como muchas, obteniendo así resultados inesperados, es por eso que usamos un ciclo while donde evaluamos la misma condición del botón con el fin de esperar a que este sea soltado para así dar paso a la acción que debe realizar.

Dicho de otro modo, mientras tengamos el botón pulsado el programa permanecerá dentro del ciclo antirebote a la espera que los soltemos, cuando lo hacemos RA0 dejara de ser igual a 0, se ejecutara la acción a realizar y volverá a evaluar el if.

Para este ejemplo lo que buscamos es que el Led se encienda o apague por cada pulsación y lo hacemos de la siguiente manera, como sabemos el puerto B inicia todo en 0, por tanto el Led estará apagado, en la línea 20 encontramos la sentencia:

RB0 = !RB0;

Esta línea lo que hace es asignarle a RB0 su mismo valor pero negado, al anteponer el signo de admiración lo que le decimos es que nos invierta el valor de lo que tiene a la derecha, es así que si el valor der RB0 es 0, lo cambiara a 1 y si es 1 lo cambiara a 0, por eso cada de pulsemos el botón el Led encenderá o apagara según su estado anterior.

Compila el programa y cargarlo a Proteus, comprueba que tal funciona. Fíjate que el Led solo cambia cuando sueltas el botón.