Las máscaras y los puertos que Arduino nos ocultó

máscaras en arduinoRecién pasado el carnaval y a mi no se me ocurrió hablarte de las máscaras. Que cara más dura tengo cuando quiero… Aunque la verdad, te veo imaginando máscaras cómo las que usan los robots de bq…y ya te digo que nada más lejos a la realidad.

De hecho…la explicación de porqué se llaman máscaras no es algo que me haya planteado en mi vida. Supongo que si hay algún informático en la sala tal vez sepa explicar mejor que yo la historia de las máscaras en programación. Yo iré un poco más al grano 😉

Bits, bytes…¡Qué jaleo!

Bueno, aunque no lo sepas, los microcontroladores en general funcionan con bits. Se programan con ellos. Un bit es el típico 0 o 1 que estás acostumbrado a ver en las pelis. Pues eso se usa continuamente. En otros microcontroladores es algo muy palpable. Se juega continuamente con los ceros y los unos. En Arduino no.

Un ejemplo, si quieres encender un led lo que haces es:

void setup() {
pinMode(9,OUTPUT);
}

void loop() {
  digitalWrite(9,HIGH);
}

Que en el fondo no es más que poner un uno en ese pin de salida. Entonces, quiere decir que el resto de valores tienen un cero y solamente ése tiene un uno. Pues simplemente es eso. Escribir los unos y los ceros dónde toquen.

Para eso, los pines físicos, si te fijas, están como separados físicamente. Están los analógicos, luego están los digitales del 0 al 7 y luego los digitales del 8 al 13. ¿Qué pasaría si te dijese que estos ceros y unos se definen por bytes? ¿Y si te digo que un byte son 8 bits? ¿Y si te recuerdo que un bit es un uno o un cero?

Vaya, los digitales del 0 al 7 son 8…igual que los bits de un byte y el resto…el resto no, pero bueno estas cosas pasan. De esta manera, Arduino se divide en lo que se llaman puertos. Lo que pasa es que, en lugar de ser lo más normal del mundo, en Arduino parece que sea cosa de raritos porque no hay ni mucha información ni son tan populares como las funciones de escribir en los puertos. Supongo que esto es una cosa de frikis electrónicos y no algo de informáticos.

Los puertos en Arduino

El tema está en que tenemos el puerto B, el C y el D. Los pines analógicos forman el puerto C, los digitales del 0 al 7 el puerto D y los pines del 8 al 13 el puerto B. Sé que es chungo de entender, pero vamos a ver un ejemplo:

void setup() {
pinMode(6,OUTPUT);
}

void loop() {
  PORTB = B00000000;
}

Aquí lo que pasa es que en el puerto B todos son 0 por lo que están todos en LOW. La B antes de los ceros indica que son bits, no te imagines que es por el puerto B o cosas similares. Ahora encendamos el pin 9:

void setup() {
pinMode(9,OUTPUT);
}

void loop() {
  PORTB = B00000010;
}

Claro, he cambiado el cero a uno. Pero hay una cosa que no te he dicho, los bits van de derecha a izquierda. Es decir, el más pequeño es el que más a la derecha queda. Vamos como los números enteros, el uno en la derecha es menos que el uno dos posiciones más a la izquierda (que sería 100). Pues aquí lo mismo.

Aunque claro, esto es una ciencia un poco a la cuenta la vieja. Para algo más serio está la imagen que ofrecen desde Arduino. En esa imagen puedes ver cómo en rojo está el nombre del pin físico que conoces y en negro el nombre del puerto y la posición en el byte, en el caso del pin digital 9 pone PB1, que es dónde yo lo he puesto (en el puerto B en la posición 1, siempre teniendo en cuenta que la primera posición es 0). Esta imagen puede encontrarse aquí, estando bajo una licencia CC-BY-SA 3.0.

Arduino-To-Atmega8-Pins

Como ves, el puerto B va del 8 al 13…y eso no da 8 pines por lo que…¿Qué pasa con los que faltan? Pues puede ser que estén vacíos o que el chip del microcontrolador los utilice para otras cosas. En este caso se utilizan para XTAL1 y XTAL2, eso es el oscilador. Que es una cosa que no necesitas ahora ni creo que necesites. Digamos que es el que marca la velocidad a la que trabaja el microcontrolador.

Bueno, pues..antes la he liado. He puesto a cero esos dos valores. Pero, ¿Cómo coño sé yo que eso vale cero? No sé ni si vale cero, ni uno, ni si va cambiando…¡No tengo ni idea! Lo de arriba es un horror y no deberías programarlo JAMÁS.

Ufff…bueno siempre me puedo quedar con la función digitalWrite aunque…¿Qué pasaría si necesitase una precisión milimétrica y que se encendiesen tres leds a la vez? Y cuando digo a la vez es en la misma orden. Tengo que volver a los puertos…pero no tengo ni idea de que poner en algunos de ellos…

Las máscaras en Arduino…y sus operadores

Es aquí dónde aparecen las famosas máscaras. Una máscara no son más que unos bits que aplicaremos a nuestros puertos para que suceda alguna cosa. Cambiaremos los valores que queremos dejando el resto igual que estaban. Esto si que es ya más interesante. Para eso se utilizan dos símbolos que ya conoces: & y |

Y no, no estoy de cachondeo. El & significa ‘y’. Mientras que la barra | significa ‘o’. Cuidado que además de tener mucho poder estos operadores son totalmente distintos. De esta manera, & será una multiplicación y | una suma. ¿Cómo te quedas? 😉 ¿Cómo se utilizan?

Pues la multiplicación al multiplicar por 1 se va a quedar el mismo valor mientras que si multiplicas por 0 forzarás a que ese valor sea cero. De esta manera, & se utiliza para poner ceros donde queramos y el resto dejarlo como está.

Por otra parte, la suma lo que hace es que al sumar un 1, pase lo que pase ahí tendremos un 1 obligatoriamente. Al sumar un 0…el resultado es el que estaba. Por lo que si necesitas poner un 1 en algún lugar recurrirás a el operador |.

Muchas veces lo que te puede suceder es que tengas todo ceros y un uno, como en el ejemplo, y quieras poner el uno en una posición que va cambiando en cada momento. Pues para eso están los operadores shift. Se representan así: << o >> y lo que se hace es poner a un lado el byte y al otro el numero de posiciones que se mueve. La dirección del movimiento la indican estas pequeñas flechas.

byte y = B10000000;

void setup() {
Serial.begin(9600);
}

void loop() {
   y = y >> 1;
   Serial.println(y);
   delay(1500);
}

Como puedes ver, lo que hago es mover una posición hacia la derecha los números de y. Así, lo que pasa es que el uno se va moviendo a la derecha y lo que va antes del uno se va rellenando con ceros. Se va rellenando con ceros no porque dé la vuelta sino porque siempre se añaden ceros. No importa el sentido en el que se gire.

De esta manera, el destino de utilizar estos shift en bucle (left shift y right shift se llaman) es que el byte quede todo a cero ya que se va moviendo y los huecos libres se rellenan con ceros.

Dirección de registros y direcciones de entrada en pines

Vale, ahora ya puedes encender a la vez los pines 9, 10 y 11 utilizando los operadores y recordando que los 2 últimos no debes de tocarlos y es por eso por lo que se utilizan estos operadores. Lo mismo pasa con los pines analógicos y lo mismo pasa con los digitales del 0 al 7. En los analógicos solo llegan hasta el pin 5 y en los digitales tienes los pines 0 y 1 que son intocables.

Pero claro, luego viene lo otro…que vas a hacer, ¿vas a declarar uno a uno los pines para decir si son INPUT o OUTPUT cada vez que cambies con los operadores los valores de los pines? ¡Vaya jaleo, hermano!

Para eso existe lo que se llama la dirección de registros. Que lo que hace es que, con el mismo orden que en el puerto, si recibe un uno eso es una salida y si recibe un 0 es una entrada. Por ejemplo:

DDRB = B00000010;

Cómo ves, DDR hace referencia a ‘dirección de registro’ y la B al puerto B. Podría ser DDRD o DDRC. En cuanto al byte que he escrito, he hecho que el pin 9 sea una salida (OUTPUT) y lo demás sean entradas (INPUT). Pero bueno…ya sabes que…¡debes aplicar los operadores de antes, aplicar los bytes directamente no se debe de hacer JAMÁS!

Por último están las direcciones de entrada de los pines. Esto significa que al aplicar PIND, PINB o PINC, al poner todos los pines como entrada (sólo lee, solo entradas) nos pondrá un 0 si no le llega ningún voltaje y un 1 si le llega algún voltaje. Si he conectado un sensor magnético al pin 8 me devolverá un valor de 1 y si lo conecto en 9 me devolverá un 2. Esto es porque todo lo que te he contado en binario (sí sí, los unos y ceros son código binario), se puede traducir a números decimales. Y entonces Arduino hace la conversión. Si no sabes pasar de binario a decimal hasta la calculadora por defecto en Ubuntu lo hace, así que no te tires de los pelos 😉

Opt In Image

¡Oye! ¡Que esto se acaba!

Así que al final, esto es lo que se ha hecho toda la vida: programar los pines directamente. Está claro que no es tan sencillo como las funciones que trae Arduino. De hecho ellos desaconsejan utilizar este método por si la lías y metes un uno dónde no toca. Pero la verdad es que si tienes que jugar con cosas que requieren apagar algo y encender algo a la vez, no está mal. Es jaleoso pero útil.

¿Pero que es una máscara? Son los bits que añades para hacer la operación. Eso es la máscara. Los bits que añades para hacer la operación del & con los bits que hay en tu puerto, por ejemplo. Espero que esto te haya servido. ¿Habías utilizado antes los registros de Arduino? ¡Contéstame en los comentarios! Y ya de paso…comparte el post anda 😉

[Total:7    Promedio:4.3/5]

Déjame un comentario que en el fondo soy buen chaval

  1. Antonio Capel

    Responder

    • Responder

  2. Manuel Molina

    Responder

    • Responder

  3. alex

    Responder

    • Responder

  4. Responder

    • Responder

Deja un comentario