Descripción
Los LEDs se fabrican en todos los tamaños y formatos imaginables. Las matrices de LEDs (o LED arrays) son una matriz de diodos LED normales y corrientes que se comercializa en multitud de formatos y colores. Desde las de un solo color, a las que tienen varios colores posibles, e incluso las hay de una matriz RGB
En esta sesión vamos a usar una matriz de 8×8 LEDs de color rojo, como demostración de cómo manejarla y de lo que se puede hacer con este tipo de material.
Utilizaremos una única matriz e iremos arrastrando, letras y símbolos, para demostración de lo que podríamos hacer con una docena.
La idea, es que podemos dibujar letras y símbolos, definiendo matrices de puntos para representar las letras, que luego sacaremos por el Display.
Por lo demás, son diodos LED totalmente normales, organizados en forma de matriz, que tendremos que multiplexar para poder iluminar uno u otro punto, tal y como se hace con el teclado matricial.
Este componente se presenta con dos filas de 8 pines cada una, que se conectan a las filas y las columnas.
Si los diodos se unen por el positivo, se dice que son matrices de Ánodo común y se se une por el negativo decimos que son de Cátodo común.
Dependiendo del fabricante podéis encontrar de ambos tipos.
Si ponemos HIGH en una columna, digamos la 2, no se iluminara nada aun. Pero cuando hagamos LOW en, digamos la fila 4, se cerrara el circuito a GND con una resistencia de limitación, por supuesto y el pin col 2 x fila 4, se encenderá.
Así pues, aplicar la regla número uno. Buscad el manual del fabricante en Google
RTFM, ( Read The Fucking Manual = Lee el puto manual).
Así pues vamos con el manual del 1588AS : Fíjate que aquí lo importantes es, la descripción de la matriz, donde nos habla de filas y columnas, pero sobre todo nos dice que pines del chip son cada fila y columna. Ya solo nos falta saber cuál de los pines es el uno, y aquí, yo no he sido capaza de localizar una marca que lo indique, a pesar de que si os fijáis, el manual marca con una cruz el pin 1, pero en mi chip, no he sido capaz de encontrar ninguna marca asimétrica.
Lo que yo he hecho ha sido conectar 5V y GND, con una resistencia de 330Ω, y buscar los pines 13 y 9 correspondientes a la columna 1, fila 1, hasta que el punto 1,1 se encendió. A partir de ahí, el resto es fácil.
Os recomiendo que una vez que lo hayáis localizado, vayáis conectando el resto de los pines poco a poco y vayáis probando las conexiones. En mi caso lo he representado en el esquema.
Placa de Arduino
8 Resistencia de 330
1 Matriz LED 8 X 8 1588AS
Protoboard, Cables para conexiones y un cable USB para conectar arduino al PC y que siver además de alimentación
Esquema
Montaje
Código
El primer código es un código de barrido que se usa para comprobar que teníamos bien conectados los puntos, contiene ya la base de nuestro código
El primer código es un código de barrido que se usa para comprobar que teníamos bien conectados los puntos, contiene ya la base de nuestro código
void setup(){
for (int j=2; j<19; j++)
pinMode(j, OUTPUT);
}
void loop(){
for (int j=2; j<10; j++){
digitalWrite(j, HIGH); //Levantamos la columna
for (int k= 10 ; k<18 ; k++){
digitalWrite(k, LOW); //Encendemos el punto
delay(250);
digitalWrite(k, HIGH); //Apagamos el punto
}
digitalWrite(j, LOW); //Bajamos la columna
}
}
¿ AL 19 ?. ¡No existen tantos pines!. Bueno, en realidad sí.
Ya vimos en su momento que los pines analógicos e A0 al A5 se podían usar como pines digitales normales. Y cuando es así podemos numerarlos como pines digitales del 14 al 19.
Se he aprovecha de esta curiosidad, para que sea más cómodo escribir el programa.
Para iluminar un punto concreto, en primer lugar poner en LOW todas las columnas y en HIGH todas las filas, lo que apaga todo.
Después levantar ha HIGH la columna que contiene el punto a iluminar. Fíjate que esto de por sí, no va a encender nada aun. Sera cuando pongamos una de las filas en LOW, cuando se cerrara el circuito y un punto se iluminara.
La curiosidad de esto, es que el diodo se ilumina cuando ponemos 0 en una fila, no un 1 como hasta ahora. A esto se le llama, lógica negativa, porque la acción se ejecuta con un valor bajo y no alto.
Entonces ¿ Cómo hacemos para mostrar un carácter, digamos la P? Pues tal y como vimos en la sesión previa. Dibujando cuadraditos en un papel cuadriculado.
Pero, ¿Entonces, tenemos que definir una matriz por cada letra que quiero representar?
La respuesta, querido amigo, es un rotundo SI. Y no solo para cada letra, mayúscula y minúscula, sino también para cada número y símbolo que quiera representar.
La respuesta, querido amigo, es un rotundo SI. Y no solo para cada letra, mayúscula y minúscula, sino también para cada número y símbolo que quiera representar.
De hecho este es el primer sistema que los ordenadores han usado desde el principio para dibujar los caracteres en pantalla.
Para escribir PROMETEC, tendremos que definir las letras correspondientes:
Vamos ahora, a ver como sacamos una de estas letras en el display. Lo primero es que vamos a usar la función GetBit de la sesión anterior para sacar la información a presentar en el display.
byte P[] = { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40 };
byte R[] = { 0x78, 0x44, 0x44, 0x78, 0x70, 0x58, 0x4C, 0x46 };
byte O[] = { 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C };
byte M[] = { 0x66, 0x7E, 0x5A, 0x42, 0x42, 0x42, 0x42, 0x42 };
byte E[] = { 0x7C, 0x40, 0x40, 0x78, 0x78, 0x40, 0x40, 0x7C };
byte T[] = { 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 };
byte C[] = { 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C };
byte N[] = { 0x42, 0x62, 0x72, 0x5A, 0x4E, 0x46, 0x42, 0x42 };
byte dot[]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06 };
byte sp[]= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
bool GetBit( byte N, int pos){ // pos = 7 6 5 4 3 2 1 0
int b = N >> pos ; // Shift bits
b = b & 1 ; // coger solo el ultimo bit
return b ;
}
void setup(){
Y ahora definimos un esqueleto que barra filas y columnas, sin preocuparnos de los números de pin:
Los print centrales han sido para comprobar que lee correctamente (que nunca se sabe). Vamos ahora a buscar el bit para cada fila y columna, y lo sacaremos en pantalla, para asegurarnos de que lee bien los bits:
Volvemos a comprobar, que presenta correctamente los valores de cada bit, con lo que ya hemos desempaquetado el valor de cada punto del display. Si entornáis los ojos casi se ve la P entre los 1s y 0s Ahora nos queda convertir los valores fila y columna a pines de Arduino. Recordad que las columnas van del pin2 al pin9 de Arduino, pero la dos corresponde a nuestra columna 7, según lo definimos en GetBit, Como este no es mi primer baile, vamos a ver despacito como hacemos esto. Queremos convertir valores de columnas que van del 7 al 0, en valores de pin que van del 2 al 9. ¿Qué formula aplicamos?. ¡VA! Pensad un poco. Basta con esto, Pin = 9 – col , y no hay más. Vamos a comprobarlo
Col 0 1 2 3 4 5 6 7
9 – 0 9 -1 9-2 9-3 9-4 9-5 9-6 9-7
pin 9 8 7 6 5 4 3 2
A que no era para tanto. Vamos ahora a ver como convertimos las filas del 0 al 7 en pines del 10 al 17….con este sí que os atrevéis, ¿No? Pin = fil + 10. Nos falta otra pequeña función antes de escribir el programa completo. Una que apague todos los puntos LED para borrar el display:
Las columnas son activas en HIGH, así que ponemos todas a LOW. Y las filas son activas en LOW, por lo que que todas a HIGH. Esto nos garantiza que todos los puntos se apaguen. Ya encenderemos luego los que nos interesen. El programa quedara más o menos así
Podéis comprobar que pinta una bonita P en el display. Prog_37_2
byte Selecciona( char c, byte fil)
{
byte Selecciona( char c, byte fil){
Y además, modificaremos nuestro anterior loop, para convertirlo en una función, a la que pasamos el carácter que queremos mostrar, y dentro de esta función llamaremos a Selecciona () para leer la información del array correspondiente.
Ya solo falta escribir el loop:
Que lo único que hace, es ir tomando una a una, las letras del String s y llamar a Setchar para que la represente. Pero con una complicación adicional. Ya que cuando multiplexas segmentos, o en este caso puntos, cualquier intento de utilizar un delay acabará en desastre porque la imagen en el display depende de la velocidad a la que refrescas los puntos, y el delay sencillamente lo impide.
for (int j=2; j<19; j++){
pinMode(j, OUTPUT);
}
Serial.begin(115200);
}
void loop(){
for (int fil = 0; fil <8 ; fil++){
byte F = P[fil] ;
for (int col =7; col >= 0 ; col--){
Serial.print(F, HEX);
Serial.print(", ");
}
Serial.println();
}
}
void loop(){
for (int fil = 0; fil <8 ; fil++){
byte F = P[fil] ;
for (int col =7; col >= 0 ; col--){
bool b = GetBit(F, col) ;
Serial.print(b);
Serial.print(",");
}
Serial.println();
}
}
Col 0 1 2 3 4 5 6 7
9 – 0 9 -1 9-2 9-3 9-4 9-5 9-6 9-7
pin 9 8 7 6 5 4 3 2
A que no era para tanto. Vamos ahora a ver como convertimos las filas del 0 al 7 en pines del 10 al 17….con este sí que os atrevéis, ¿No? Pin = fil + 10. Nos falta otra pequeña función antes de escribir el programa completo. Una que apague todos los puntos LED para borrar el display:
void Clear(){
for (int j=2; j<10; j++) // Valores de los pines de columna
digitalWrite(j, LOW); // Todos apagados
for (int k= 10 ; k<18 ; k++)
digitalWrite(k, HIGH); // Todas las filas cortadas
}
void loop(){
Clear();
for (int fil = 0; fil <8 ; fil++){
digitalWrite( fil + 10 , LOW) ; // Activamos la fila para el barrido
byte F = P[fil] ;
for (int col =7; col >= 0 ; col--){
bool b = GetBit(F, col) ;
if (b)
digitalWrite( 9 - col ,HIGH); //Levantamos la columna
else
digitalWrite( 9 - col ,LOW); // Si 0, apagamos
}
digitalWrite( fil + 10 , HIGH) ; // Apagamos fila antes de salir
}
}
byte Selecciona( char c, byte fil)
{
byte Selecciona( char c, byte fil){
if ( c == 'P'){
return(P[fil]) ;
}
if ( c == 'R'){
return( R[fil]) ;
}
if ( c == 'O'){
return( O[fil]);
}
if ( c == 'M'){
return( M[fil]);
}
if ( c == 'E'){
return( E[fil]);
}
if ( c == 'T'){
return( T[fil]);
}
if ( c == 'C'){
return( C[fil]);
}
if ( c == 'N'){
return( N[fil]);
}
if ( c == '.'){
return( dot[fil]);
}
if ( c == ' '){
return( sp[fil]);
}
}
Y además, modificaremos nuestro anterior loop, para convertirlo en una función, a la que pasamos el carácter que queremos mostrar, y dentro de esta función llamaremos a Selecciona () para leer la información del array correspondiente.
void SetChar(char p){
Clear();
for (int fil = 0; fil <8 ; fil++){
digitalWrite( fil + 10 , LOW) ; // Activamos la fila para el barrido
byte F = Selecciona( p, fil);
for (int col =7; col >= 0 ; col--){
digitalWrite(8-col, LOW); //Bajamos la columna
bool b = GetBit(F, col) ;
if (b){ //Levantamos la columna, con su pin
digitalWrite( 9 - col ,HIGH);
} else{
digitalWrite( 9 - col ,LOW); // Si 0, apagamos
}
}
digitalWrite( fil + 10 , HIGH) ; // Apagamos fila antes de salir
}
}
void loop(){
String s = "PROMETEC.NET " ;
int l = s.length(); // Calcula la longitus de s
for ( int n = 0; n< l; n++ ){
long t = millis();
char c = s[n];
while ( millis()< t+ 400)
SetChar(c);
}
}
Cuando necesitéis un retraso, como ahora, y no podáis poner un delay, utilizar un while como este suele ser seguro.
Fijaros que he añadido un par de espacios al final del string s. Como he definido los espacios como todo apagado. Esto nos da un retraso adicional, antes de que vuelva a empezar con la función.
Aqui os dejo un pequeño video con el resultado
Aquí dejo el código completo y terminado
byte P[] = { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40 };
byte R[] = { 0x78, 0x44, 0x44, 0x78, 0x70, 0x58, 0x4C, 0x46 };
byte O[] = { 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C };
byte M[] = { 0x66, 0x7E, 0x5A, 0x42, 0x42, 0x42, 0x42, 0x42 };
byte E[] = { 0x7C, 0x40, 0x40, 0x78, 0x78, 0x40, 0x40, 0x7C };
byte T[] = { 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 };
byte C[] = { 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C };
byte N[] = { 0x42, 0x62, 0x72, 0x5A, 0x4E, 0x46, 0x42, 0x42 };
byte dot[]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06 };
byte sp[]= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
void setup(){
for (int j=2; j<19; j++){
pinMode(j, OUTPUT);
}
Serial.begin(115200);
}
void loop(){
String s = "PROMETEC.NET " ;
int l = s.length(); // Calcula la longitus de s
for ( int n = 0; n< l; n++ ){
long t = millis();
char c = s[n];
while ( millis()< t+ 400)
SetChar(c);
}
}
bool GetBit( byte N, int pos){ // pos = 7 6 5 4 3 2 1 0
int b = N >> pos ; // Shift bits
b = b & 1 ; // coger solo el ultimo bit
return b ;
}
void Clear(){
for (int j=2; j<10; j++) // Valores de los pines de columna
digitalWrite(j, LOW); // Todos apagados
for (int k= 10 ; k<18 ; k++)
digitalWrite(k, HIGH); // Todas las filas cortadas
}
byte Selecciona( char c, byte fil){
if ( c == 'P'){
return(P[fil]) ;
}
if ( c == 'R'){
return( R[fil]) ;
}
if ( c == 'O'){
return( O[fil]);
}
if ( c == 'M'){
return( M[fil]);
}
if ( c == 'E'){
return( E[fil]);
}
if ( c == 'T'){
return( T[fil]);
}
if ( c == 'C'){
return( C[fil]);
}
if ( c == 'N'){
return( N[fil]);
}
if ( c == '.'){
return( dot[fil]);
}
if ( c == ' '){
return( sp[fil]);
}
}
void SetChar(char p){
Clear();
for (int fil = 0; fil <8 ; fil++){
digitalWrite( fil + 10 , LOW) ; // Activamos la fila para el barrido
byte F = Selecciona( p, fil);
for (int col =7; col >= 0 ; col--){
digitalWrite(8-col, LOW); //Bajamos la columna
bool b = GetBit(F, col) ;
if (b){ //Levantamos la columna, con su pin
digitalWrite( 9 - col ,HIGH);
} else{
digitalWrite( 9 - col ,LOW); // Si 0, apagamos
}
}
digitalWrite( fil + 10 , HIGH) ; // Apagamos fila antes de salir
}
}
No hay comentarios:
Publicar un comentario