Control de 8 Dígitos con MAX7219

El integrado MAX7219 es un conversor serial paralelo con algunas funciones extra, como control PWM de brillo para los LEDs, tablas de verdad de dígitos de 7 segmentos, ya que es posible utilizar este integrado tanto para controlar una matriz de leds como para controlar display de 7 segmentos.
El MAX7219 posee una interfaz SPI (Control mediante Reloj, Dato y Carga).
Este dispositivo posee dos salidas de 8 bit conformando el control de 64 puntos (8x8), o bien 8 dígitos de 7 segmentos con su punto.

Las especificaciones son las siguientes:

o Interfaz serial de hasta 10MHz
o Control Individual de cada LED
o Decodificador de 7 segmentos o sin decodificador
o Modo bajo consumo de 150uA
o Control de Brillo
o Saludo inicial en los display para corroborar el funcionamiento
o Interfaz SPI, QSPI y Microwire
o Tensión de alimentación hasta 6V
o Corriente maxima de hasta 500mA
o Encapsulado SMD y THT
o Control de corriente externo mediante una resistencia.

La configuración típica que encontraremos en el datasheet sera la siguiente, aunque la esta mostrando con los 8 dígitos, podríamos utilizar una matriz de 8x8 puntos.:



En este caso se ha realizado el control SPI por software, aunque es posible hacerlo por hardware con el microcontrolador, la opción por software es sencilla para aquellos microcontroladores que no poseen la interfaz.

Como mencionaba anteriormente el MAX7219 posee algunas opciones especiales, no es solo un conversor serial paralelo.
Para ello debemos analizar los registros internos del MAX.



0xX0: En esta posición tendremos el No-Operation, es decir, no se realizara ninguna acción, pero no esta apagado el dispositivo sino que los leds en su salida están apagados.

0xX1 a 0xX8: Sera la elección de los dígitos o columnas, que podremos hacerlo de forma directa con estos valores.

0xX9: Es el registro que controlara el tipo de decodificación, si sera binaria o 7 segmentos.

0xXA: Con esta dirección controlaremos el brillo de los leds, que puede setearse al principio o variarse dinámicamente dando un efecto de tonalidad si quisiéramos dibujar en una matriz de 8x8 puntos.

0xXB: Esta dirección se utiliza si no estamos seguros de cuantos dígitos vamos a usar (por si queremos realizar una librería estándar).

0xXC: En esta dirección pasaremos al modo bajo consumo o lo despertaremos.

0xXF: Este sera un comando de test del Display.

El registro de tipo de decodificación nos indicara si decodificamos 7 segmentos los 8 dígitos, o para el primer dígito y el resto no, los primeros 4 dígitos y los otros 4 no y por ultimo todos en binario, para ello debemos decidir si al registro que posee el valor 0x09 le enviaremos 0x00, 0x01, 0x0F o 0xFF.



En esta otra tabla podremos ver la tabla de verdad interna donde tendremos la codificación para controlar los display de 7 segmentos si eligiéramos esa opción.



Ahora controlaremos el brillo de cada led, para ello debemos configurar el valor que nos demuestra la tabla y enviarlo al registro 0x0A, en esta tabla podremos ver que el valor va de 0 a 15 y en la primer columna veremos el ciclo de trabajo PWM para los leds.



La opción de elegir la cantidad de dígitos de forma dinámica requiere de la función ScanLimit, lo que realizara mas eficientemente la librería para utilizarla de forma universal.
Para ello debemos mover el valor de dígitos al registro 0x0B.



Por ultimo el registro encargado de apagar o poner en modo Sleep el circuito para que el consumo se reduzca a 150uA, también podremos despertarlo para ser utilizado, es muy útil en sistemas con baterías.


El circuito que he implementado es sumamente sencillo y no requiere de mucha explicación pero como podremos ver todo esta resuelto con el MAX7219, el microcontrolador solo utiliza 3 salidas digitales, lo que nos da la opción de usar un microcontrolador sencillo de 8 pines para ahorrar dinero y espacio en el circuito.


El programa que he realizado solo envía valores numéricos estáticos al circuito ya que para el ejemplo esta bien y luego uno puede modificar dinámicamente la función escribe7219() con los valores que quiera.

Lo primero que encontraremos serán las macros de definición para los pines de salida que solo hay que elegir cual sera el que quieren usar o queda cómodo en el diagrama impreso.

  1. //Pines a utilizar
  2. #define CLK  PIN_B6
  3. #define LOAD PIN_B5
  4. #define DATA PIN_B4

Luego tendremos las direcciones del registro mencionado anteriormente con cada cuadro de configuración que serán utilizados mas adelante en la inicialización del MAX.

  1. //Variables del MAX7219 segun Datasheet
  2. #define decodifica 0x09
  3. #define brillo 0x0A
  4. #define cantDigitos 0x0B
  5. #define bajoConsumo 0x0C

Luego se han realizado varias funciones en el código que podrían hacerse en menos pero esta forma permite la reutilización de código mas eficiente.

  1. //Funcion de Clock
  2. void clock7219(){

  1. //Funcion para cargar el valor
  2. void load7219(){

  1. //Funcion para enviar el dato de 16bit
  2. void envia7219(long dato){

  1. //Funcion para construir el dato a enviar
  2. void creaDato(byte modo, int datoEntrante){

  1. //Funcion para escibir, Digito y Valor (1xxx xxxx DP)
  2. void escribe7219(byte digito, int dato){

  1. //Modo bajo consumo 1=WakeUp, 0=Sleep
  2. void bajoConsumo7219(int modoOperacion){

  1. //Modo de codificacion Binario(15) o Decada
  2. void decodifica7219(int modoDecodifica){

  1. //Configuracion del nivel de brillo 1 a 15
  2. void brillo7219(int nivelBrillo){

  1. //Configuracion de la cantidad de digitos 1 a 8
  2. void cantDigitos7219(int totalDigitos){

De todas las funciones podríamos destacar la mas importante como la función creaDato() que sera llamada del resto de las funciones para tomar el valor de registro y de configuración como se menciono en los cuadros de configuración de registros anteriores.

Luego las funciones de manejo de bits como clock, dato y carga que son las necesarias para crear la comunicación con el integrado.

Por ultimo la función inicializa que se encarga de configurar los parámetros de registro en los cuadros principalmente antes de comenzar el ciclo repetitivo del programa.

La función que enviara el valor es escribe7219() donde enviaremos dígito y valor.

Ahora el programa completo:

  1. #include <16F883.h>
  2. #use delay(clock=4000000)
  3. //Pines a utilizar
  4. #define CLK  PIN_B6
  5. #define LOAD PIN_B5
  6. #define DATA PIN_B4
  7. //Variables del MAX7219 segun Datasheet
  8. #define decodifica 0x09
  9. #define brillo 0x0A
  10. #define cantDigitos 0x0B
  11. #define bajoConsumo 0x0C
  12. //Variable de formateo de salida
  13. long datoSerial=0;
  14. //Funcion de Clock
  15. void clock7219(){
  16.    output_low(CLK);
  17.    delay_ms(1);
  18.    output_high(CLK);
  19. }
  20. //Funcion para cargar el valor
  21. void load7219(){
  22.    output_low(LOAD);
  23.    delay_ms(1);
  24.    output_high(LOAD);
  25. }
  26. //Funcion para enviar el dato de 16bit
  27. void envia7219(long dato){
  28.    int cont;
  29.    for(cont=0;cont<16;++cont){
  30.       output_bit(DATA,shift_left(&dato,2,0));
  31.       clock7219();
  32.    }
  33.    load7219();
  34. }
  35. //Funcion para construir el dato a enviar
  36. void creaDato(byte modo, int datoEntrante){
  37.    datoSerial=0x00;
  38.    datoSerial<<=4;
  39.    datoSerial|=modo;
  40.    datoSerial<<=8;
  41.    datoSerial|=datoEntrante;
  42.    envia7219(datoSerial);
  43. }
  44. //Funcion para escibir, Digito y Valor (1xxx xxxx DP)
  45. void escribe7219(byte digito, int dato){
  46.    creaDato(digito, dato);
  47. }
  48. //Modo bajo consumo 1=WakeUp, 0=Sleep
  49. void bajoConsumo7219(int modoOperacion){
  50.    creaDato(bajoConsumo,modoOperacion);
  51. }
  52. //Modo de codificacion Binario(15) o Decada
  53. void decodifica7219(int modoDecodifica){
  54.    creaDato(decodifica, modoDecodifica);
  55. }
  56. //Configuracion del nivel de brillo 1 a 15
  57. void brillo7219(int nivelBrillo){
  58.    creaDato(brillo, nivelBrillo);
  59. }
  60. //Configuracion de la cantidad de digitos 1 a 8
  61. void cantDigitos7219(int totalDigitos){
  62.    creaDato(cantDigitos, totalDigitos);
  63. }
  64. void inicia7219(){
  65.    creaDato(bajoConsumo,1);
  66.    //Deco 7seg, 255 para 8dig, 15 para 4dig
  67.    creaDato(decodifica,255);
  68.    //Cant 7seg, 0 al 7
  69.    creaDato(cantDigitos,7);
  70.    //Brillo minimo 0 y maximo 15
  71.    creaDato(brillo,15);
  72. }
  73. void main(){
  74.    inicia7219();
  75.    while(true){
  76.       escribe7219(1,0);
  77.       escribe7219(2,0);
  78.       escribe7219(3,0);
  79.       escribe7219(4,1);
  80.       escribe7219(5,2);
  81.       escribe7219(6,1);
  82.       escribe7219(7,7);
  83.       escribe7219(8,0);
  84.    }
  85. }

2 comentarios:

  1. Funciona bien con el modulo físico, pero ¿Cómo agrego un segundo modulo?, si conecto el DOUT de l primero con el DIN del segundo(como esta en la página 13 del datasheet https://datasheets.maximintegrated.com/en/ds/MAX7219-MAX7221.pdf) solo se repiten los números en las mismas posiciones.

    ResponderBorrar