Revisando en el trastero todo aquello que me pudiera servir para mis arduinos, me encontré algún que otro descodificador. De uno de ellos obtuve este panel:
Básicamente tenemos ocho botones, un display de 4 dígitos, dos leds bicolores (rojo-verde) y tres de color (rojo, amarillo, verde) y un receptor IR con su mando a distancia… todo por el módico precio de averiguar cómo demonios controlar esto con un Arduino. Tenía la esperanza de que al tener tantos componentes en la placa y sólo un bus de diez líneas como única comunicación con la placa base sería posible controlar el panel de forma sencilla con Arduino.
Así que lo primero que hice fue revisar la trasera del frontal para ver qué circuitos integrados (aka garrapatas negras) lleva el trasto:
En la foto no se observa, pero con una lupa y la iluminación adecuada pude comprobar que los dos únicos circuitos integrados son el MM74HC595M:
Una rápida búsqueda nos da como resultado que el MM74HC595M es un registro de desplazamiento de 8 bits (8bits Shift Register) del que hay sobrada documentación con respecto a cómo controlarlo con Arduino. Así que mi primera intuición empezaba a cobrar fuerza.
Sin embargo necesitaba saber el esquema para poder averiguar cómo controlar el panel. Así que en dos o tres días ya tenía los primeros esquemas a mano de la parte de los cuatro dígitos de siete segmentos y en dos o tres días más el esquema definitivo:
Del esquema se puede ver que con sólo 8 cables (6 si descontamos Vcc y GND) podemos controlar los 4 dígitos de siete segmenos, los 5 leds (dos de ellos bicolor), recibir las señales del mando a distancia y saber qué pulsador es el que se ha accionado.
Lo más fácil es utilizar el receptor de infrarrojos, ya que con conectar la alimentación (pin 1 del panel a GND y pin 9 a +5V) y conectar el pin 2 del panel a una entrada digital del Arduino ya podemos jugar con un mando a distancia.
Evidentemente para jugar con el resto de elementos hay que pensar un poco más. Por ejemplo, algo que en los ejemplos y circuitos que he visto con Arduino y el 74595 suelen obviar el pin Enable de estos chips. El panel lo utiliza y le da salida, siendo muy útil pues si en setup lo ponemos en HIGH antes de poner el panel en su configuración inicial (la que decidamos que deba ser) y una vez establecida dicha configuración ponemos el Enable a LOW habremos tenido el panel completamente apagado (los leds y los segmentos de los dígitos) hasta obtener una situación estable y conocida:
void setup() { pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(enablePin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(swPin, INPUT); // Desactivamos las salidas de los 74595 digitalWrite(enablePin, HIGH); // Establecemos la condición inicial del Panel digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, 0b00001111); shiftOut(dataPin, clockPin, LSBFIRST, 0b00110000); digitalWrite(latchPin, HIGH); // Activamos las salidas de los 74595 digitalWrite(enablePin, LOW); }
La verdad, el resultado es muy chulo, sobre todo por las opciones que me da sin tener que cablear o soldar nada:
Y el código completo:
const byte Digits[] = { 0b00001110, // Digit 0 0b00001101, // Digit 1 0b00001011, // Digit 2 0b00000111, // Digit 3 }; const byte swMask = 0b00001111; const byte buttons[] = { 0b10001110, // 0 SW1 POWER 0b10001101, // 1 SW2 UP 0b10001011, // 2 SW3 DOWN 0b10000111, // 3 SW4 RADIO 0b01001110, // 4 SW5 MENU 0b01001101, // 5 SW6 LEFT 0b01001011, // 6 SW7 YES 0b01000111, // 7 SW8 RIGHT }; const byte dec7seg[] = { 0b00111111, // 0 0b00000110, // 1 0b01011011, // 2 0b01001111, // 3 0b01100110, // 4 0b01101101, // 5 0b01111101, // 6 0b00000111, // 7 0b01111111, // 8 0b01101111, // 9 }; const byte LedsRight = 0b00001111; const byte LedsRYG_G = 0b00100001; const byte LedsRYG_Y = 0b00100010; const byte LedsRYG_R = 0b00101000; const byte LedsRG_G1 = 0b00010001; const byte LedsRG_R1 = 0b00010010; const byte LedsRG_G4 = 0b00010100; const byte LedsRG_R4 = 0b00011000; const int dataPin = 11; // 74HC595 Pin 14 (GRIS) const int latchPin = 10; // 74HC595 Pin 12 (VERDE) const int clockPin = 9; // 74HC595 Pin 11 (MORADO) const int enablePin = 8; // 74HC595 Pin 13 (MARRON) const int swPin = 7; // AZUL byte LedsRG = 0b00000000; byte LedsRYG = 0b00000000; int wait = 0; void setup() { pinMode(latchPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(enablePin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(swPin, INPUT); digitalWrite(enablePin, HIGH); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, 0b00001111); shiftOut(dataPin, clockPin, LSBFIRST, 0b00110000); digitalWrite(latchPin, HIGH); digitalWrite(enablePin, LOW); } void Display (int Num, int wait) { for (int d = 0; d < sizeof(Digits); d++) { int N = int(Num / pow(10, d)) % 10; digitalWrite(latchPin, LOW); byte dataR = (dec7seg[N] << 4) | Digits[d]; byte dataL = (dec7seg[N] >> 4) | 0b00110000; shiftOut(dataPin, clockPin, LSBFIRST, dataR); shiftOut(dataPin, clockPin, LSBFIRST, dataL); digitalWrite(latchPin, HIGH); delay(wait); } } int readsw () { for (int sw = 0; sw < sizeof(buttons); sw++) { digitalWrite(latchPin, LOW); byte dataR = swMask & buttons[sw]; byte dataL = (~swMask) & buttons[sw]; shiftOut(dataPin, clockPin, LSBFIRST, dataR); shiftOut(dataPin, clockPin, LSBFIRST, dataL); digitalWrite(latchPin, HIGH); if (digitalRead(swPin) == LOW) return sw; } return -1; } const byte swLeds[] { 0b00000000, LedsRYG_G, LedsRYG_R, LedsRYG_R | LedsRYG_G, LedsRYG_Y, LedsRYG_Y | LedsRYG_G, LedsRYG_Y | LedsRYG_R, LedsRYG_Y | LedsRYG_R | LedsRYG_G, }; void loop() { int Num = millis() / 1000; LedsRG = 0b00000000; LedsRYG = 0b00000000; int sw = readsw(); if (sw >= 0) { LedsRG = LedsRG_G4; LedsRYG = swLeds[sw]; } if (Num % 2) LedsRG = LedsRG | LedsRG_R1; switch (sw) { case 1: if (sw == 1) wait += 10; for (int i = 0; i < 10; i++) { Display(wait, 0); delay(20); } break; case 2: if (sw == 2 && wait > 0) wait -= 10; for (int i = 0; i < 10; i++) { Display(wait, 0); delay(20); } break; case 4: Display(wait, 0); break; default: Display(Num, wait); } digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, LedsRight); shiftOut(dataPin, clockPin, LSBFIRST, LedsRYG); digitalWrite(latchPin, HIGH); digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, LedsRight); shiftOut(dataPin, clockPin, LSBFIRST, LedsRG); digitalWrite(latchPin, HIGH); }
Lo único que no estaría en un código de producción sería la variable wait de la función Display, que quedaría así:
void Display (int Num) { for (int d = 0; d < sizeof(Digits); d++) { int N = int(Num / pow(10, d)) % 10; digitalWrite(latchPin, LOW); byte dataR = (dec7seg[N] << 4) | Digits[d]; byte dataL = (dec7seg[N] >> 4) | 0b00110000; shiftOut(dataPin, clockPin, LSBFIRST, dataR); shiftOut(dataPin, clockPin, LSBFIRST, dataL); digitalWrite(latchPin, HIGH); } }
¿Por qué introducir una pausa variable entre el refresco de cada dídito?, pues simplemente como demostración de que sólo uno de los cuatro dígitos está encendido al mismo tiempo. Vamos, por aumentar el elemento didáctico, que a fin de cuentas esa es la excusa con la que me he comprado los juguetes…
Hace ya tiempo de mi última entrada de apuntes de electrónica. Fue la entrada sobre…
Looking for cheap multimeters I found the Zoyi ZT-300AB, for about €20 we have a…
In my search for interesting multimeters I came across a manufacturer whose multimeters were sold…
Desde que la industria empezó a deslocalizar sus fabricas llevando gran parte del peso de…
Desde que vi por primera vez una pinza amperimétrica quise tener una. Con la aparición…