Archivo de la categoría: Arduino

  • -

Teclado simple para Arduino

En el mercado existe una gran variedad de teclados que pueden adaptarse casi a cualquier proyecto. Desde los más utilizados, como los teclados de membrana similares a un teclado telefónico hasta las matrices de pulsadores múltiples o los shields que integran el teclado a un LCD, muy útiles para manejar un menú, por ejemplo.

Resultado de imagen para teclados arduino

Pero que pasa cuando no disponemos de la cantidad de pines libres que requieren estos teclados? Y cuando no queremos o no podemos implementar un shield a nuestro proyecto?

Teclado resistivo para un sólo pin

Los pines analógicos de Arduino permiten leer tensiones de 0 a 5v devolviendo al programa un valor proporcional a la lectura, entre 0 y 1023.

Por otro lado, con un par de resistencias en serie se puede crear un divisor de tensión: un circuito que divide la tensión de entrada en el circuito en otras dos diferentes y más pequeñas de salida.

Algo así:

Se trata de una entrada de voltaje Vin y una salida a través de la resistencia R2. La resistencia R1 se usa para dividir la tensión hacia la salida Vout.

Podés saber que valor tendrá Vout con la siguiente fórmula:

Vout=(R1 / (R1 + R2)) x Vin

… pero para nuestra finalidad la verdad es que mucho no va a importar. Lo que sí tiene que importarte es que si el valor de la resistencia R1 cambia, tambien lo hará el valor de Vout. Entonces, si conectamos Vout a un pin analógico de Arduino (por ejemplo, A0), cuando cambie el valor de R1, va a cambiar el valor devuelto por analogRead(A0).

Además, R1 puede ser remplazada por varias resistencias conectadas en serie, cuyos valores se suman. Y si entre estas resistencias en serie colocamos interruptores, podemos cambiar el valor de R1 al abrir o cerrar esos interruptores. Como sigue:

Si seguís más o menos este circuito, notarás que según que pulsador se active, se sumará una diferente cantidad de resistencias (las que en nuestro ejemplo inicial llamamos R1) y por ende el valor leído en A0 será diferente.

Entonces podés conectar a tu proyecto un completo teclado para, por ejemplo manejar un menú con arriba-abajo, derecha-izquierda y OK, usando apenas 5 pulsadores y 6 resistencias. Si además tenés en cuenta que sólo vas a consumir 1 único pin analógico de tu Arduino, las ventajas ya son obvias.

Claro que es un circuito económico y sencillo y por eso, sabiendo que la magia no existe, tambien será bastante impreciso. La misma pulsación difícilmente entregue el mismo exacto valor a A0… más bien este valor va a estar dentro de un rango, pero no es demasiado difícil lidiar con eso:

 

int pinKb = A0;
 
void setup() {
 
   Serial.begin(9600);
 
   Serial.print("PULSADA:");
 
}
 
void loop() {
  // LECTURA DE TECLADO Y MENU *************************
  int pulsada = analogRead(pinKb);
 
  if (pulsada > 100) {
 
    Serial.println(pulsada);
 
  }

Habiendo armado el circuito del esquema anterior, cargás este último sketch en tu Arduino y, desde el monitor serial, vas a obtener el valor leído para cada tecla pulsada. Entonces vas a hacer repetidas pruebas con cada pulsador, tomando nota en cada caso del valor obtenido. Como resultado, vas a tener una tabla como esta:

Pulsador 1 – Valor mínimo: 100, Valor máximo 190

Pulsador 2 – Valor mínimo 210, Valor máximo 260

Pulsador 3 – Valor mínimo 310, Valor máximo 385

Pulsador 4 – Valor mínimo 410, Valor máximo 475

Pulsador 5 – Valor mínimo 516, Valor máximo 685

Con esta tabla, no te va a ser difícil implementar en tu proyecto funciones similares a la siguiente:

 

int tecla=analogRead(pinKb);
   if ((tecla>99) && (tecla<191)) { // se presionó la tecla 1 // y acá va el código en consecuencia... } if ((tecla>209) && (tecla<261)) {
    // se presionó la tecla 2
    // y acá va el código en consecuencia...
   }

A tener en cuenta:

Los valores que obtengas en tus experimentos seguramente van a ser bien diferentes de los de mi ejemplo. Van a depender principalmente del valor de las resistencias que hayas utilizado. En este ejercicio usé resistencias de 2k2, pero podes usar el valor que mejor te convenga. Tené en cuenta que cuanto mayor sea el valor de las resistencias, más amplitud habrá entre los valores obtenidos para cada tecla y esto es deseable. Pero si exagerás con las resistencias, la tensión que llegue al pin A0 puede ser demasiado pequeña para ser leída…

Este circuito, por su pobre diseño, ya es bastante impreciso en sí mismo, aunque cumple con creces con lo que se le pide. No le confiaría el control de un centro de disparo de misiles nucleares, pero para un menú de opciones de un control de luces LCD será más que suficiente. Igualmente, no está demás recomendarte que uses resistencias de tolerancias bajas… 1% no estaría mal. El valor de las resistencias varía de acuerdo a muchos factores… el circuito, el cableado, la temperatura, etc… y cuanto mayor sea la tolerancia de la resistencia, más van a variar los valores finales y por ende variarán tambien los valores obtenidos en la lectura del pin A0. Por ejemplo, para un circuito con resistencias de tolerancia 5% que armé durante el verano, con temperaturas por sobre los 30 grados, ahora que cambió el clima y tenemos unos 8 grados en el ambiente las pulsaciones en el teclado resultan erráticas: no siempre son leídas y muchas veces se confunde la tecla pulsada con otra. O bien tendría que hacer versiones diferentes del programa para cada temporada (????) o, lo correcto, usar resistencias de buena calidad con tolerancias bajas y ajustar los valores del rango correspondiente a cada tecla.

Si tu circuito usa lecturas de varios pines analógicos, especialmente si están próximos, tenés que considerar hacer una pausa entre las lecturas, para darle tiempo al microcontrolador de Arduino a limpiar los canales y obtener datos fehacientes. Un delay(100) debería ser suficiente en la mayoría de los casos.

El ruido eléctrico propio de tu circuito o interferencias externas pueden afectar estas lecturas. Incluir la instrucción inputMode(A0, INPUT_PULLUP) antes de comenzar a leer puede solucionar parte del problema (esto activa la resistencia pullup interna conectada al pin analógico de Arduino) pero si lo vas a hacer de este modo tendrás que volver a tomar los valores para tu tabla de referencia, porque el pullup activado va a modificar los valores obtenidos.

Si hay relés conectados al circuito para la activación de cargas importantes (calefactores, motores, etc…) el “chispazo” de activación de los relés pueden provocar el ruido suficiente como para que e dispare una falsa lectura de tecla pulsada. En algún momento publicaré algo sobre filtros antichispa, pero mientras tanto podes googlear el tema.

 


  • -

Conectar 2 Arduino por I2C

En un principio, para proyectos simples, no parece muy útil. Pero al empezar a explorar la posibilidad de interconectar dos o más placas Arduino entre sí, las alternativas, ocasiones y necesidad de usar este sistema se multiplican muchísimo. Por ejemplo, algunas situaciones en que la interconexión de Arduinos nos permiten saltear problemas de desarrollo. Especialmente porque podremos aprovechar al máximo la capacidad de cada una de las placas que interconectemos, haciéndolas conversar entre ellas para que se presten los recursos.

Falta de memoria

No la tuya, sino la de Arduino. Sketchs extensos o intensivo uso de variables puede hacer directamente que nuestros programas no carguen o que durante la ejecución aparezcan errores productos de la corrupción de la memoria: extraños contenidos en las variabes, funciones que no devuelven los valores esperados, cuelgues diversos…

En estos casos se puede “repartir” el sketch entre dos o más Arduinos, haciendo que uno consulte el resultado de funciones almacenado en el otro o utilizando la EPROM de ambos para almacenar datos que puedan ser consultados por uno u otro cuando se necesiten. Un buen uso de Arduino en estos casos puede producir una diferencia similar a utilizar una PC con un sólo núcleo o una con varios, porque estaremos repartiendo la carga de la ejecución del sketch en varios procesadores e incluso podremos programar procesos que corran en paralelo e independientes de la manera más pura.

Como ejemplo, podríamos utilizar un Arduino para la comunicación con el usuario, controlando un display, teclado y menúes y otro Arduino para que se encargue de relevar estado de sensores y activar o desactivar dispositivos comunicando los datos al otro cuando lo solicite.

Falta de pines, entradas o salidas

En especial cuando usamos Pro Mini o Nano, podemos encontrarnos con que nos resulten insuficientes los pines analógicos o digitales para determinadas funciones. PWM por ejemplo. Sumar Arduinos suma tambien sus puertos I/O permitiéndonos expandir nuestro proyecto todo lo que necesitemos.

Falta de velocidad

Los microcontroladores con que se equipan las placas Arduino son más que suficientes para la mayoría de las aplicaciones para las que fueron planeados, pero no son un Ryzen ni un i7. Aplicaciones complejas pueden funcionar de maravillas pero decepcionarnos un poco con los tiempos de respuesta. Tal como explicaba en el caso de falta de memoria, repartir la carga del sketch entre varios Arduinos mejora notablemente los tiempos de ejecución. La única limitación será la habilidad, creatividad y talento del programador. Y el presupuesto disponible para placas, pero de eso no me voy a ocupar… o sí? Sí, tambien:

Presupuesto

En un proyecto reciente, actual de hecho… en realidad todavía en proceso… por los requerimientos de memoria y pines opté por iniciarlo sobre una Mega cuyo costo en Argentina es de unos u$s 20.- y a poco de avanzar me resultaron insuficientes los puertos de I/O para ciertas funciones. Buscando como saltar el problema, pensé en la conexión I2C con una Pro Mini y de ese modo sumar puertos. Y allí me dí cuenta de que dos placas Pro Mini me daban los recursos necesarios y, a u$s 4.- cada una, a menos de la mitad del costo. Tambien hay que tener en cuenta el mejor aprovechamiento del espacio en el circuito final y por ende, un menor costo en fabricación y materiales de un posible PCB.

Y, la mejor parte: todo esto…

Así de Fácil

La imagen muestra el diagrama de conexión, usando en este caso dos placas Pro Mini, pero sea cual sean las placas a conectar se trata de usar una conexión a masa común (unir los pines GND de las placas y la alimentación), conectar los +5V de la fuente de alimentación a la entrada correspondiente en las placas y, la parte que nos importa, unir el pin SDA de una placa con el SDA de la otra, y el SCL de una con el SCL de la otra.

Para las placas Uno, Pro Mini y Nano, el puerto SDA corresponde al pin A4 y el SCL al pin A5. En las placas Mega y Due el puerto SDA corresponde al pin 20 y el puerto SCL corresponde al pin 21

 

Acá voy a hacer una aclaración importante: este recurso no se limita a interconectar dos placas sino que pueden sumarse tantas placas como sea necesario casi sin límite. Simplemente uniendo todos sus pines SDA por un lado y los SCL por otro. Es más, tambien pueden conectarse de este modo, en la misma línea, otros dispositivos que requieran de interconexión IC2.

Esto es así, porque luego en la programación veremos que cada dispositivo tendrá un identificador único que se utilizará en la comunicación para diferenciarlo de todos los demás. Así, si el dispositivo (o la placa) nro. 1 necesita un dato de la placa (o el dispositivo) nro. 8, enviará la pregunta al dispositivo identificado como “8” y este enviará la respuesta al dispositivo identificado como “1”, permitiendo que las conexiones entre todos viajen por los mismos cables sin confundirse.

A trabajar

Con todo conectado, vamos a escribir un primer sketch para probar el sistema. En realidad, vamos a escribir 2: uno para el Arduino que hará las veces de Master y otro para el que hará de Slave.

Master

 
// la librería encargada de proporcionarnos todos los comandos necesarios para la comunicación I2C
#include <Wire.h>
 
void setup() {
 
    Wire.begin(1); // Iniciamos el bus I2C identificando este dispositivo como 1. En el caso del Master el "1" es opcional y podríamos obtener el mismo resultado escribiendo Wire.begin();
 
}
 
void loop() {
 
    byte x = 0; // definimos x como variable tipo byte (podrá contener un valor entero entre 0 y 255)
 
    Wire.beginTransmission(8); // preparamos el bus para transmitir datos al dispositivo nro. 8
    Wire.write("x es ");        // envía 5 bytes (un caracter = un byte)
    Wire.write(x);              // envía un byte
    Wire.endTransmission();    // finaliza la transmisión
 
    x++;
 
    if (x>255) {
 
        x=0; // si x es mayor a 255 lo volvemos a 0 para no superar los valores permitidos para una variable tipo byte
 
    }
 
    delay(500); // una pausa necesaria para dar tiempo a la transmisión completa
 
}

Slave

#include <Wire.h> // la librería encargada de proporcionarnos todos los comandos necesarios para la comunicación I2C
 
void setup() {
    Wire.begin(8);                // Conectamos al bus I2c identificando a este dispositivo como 8
 
    Wire.onReceive(receiveEvent); // Se registra la función receiveEvent, que será llamada cada vez que se reciba un dato por I2C
    Serial.begin(9600);           // Iniciamos el puerto serie para imprimir la salida por el monitor serie de Arduino
 
}
 
void loop() {
    delay(100); // pausa para esperar la recepción y completar la transmisión de respuestas
}
 
void receiveEvent(int cuantosBytes) {
 
    while (1 < Wire.available()) { // loop para leer todos los bytes recibidos, menos el último
        char c = Wire.read(); // lee un byte recibido y lo convierte a caracter
        Serial.print(c);         // imprime el caracter en el monitor serie
    }
    int x = Wire.read();    // lee un último byte y lo convierte a integer
    Serial.println(x);         // imprime el valor por el monitor serie
 
}

El resultado será algo así:

X es 0

X es 1

X es 2

… nada demasiado útil ni emocionate en sí mismo, pero date cuenta que habrás logrado interconectar y hacer interactuar dos microcontroladores independientes. Master calcula el valor de x y le transmite a  Slave la frase “x es..” y el valor. Slave recibe la frase y se encarga de imprimirla a tu monitor a través del puerto serie.

Con el mismo procedimiento podés hacer que Master envíe órdenes que sean interpretadas y obedecidas por Slave.

Por ejemplo, Master envía “T”. Slave recibe un byte y si ese byte corresponde al caracter “T”, lee el valor del sensor de temperatura y lo devuelve a Master, que lo lee y si es menor a una temperatura predeterminada activa el relé de un calefactor. Ya no es tan inútil, no?

Con un poco de imaginación y talento no te será difícil crear tu propio “protocolo” de comandos para intercambiar órdenes y respuestas entre un Master y un Slave, o varios. Te será muy útil y necesario seguramente aprender o refrescar un poco las bases de la comunicación seríal basada en transmisión de bytes y un poco de sistemas numéricos para ayudarte a transmitir valores mayores a 255 o menores a 0 u otro tipo de datos.

Esa parte, se la dejo a Google.

 

 

 


Buscar en JADM

Biblioteca