2021-03-13
Conexión de un display de 4 digitos.
En la entrada anterior vimos como se conecta un display de 7 segmentos a un Arduino, pero obviamente es lo menos práctico que se puede hacer con un display ya que siempre nos interesara mostrar un número más grande.
Como montar un display de 4 digitos
Lo primero que nos viene a la cabeza es montar un display de un digito por cada Arduino, con lo cual necesitamos 7*4=28 pines. Obviamente un Arduino UNO es insuficiente, con lo cual hemos de recurrir a un Mega, recurrir a un chip que haga el trabajo o alguna por hardware/software.
Aquí vamos a discutir dicha técnica hardware/software.
¿Quien ha dicho que el display deba estar siempre encendido? Podríamos simplemente encender un digito, después otro, el siguiente y por fin el último. Si lo hacemos lo suficientemente rápido, podemos engañar a nuestro ojo haciéndole creer que los cuatro displays estan encendidos a la vez, lo cual no es verdad.
¿Cómo logramos que ocurra tal cosa?. Recordemos que los display suelen tener o el ánodo o el cátodo común, si podemos colocar un "interruptor" en él, podremos encenderlo y apagarlo a voluntad. Tal interruptor existe y se llama transistor
Así que colocando cuatro transistores en cada común y controlándolo por software hemos conseguido encender y apagar el display. Además hemos reducido el numero de pines a usar a 11 (7 para los segmentos y 4 para los comúnes).
En la imagen anterior hemos usado un display de cátodo común y cuatro transistores NPN. Si el display fuera de ánodo común deberiamos usar transistores PNP y tener cuidado con la polarización de estos.
Programando la rutina
Como dijimos anteriormente, esta técnica se basa en mostrar los digitos uno a uno, por lo tanto el primer paso es tener una función que nos de el digito correspondiente a las unidades, decenas, centenas, etc.
// Obtiene de un entero el digito en la posicion 'p', siendo 0 las unidades, // 1 decenas, 2 centenas, 3 millares, etc. int digitopos(int v, int p) { int d, r; d = v; int i=0; while (i<=p) { r = d % 10; d = d / 10; i++; } return r; }
Lo que hacemos con este código es hacer una división entera entre 10 tantas veces como posiciones queremos quedándonos al final con el resto.
Lo siguiente que necesitamos es una rutina para encender los segmentos según el digito que tenemos:
// Muestra un digito, encendiendo los corresponientes segmentos para formar un // número. // En el array segmentos tenemos un byte cuyo bit indica que led ha de // encenderse. const uint8_t numeros[10] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67 }; void printd(uint8_t v) { if ( v>=0 && v<=9 ) { for (int i=0; i<7; i++) { digitalWrite(segmentos[i], bitRead(numeros[v], i)); } } }
Ahora ya podemos empezar a controlar los comunes de cada segmento. Para ello necesitamos un array donde estén almacenados los pines que activan cada digito del display.
El siguiente paso es recorrer el valor a mostrar, que estará almacenado en una variable entera con la función digitopos encenderlo y mostrarlo.
Para entender mejor el proceso podemos usar dos funciones: una usando delayMicroseconds y la otra micros. El funcionamiento es similar, salvo que al utilizar retrasos, detenemos el programa y con micros no.
const uint8_t numeros[10] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67 }; const uint8_t segmentos[7] = { A1, A3, 10, 11, 12, A2, 9 }; // Este array contiene los pines de atacan la base de los transistores. const uint8_t digitos[4] = { 13, A0, 5, 6 }; // Variables auxiliares. uint8_t digitoActual; uint32_t td; int valorDisplay=0; // Valor actual que se mostrará en el display. // Versión utilizando delay, es más fácil de enteder. Se realiza un bucle for // para cada digito, mostrando el valor un tiempo, apagando y mostrando el // siguiente. void actualizaDisplay1() { for (int d=0; d<4; d++) { printd(digitopos(valorDisplay, 3-d)); digitalWrite(digitos[d], HIGH); delayMicroseconds(800); digitalWrite(digitos[d], LOW); delayMicroseconds(200); } } // Versión utilizando micros. Cada vez que el temporizador haya transcurrido // se apaga ese digito y se enciende el siguiente. void actualizaDisplay2() { if ( micros()-td > 2000 ) { digitalWrite(digitos[digitoActual], LOW); digitoActual++; if ( digitoActual==4 ) digitoActual = 0; printd(digitopos(valorDisplay, 3-digitoActual)); digitalWrite(digitos[digitoActual], HIGH); td = micros(); } }
Podemos cambiar la velocidad de refresco (la velocidad a la que se van a actualizar los digitos, cambiando los valores de retraso o de temporización correspondiente. Si subimos mucho el tiempo, llegaremos a ver el proceso de como se hace digito a digito.