¿Y si realmente quiero todos los pines juntos?

Claro, ahora si anda bien…

¿Vieron esas situaciones en que realmente quieren prender dos pines del Arduino (poner en alto, ejem…) pero al mismo tiempo, onda, sin ningún retraso pero posta posta? ¿Nunca les pasó?

Bromas aparte, vamos a realizar un caso hipotético en el que quiero prender y apagar al mismo tiempo, dos leds conectados a los pines 2 y 3 (ya resuelta la electrónica, claro, ¡led con sus resistencia!). Con referencia al programa (código) en la IDE de Arduino seria algo como:

void setup() {
   // Ponemos los pines 2 y 3 como salida
   pinMode(2, OUTPUT);
   pinMode(3, OUTPUT);
 }
 void loop() {
   //Predemos y esperamos
   digitalWrite(2, HIGH);
   digitalWrite(3, HIGH);   
   delayMicroseconds(1000);                       
 //Apagamos y esperamos
   digitalWrite(2, LOW);
   digitalWrite(3, LOW);        
   delayMicroseconds(1000);                       
 }

¡La lógica es inapelable! prendo + prendo + espero + apago + apago + espero + repito el ciclo…

¿Qué sucede con esto? Voy a armar un protoboard con unos leds y un Arduino Nano…

¡Y claro, prenden y apagan al mismo tiempo! Probemos, midamos, hagamos: voy a usar el osciloscopio para sacarme las dudas y voy a conectar cada canal a un led:

En cada canal (A y B, celeste y amarillo) existe, según la medición, un microsegundo (cada división vertical equivale a un microsegundo) entre su estado bajo y su estado alto (prendido y apagado) con lo cual, no prenden y apagan los leds al mismo tiempo: hay un problema…

En algunos casos, yo necesito que ambos pines cambien su estado al mismo tiempo. Puedo solucionarlo usando el mismo pin para ambos leds, agregar un transistor, etc. Pero esto se puede solucionar por programación:

void setup() {
   // Setear el puerto de pines 8 al 0 como salida, sin tocar los modos pre-existentes
   DDRD = DDRD | 0B00001100;
 }
 void loop() {
   // Escribir todos los pines al mismo tiempo
   PORTD = DDRD | 0B00001100;
   delayMicroseconds(50);
 // Poner todos los pines en cero
   PORTD =  0B00000000;
   delayMicroseconds(50);
 }
¡Ahora si!

¡Poco intuitivo este blink Marcelo! Pero los pines cambian de estado al mismo tiempo, menos de un microsegundo desde su estado bajo hasta su estado alto.

Vamos a ver el tema del código, porque es medio inentendible:

void setup() {
   // Setear el puerto de pines 8 al 0 como salida, sin tocar los modos pre-existentes
   DDRD = DDRD | 0B00001100;
 }

Lo que hice acá fue, usando la manipulación directa del puerto D (el puerto es el conjunto de pines, en este caso, del 0 al 7) definir pines 2 y 3 como salida.

void loop() {
   // Escribir todos los pines al mismo tiempo
   PORTD = DDRD | 0B00001100;
   delayMicroseconds(50);
 // Poner todos los pines en cero
   PORTD =  0B00000000;
   delayMicroseconds(50);
 }

Usando la misma técnica de manipulación directa del puerto, prendo (1) y apago (0) dos pines específicos, con su tiempo de espera correspondiente.

La manipulación directa de los puertos es una técnica usada en la programación avanzada de Arduino (y de microcontroladores en general) y también se la llama » bare metal manipulation» o «port manipulation»

De hecho, en la referencia de Arduino se habla de este tema.

Si bien este es un caso hipotético de poca utilidad en el mundo real, existen varias aplicaciones, entre ellas, hacer un rudimentario generador de onda sinusoidal:

¡A divertirse y probar, que Arduino es para eso!

Invitame un café en cafecito.app