Vamos a programar #25 - Inútil Apps #2 - Clock View

Hola a todos, el día de hoy vamos a realizar otro pequeño proyecto con arduino, es muy simple en realidad, pero creo que sirve para reforzar lo básico, además, si cómo yo, eres fanático de los LED's de seguro este proyecto te encantará.


Cuando hice el proyecto para mostrar la información de ITunes en las matrices LED, usaba una librería que se encargaba de desplegar las letras, los números y además, también proporcionaba algunos efectos básicos: scroll a la derecha, scroll a la izquierda, etc.

Para está ocasión, vamos a hacer algo un poco más sencillo, porque me parece un desperdicio de recursos utilizar toda la librería que use en el proyecto antes dicho para mostrar la hora.

Para los componentes de hoy vamos a requerir:
  1. Un arduino Uno/Mega/Nano.
  2. Un protoboard.
  3. Dos o más matrices led con driver Max7219.
  4. Modulo de reloj en tiempo real con DS1302.
  5. Liberia "LedControl.h"
  6. Liberia "DS1302.h"
  7. Algunos cables jumper para hacer las conexiones.
  8. Un par de manos (o en su defecto una).

Las conexiones.

Lo primero que debemos de hacer las conexiones entre los componentes. Yo en mi caso voy a usar 3 matrices LED, justo ahora compre más por internet, pero como van a tardar mas de 15 días en llegar, solo usaré las que tengo disponibles.
Las conexiones que voy a poner en este post lo más seguro es que cambien un poco en futuras actualizaciones del proyecto, por lo que si quieres usar pines diferentes en el arduino, eres libre de hacerlo.


Para empezar, vamos a conectar las matrices de izquierda a derecha, es decir si miramos de frente, la primer matriz estará al lado izquierdo, y la ultima estará al lado derecho.
Las conexiones de la matriz que se conecta al arduino irán de las siguiente manera:
  1. VCC. Se conecta a +5 voltios.
  2. GND. Se conecta a tierra.
  3. DIN. Lo conectaremos al pin 12 del arduino.
  4. CS. Lo conectaremos al pin 11 del arduino.
  5. CLK. Lo conectaremos al pin 10 del arduino.
Para la siguiente matriz solo conectaremos las salidas iguales con iguales, es decir:
  1. VCC. Se conecta a VCC en la entrada de la siguiente matriz.
  2. GND. Se conecta a tierra.
  3. DIN. Lo conectaremos a DIN en la entrada de la siguiente matriz.
  4. CS. Lo conectaremos a CS en la entrada de la siguiente matriz.
  5. CLK. Lo conectaremos CLK en la entrada de la siguiente matriz.
Las otras se conectaran de la misma forma, hay que recordar que, cómo máximo se pueden usar ocho por cada objeto "LedControl".

Para el modulo de reloj, las conexiones se harán de la siguiente manera:
  1. VCC. Se conecta a +5 voltios.
  2. GND. Se conecta a tierra.
  3. CLK (Serial clock). Lo conectaremos al pin 9 del arduino.
  4. DAT (IO). Lo conectaremos al pin 8 del arduino.
  5. RST (Chip enable). Lo conectaremos al pin 7 del arduino.
Una vez que se realizaron las conexiones anteriores, la parte del hardware está lista, ahora vamos a ver el código que hace funcionar las cosas..

El código en C.

Primero vamos a ver el código fuente completo y después explicare cada una de las partes que lo compone.

//Clockview 1.0
#include <DS1302.h>
#include "LedControl.h"
//Constantes para los pines usados en la matriz
const int MaxDIn = 12;
const int MaxCS = 11;
const int MaxCLK = 10;
int MaxNDevices = 3;
//Constantes para los pines usados en el reloj
const int kCePin = 7;  // RST
const int kIoPin = 8;  // Dat
const int kSclkPin = 9;  // Serial Clock
//Inicializacion de la matriz
//DIN,CLK,CS
LedControl lc = LedControl(MaxDIn, MaxCLK, MaxCS, MaxNDevices);
//Inicializacion del reloj
DS1302 rtc(kCePin, kIoPin, kSclkPin);
//Algunas variables
int MatrixB = 1;
//Matriz con los "Numeros"
const unsigned char Numbers[] = {
 B11111, B10001, B11111, //0
 B10010, B11111, B10000, //1
 B11101, B10101, B10111, //2
 B10001, B10101, B11111, //3
 B00111, B00100, B11111, //4
 B10111, B10101, B11101, //5
 B11111, B10101, B11101, //6
 B00001, B00001, B11111, //7
 B11111, B10101, B11111, //8
 B00111, B00101, B11111, //9
 B11111, B00101, B00111, //A
 B11111, B01100, B11111, //M
 B11111, B00101, B00111, //P
};
//Funcion para escribir los numero en la matriz.
void PrintNumber(byte NumberOne, byte NumberTwo, byte Device){
 for (int X = 1; X < 8; X++){
  if (X < 4){
   lc.setRow(Device, X, Numbers[NumberOne * 3 + X - 1]);
  }
  if (X == 4){
   lc.setRow(Device, 4, 0);
  }
  if (X > 4){
   lc.setRow(Device, X, Numbers[NumberTwo * 3 + X - 5]);
  }
 }
}
//Imprimir el tiempo en las matrices y en el monitor serie
void printTime(){
 Time t = rtc.time();
 char buf[10];
 snprintf(buf, sizeof(buf), "%02d:%02d:%02d", t.hr, t.min, t.sec);
 PrintNumber(t.hr / 10, t.hr % 10, 0);
 PrintNumber(t.min / 10, t.min % 10, 1);
 PrintNumber(t.sec / 10, t.sec % 10, 2);
 Serial.println(buf);
}
//Convertir los dias
String dayAsString(const Time::Day day) {
 switch (day){
  case Time::kSunday: return "Sunday";
  case Time::kMonday: return "Monday";
  case Time::kTuesday: return "Tuesday";
  case Time::kWednesday: return "Wednesday";
  case Time::kThursday: return "Thursday";
  case Time::kFriday: return "Friday";
  case Time::kSaturday: return "Saturday";
 }
 return "(unknown day)";
}
//Setup
void setup(){
 for (int CurrentDevice = 0; CurrentDevice < MaxNDevices; CurrentDevice++)
 {
  lc.shutdown(CurrentDevice, false);
  lc.setIntensity(CurrentDevice, MatrixB);
  lc.clearDisplay(CurrentDevice);
 }
 Serial.begin(9600);
 //Esta parte se usa para actualizar la hora.
 //rtc.writeProtect(false);
 //rtc.halt(false);
 //Time t(2016, 12, 7, 23, 57, 00, Time::kWednesday);
 //rtc.time(t);
}
//Loop
void loop() {
 printTime();
 delay(1000);
}

Lo primero que hacemos es incluir las librerías "LedControl.h" y "DS1302.h", creamos constantes para los pines que usara la primer matriz, para el reloj y después creamos los objetos "lc" y "rtc" para la matriz y para el reloj respectivamente.
El objeto lc se le asigna un objeto "LedControl"; el cual recibe cuatro parámetros: los números de pines a usar, el primer parámetro debe de ser el pin que se usará para conectará a "DIN" en la primer matriz, el segundo conectará a "CLK", el tercero conectará a "CS" y finalmente el cuarto, sirve para indicar cuantas matrices se usarán con ese objeto.
Para el reloj, crearemos un objeto "DS1302" y para "inicializarlo", le pasaremos como parámetros, los pines que se usarán. El primer parámetro es el pin que conecta a "RST", el segundo parámetro es el pin que conecta a "DAT" y finalmente el tercero es el pin que conecta "CLK".
Una vez que tenemos lo objetos listos, creamos unas variables, la primera es "MatrixB" que las usaremos para almacenar el brillo que tendrán las matrices, por ahora la única forma de cambiarlo, es editando el valor que le asignamos, pero un poco mas adelante, seremos capaces de cambiar el brillo de forma externa.

Después viene una matriz que contiene los datos que vamos a usar para crear los "números" que después veremos en las matrices, pero antes de eso hay que saber como es que se controlan los LED´s de las matrices.

LedControl y Matrices LED.

Para este proyecto estamos usando la librería LEdControl.h, está nos ofrece varias maneras de controlar los LED's de la matriz, las funciones disponibles son: setLed, setRow y setColum.
La función setLed tiene una forma similar a la siguiente:
void setLed(int addr, int row, int col, boolean state);
El primer parámetro indica en que dirección se encuentra la matriz que queremos usar (de cero a siete), es decir, si tenemos 4 matrices conectadas en "serie", y queremos prender el primer led de la tercera matriz, tendremos que poner un 3 en el primer parametro.
El segundo parámetro indica en que columna está el LED que queremos encender (mejor dicho controlar).
El tercero indica en que columna está el LED que queremos controlar.
El último parametro indica el estado en que vamos a poner el LED, cuando se pone "True", el LED se enciende y cuando se pone "False", el LED se apaga.
void setRow(int addr, int row, byte value);
Está funcion recibe 3 parametros, el primero es el mismo que el de la funcion anterior, el segundo indica que fila es la que se va controlar, despues, el ultimo parametro nos indica que LED´s son los que se van a prender.Para este último, hay una forma relativamente sencilla de cómo establecer los LED´s que deben de prender, tomando por ejemplo el numero 2 y el número 5 que queremos mostrar,
Como lucirá el numero 25
Antes que nada, es importante tomar en cuenta donde se ubica el origen, en mi caso (y supongo que para los que tienen un kit similar al que uso yo), el origen se encuentra en la esquina inferior izquierda, viendo la matriz como en la primer imagen, por lo que las columnas están en el lado izquierdo de la matriz y las filas en el lado inferior, entonces los LED's se controlaran de abajo hacia arriba y de izquierda a derecha si usamos la funcion "setRow". una vez que ya has determinado donde empieza la matriz, se deben de hacer los cambios pertinentes.
Para asignar el ultimo parámetro, miremos la imagen anterior, en ella se puede ver claramente que cuando un led está encendido tiene el valor de 1 y cuando está apagado es 0 y cada digito esta compuesto por 3 llamadas a la funcion "setRow", para hacer de forma rapida el dos, podriamos llamar a la función "setRow" y como ultimo parámetro el  valor "B00011101" en la primera llamada, en la segunda, el ultimo parametro "B00010101" y en la tercera llamada a la función usar cómo ultimo valor "B00010111".
Cómo los 0´s que están al lado izquierdo no son significativos, podemos omitirlos y simplemente poner "B11101" para la primer llamada a la funcion "setRow", si te fijas en el código, veras que hay algunos valores que conservan los ceros a la izquierda, esto solo es con fines "estéticos" y para que todos los valores estén alineados.

Mostrando dígitos en las matrices.

Para mostrar los dígitos en las matrices, he creado una función que se encarga de eso. La función "PrintNumber", recibe tres parámetros, el primero es el primer numero que queremos mostrar (al lado izquierdo), el segundo es el numero que queremos mostrar y finalmente,se debe de indicar en que numero de matriz vamos a despegarlos.
Todos los datos de los numero están pensados de tal forma que se puedan poner dos dígitos por cada matriz, entonces cada una nos da un rango de 00 a 99, pero para mostrar algo cómo la hora. los segundos o los minutos funciona. Para que la función "funcione", debemos de alinear los datos que componen a cada numero, si te fijas bien leemos de tres en tres y debido al acomodo que tiene la matriz "Numbers", cuando le pedimos el número 0, leerá los valores Numbers[0], Numbers[1] y Numbers[2].
La formula que dexcribe cómo se obtienen los valores del primer dígito es la siguiente:
Indice = NumeroDado * 3 +ValorDelIterador - 1
 Y para el segundo:
Indice = NumeroDado * 3 +ValorDelIterador - 5
Y con eso, podemos obtener los valores del 0 al 9 y a partir de ahi, componer cualquier numero. Por eso es importante el orden en que está cada parte de la matriz (arreglo desde este momento para evitar confusiones.).

Completando el resto del código.

La función "PrintTime" se encargará de obtener la hora y de llamar a la función "PrintNumber" para desplegar la información en la matriz LED, debido a que hay que pasar los dígitos por separado, no es posible usar "12" cómo parámetro para la función "PrintNumber", entonces lo que hacemos es dividir, primero entre 10 y para el segundo dígito, solo tomamos el residuo de la división, por lo que si tenemos el numero 21, al hacer la división entre 10, obtenemos 2; este lo pasamos cómo primer parámetro y luego obtenemos el residuo que es 1 y lo asignamos como valor del segundo parámetro, ademas de que la hora la mostramos en el monitor serie, eso es opcional pero para fines de debug funciona.
Después viene la parte de las funciones propias del arduino, "setup()" y "loop()", En la parte de setup, es donde vamos a inicializar los componentes (prácticamente aquí todo lo que se necesita ejecutar una sola vez), ademas hay unas lineas que están comentadas, estas solo sirven para ajustar la hora del reloj, si es la primera vez que vas a usar el modulo de reloj, o si cambias la batería o hiciste cualquier cosa y quieres establecer la fecha y hora, esas lineas las debes de des-comentar y editar solo la que contiene la fecha y hora, cuando hayas cargado el proyecto al arduino, si modificas alguna parte del código y ya no quieres actualizar la hora, debes de comentar de nuevo esas lineas para evitar que la hora se cambie de nueva cuenta.
Finalmente en "loop()" ponemos el código que se va a ejecutar de manera cíclica, en este caso, solo es la función que muestra la hora y un retraso de 1000ms que se usa para que la hora solo se actualice cada segundo.

Y bien, por ahora es todo, pero en el próximo post vamos a agregar un poco mas de hardware para que el uso sea mas sencillo. Cómo siempre, el código lo puedes bajar de mi dropbox para que lo revises.
Por ahora es todo. Los leo luego.

No hay comentarios.