74HC595 shift register para controlar display de 7 elementos

En un post anterior hablaba de como usar 8 puertos del Arduino para controlar un display de 7 elementos, es una manera rápida pero poco practica de controlar estos elementos.
Y es ocupar 8 salidas en el Arduino nos reduce la posibilidad de hacer otras cosas, nos deja 6 salidas libres.
Podemos usar un chip 74HC595 que nos sirve para controlar 8 salidas digitales mediante 3 salidas del Arduino, ademas se puede encadenar, por lo que podemos controlar bastantes salidas y tener libres 11 salidas del Arduino para agregarle cosas.
Antes de seguir, he de aclarar que este post y los demás relacionados son los menos técnicos, los menos formales y son solamente mis descubrimientos (no estudie nada relacionado a la electrónica o programación), pero hay que compartír lo que uno aprende, quizá haya personas como yo que no queremos ser ingenieros en algo para hacer algún aparato útil.
Hay una guía muy interesante aquí sobre como usar un 74HC595 con un Arduino para controlar LEDs, de hecho hay muchos otros tipos de shift register, pero usemos este (y aprovechando que me hice de 25 de estos a un súper precio).
El chip 74HC595 tiene 16 pins, 8 de ellos para controlar mismo numero de salidas, 3 para control 1 salida de datos (para conectar otros 74HC595)
Para conectarlo seguimos la recomendación de la pagina de Arduino
| Pin | Conectar a |
|---|---|
| 15, 1-7 | salidas digitales, leds, display |
| 8, 13 | GND |
| 9 | al pin 14 del segundo 74HC595 |
| 10, 16 | 5V |
| 11 | Arduino D12 |
| 12 | Arduino D8 |
| 14 | Arduino D11 |
Y aquí esta la imagen de dos 74HC595 conectados a 2 displays de 7 segmentos, el orden de los pins es sencillo, el pin-disp quedaria: 15-A, 1-B, 2-C, 3-D, 4-Dp, 5-E, 6-F, 7-G

Hasta aquí todo bien, pero empezamos con los problemas
Mis display son de Anodo común, lo que significa que un segmento se enciende al apagarse un pin del 74HC595, cual es el problema? pues tenemos que cambiar el modo en que enviamos los datos
para desplegar un 0 usando un display de cátodo común enviaríamos un byte 01101111 desde arduino, este encendería esos segmentos y tenemos un lindo 0; pero en uno de ánodo común tendríamos que enviar un byte 10010000 para que deje apagados (y por ende enciendan en el AC)
Ademas, claro, el byte depende de como hayamos hecho la conexión entre display y el 74HC595; así que si elegimos otro orden en los pins pues habrá que cambiar el byte de control. Lo que hace esto en poco standard y no podemos robarnos usar código de otras personas que hayan publicado.
Ya estando en el IDE de Arduino controlar el shift register es de lo mas fácil, muy pocas lineas de programación, ya que hay una instrucción que hace todo el trabajo por nosotros: shiftOut
/* Ejemplo de uso de un display de 7 segmentos ánodo común
usando un shift register 74HC595
Ivan Capdeville - ivan@darkapple.org
*/
const int latchPin = 8;
const int clockPin = 12;
const int dataPin = 11;
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop() {
digitalWrite(latchPin,LOW);
shiftOut(dataPin, clockPin, LSBFIRST, *); // * caracter del segundo display
shiftOut(dataPin, clockPin, LSBFIRST, *); // * caracter del primer display
digitalWrite(latchPin, HIGH);
el código es simple, declaramos las salidas del arduino que conectamos al 74HC595, las configuramos como salidas digitales y vamos a usar esta secuencia para activar los caracteres
digitalWrite(latchPin,LOW);
cuando el latchPin se apaga el shift register se prepara para recibir nuevos datos
shiftOut(dataPin, clockPin, LSBFIRST, *);
Esta parte es quizá la mas interesante y complicada de dominar al inicio, hay que elegir como va leer el byte de entrada, si de derecha a izquierda (LSBFIRST) o de izquierda a derecha (MSBFIRST) y en que nos afecta esto? pues determina como vamos a confeccionar los caracteres, si usamos MSBFIRST usaremos el byte 10010000 para mostrar un 0, si usamos LSBFIRST usaremos el byte 00001001
ya que elegimos que segmentos vamos a querer, ponemos una linea por cada display (en orden inverso) ponemos esta linea para prender el latchPin y que se genere la instrucción
digitalWrite(latchPin,HIGH);
Afortunadamente para los que no queremos meternos tanto en rollos técnicos, resulta que podemos usar caracteres decimales para mostrar segmentos (aquí viene la rechifla después de leer tanto sobre números binarios)
Podemos usar números del 0 al 255 para controlar los segmentos a desplegar, pero no es tan sencillo como poner un 5 para desplegar un 5, pues no, tienen su representación, así que usamos, por ejemplo, el 14 para desplegar el numero 3 y el 156 para el numero 4. Aquí es donde usar binarios se vuelve mas simple (8 caracteres fijos y un 1 o un 0 para elegir si se muestra o no el segmento, así que todos los segmentos prendidos en un display de ánodo común seria un byte 00000000 (0) todos apagados 11111111 (256))
Esto hace mucho mas fácil el elegir que segmentos se prenderán (o en una matriz de leds lo mismo) se vuelve mas gráfico el elegir, usando números decimales aun no veo una relación o secuencia (quizá la haya pero ya después buscare)
Al final de tanto rollo, mi recomendación es usar LSBFIRST si usamos un display de anodo comun y byte binario, si usamos numeros decimales y el anodo comun hay que usar MSBFIRST y la conversion a decimal del byte
| Digito en display | Byte binario | Decimal |
|---|---|---|
| 0 | 10010000 | 9 |
| 1 | 11111001 | 159 |
| 2 | 01010100 | 42 |
| 3 | 01110000 | 14 |
| 4 | 00111001 | 156 |
| 5 | 00110010 | 76 |
| 6 | 00010010 | 72 |
| 7 | 01111000 | 31 |
| 8 | 00010000 | 8 |
| 9 | 00110000 | 12 |
| . | 00010000 | 247 |