viernes, 17 de enero de 2020

Mostrar imágenes

Para visualizar las imagenes que queramos vamos a crear nuestros propios array booleanos de 5x5 y, mediante una nueva función, transferirlos al array "matrizLed[5][5]", que es el que se muestra en los LEDs al utilizar "multiplexaMatrizLed()". Simplemente hay que ir moviendo los elementos de nuestro array a la misma posición en matrizLed; utilizando dos for el código es el siguiente:

void muestraImagen(boolean tuImagen[5][5]){
  for(byte y=0; y<5; y++){
    for(byte x=0; x<5; x++){
      matrizLed[y][x]=tuImagen[y][x];
    }
  }
}

Esta función la añadimos al archivo funcionesMicrobit.ino que creamos en la entrada anterior. El siguiente programa hace parpadear dos cuadrados a intervalos de medio segundo:

/* 
 *  parpadeoImagenesCuadrados.ino
 *  En la matriz de LEDs irán parpadeando dos 
 *  cuadrados, uno mas grande y otro más pequeño,
 *  a intervalos de medio segundo.
 *  funcionesMicrobit.ino debe estar en otra pestaña
 */

/*
 * Creamos dos array para representar los cuadrados,
 * uno grande y otro pequeño.
 */
boolean imagen1[5][5] = {{1,1,1,1,1}, 
                         {1,0,0,0,1},
                         {1,0,0,0,1},
                         {1,0,0,0,1},
                         {1,1,1,1,1}};

boolean imagen2[5][5] = {{0,0,0,0,0},
                         {0,1,1,1,0},
                         {0,1,0,1,0},
                         {0,1,1,1,0},
                         {0,0,0,0,0}};

void setup() {
  pinMatrizLedSalidas();
}

void loop() {
  muestraImagen(imagen1);
  delay_(500);            
  muestraImagen(imagen2);
  delay_(500);
}

/*
 * La función que se está ejecutando mientras
 * duran los delay_
 */
void loop_(){
  multiplexaMatrizLed();   
}

En lugar de utilizar un array booleano de 5x5, podríamos usar un array de tipo byte con sólo 5 elementos, en el que cada bit de esos números binarios representaría el estado de un LED, de esta forma ahorraríamos memoria. Por ejemplo, los array de los dos cuadrados anteriores quedarían de la siguiente manera:
/*
 * Creamos dos array para representar los cuadrados,
 * uno grande y otro pequeño. Cada bit representa un LED.
 * Se utilizan números binarios (byte) de 8 bit; en 
 * nuestro caso es suficiente con 5 bit, los tres bit
 * mas a la izquierda serían ceros.
 */
byte imagen1[5] = {B11111, 
                   B10001,
                   B10001,
                   B10001,
                   B11111};

byte imagen2[5] = {B00000, 
                   B01110,
                   B01010,
                   B01110,
                   B00000};
 
Lógicamente, tenemos que hacer una nueva función, un poco más complicada, para visualizar las imagenes; ya que hay que ir realizando una operación lógica and (&) entre los distintos bytes del array con el número B10000, desplazando el 1 hacia la derecha (>>) tantas veces como indique el número de la columna en la que nos encontremos:

void muestraImagenBmp(byte tuImagenBmp [5]){
  for(byte y=0; y<5; y++){
    for(byte x=0; x<5; x++){
      matrizLed[y][x]=tuImagenBmp[y] & (B10000 >> x);
    }
  }
}

También incluiremos una función para poner a cero todos los elementos del array "matrizled" y así apagar todos los LEDs:

void borraImagen(){
  for(byte y=0; y<5; y++){
    for(byte x=0; x<5; x++){
      matrizLed[y][x]=0;
    }
  }

En este ejemplo los LEDs se van encendiendo progresivamente en diagonal:

/* 
 *  imagenesBmpBarridoLed.ino
 *  La matriz de LEDs se irá encendiendo progresivamente
 *  en diagonal.
*/

/*
 * Todos los array con las imágenes a visualizar
 */
byte imagen1[5]={B10000,
                 B00000,
                 B00000,
                 B00000,
                 B00000};
byte imagen2[5]={B11000,
                 B10000,
                 B00000,
                 B00000,
                 B00000};
byte imagen3[5]={B11100,
                 B11000,
                 B10000,
                 B00000,
                 B00000};
byte imagen4[5]={B11110,
                 B11100,
                 B11000,
                 B10000,
                 B00000};
byte imagen5[5]={B11111,
                 B11110,
                 B11100,
                 B11000,
                 B10000};
byte imagen6[5]={B11111,
                 B11111,
                 B11110,
                 B11100,
                 B11000};
byte imagen7[5]={B11111,
                 B11111,
                 B11111,
                 B11110,
                 B11100};
byte imagen8[5]={B11111,
                 B11111,
                 B11111,
                 B11111,
                 B11110};
byte imagen9[5]={B11111,
                 B11111,
                 B11111,
                 B11111,
                 B11111};

void setup() {
 pinMatrizLedSalidas();
}

void loop() {
  muestraImagenBmp(imagen1);
  delay_(100);
  muestraImagenBmp(imagen2);
  delay_(100);
  muestraImagenBmp(imagen3);
  delay_(100);
  muestraImagenBmp(imagen4);
  delay_(100);
  muestraImagenBmp(imagen5);
  delay_(100);
  muestraImagenBmp(imagen6);
  delay_(100);
  muestraImagenBmp(imagen7);
  delay_(100);
  muestraImagenBmp(imagen8);
  delay_(100);
  muestraImagenBmp(imagen9);
  delay_(1000);
  borraImagen();
  delay_(1000);
}

/*
 * La función que se está ejecutando mientras
 * duran los delay_
 */
void loop_(){
  multiplexaMatrizLed();
}

También podemos visualizar letras y números. En el siguiente programa se muestran las letras A, B y el número 2:

/* 
 *  imagenesBmpAB2.ino
 *  En la matriz de LEDs irán apareciendo las letras
 *  A y B y el número 2, a intervalos de un segundo.
*/

/*
 * Los array con las imágenes de A, B y 2.
 */
byte imagenA[5]={B01100,
                 B10010,
                 B11110,
                 B10010,
                 B10010};
byte imagenB[5]={B11100,
                 B10010,
                 B11100,
                 B10010,
                 B11100};
byte imagen2[5]={B11100,
                 B00010,
                 B01100,
                 B10000,
                 B11110};

void setup() {
 pinMatrizLedSalidas();
}

void loop() {
  muestraImagenBmp(imagenA);
  delay_(1000);
  muestraImagenBmp(imagenB);
  delay_(1000);
  muestraImagenBmp(imagen2);
  delay_(1000);
}

/*
 * La función que se está ejecutando mientras
 * duran los delay_
 */
void loop_(){
  multiplexaMatrizLed();
}









viernes, 10 de enero de 2020

funcionesMicrobit.ino

En la entrada anterior hemos usado unas cuantas funciones a las que tendremos que recurrir con mucha frecuencia. Vamos a crear, por tanto, un archivo con todas ellas y lo incluiremos, cuando sea necesario, en una nueva pestaña del IDE Arduino:




Ahora sólo tenemos que copiar y pegar el siguiente código:

/* 
 * funcionesMicrobit.ino
 * Conjunto de funciones que podemos usar en nuestros programas.
 */


/*
 * Los pines de las tres filas y 9 columnas de la matriz
 * interna de LEDs
 */
byte pinFilas[3] = {26, 27, 28};
byte pinColumnas[9] = {3, 4, 10, 23, 24, 25, 9, 7, 6};

/*
 * boolean matrizLed[5][5];
 * Vamos a crear una imagen virtual de la matriz de LEDs,
 * para ello utilizamos un array de tipo booleano de dos
 * dimensiones (fila-Columna). 
 * Un 1 es encendido y un 0 apagado.
 */
boolean matrizLed[5][5]={{0,0,0,0,0},
                         {0,0,0,0,0},
                         {0,0,0,0,0},
                         {0,0,0,0,0},
                         {0,0,0,0,0}}; //matrizLed[fila][columna]

/*
 * coorY y coorX son dos array de 3x9 que representan la
 * fila (Y) y columna (X) de cada uno de los LED (matriz de 5x5)
 * en relación con su posición en la matriz interna de 3x9.
 */
byte coorY [3][9] = {{0,0,0,3,3,3,3,3,2},
                     {2,2,2,0,0,4,4,0,0},
                     {4,4,4,1,1,1,1,1,2}};                 
byte coorX [3][9] = {{0,2,4,4,3,2,1,0,1},
                     {4,0,2,1,3,3,1,0,0},
                     {2,4,0,0,1,2,3,4,3}};

byte fila=0;       //la fila actual a encender en el multiplexado.

long millisInicialesLed=0;
long millisInicialesDelay_=0;

/*
 * pinMatrizLedSalidas()
 * Programa como salidas los 3 pines de las filas internas
 * y los 9 pines de las columnas
 */
void pinMatrizLedSalidas(){
  for (byte i=0; i<9; i++){
    pinMode(pinColumnas[i], OUTPUT);
  }
  for (byte i=0; i<3; i++){
    pinMode(pinFilas[i], OUTPUT);
  }
}

/*
 * multiplexaMatrizLed()
 * Cada 6 milisegundos llama a la función
 * multiplexadoFilasLed.
 */
void multiplexaMatrizLed(){
  if (millis() - millisInicialesLed > 6) {
    millisInicialesLed = millis();
    multiplexaFilasLed();
  }
}

/*
 * apagaMatrizLed()
 * Desactiva todos los pines tanto de las tres filas
 * como de las nueve columnas de la matriz de LEDS.
 */
void apagaMatrizLed(){
  for (byte i=0; i<3; i++){
    digitalWrite(pinFilas[i], LOW);
  }
  for (byte i=0; i<9; i++){
    digitalWrite(pinColumnas[i], HIGH);
  }
}

/*
 * multiplexaFilasLed()
 * Primero apaga toda los LEDs y después transfiere los 0 y 1
 * de la matriz virtual a los LEDs correspondiente.
 * Cada vez que se ejecuta (cada 6 mseg)se actualiza una sola
 * de las tres filas internas.
 * Recordamos los pines (fila columna) de los LEDs:
 *  (26-3)  27-23  26-4   27-24 (26-10)
 *   28-23 (28-24) 28-25 (28-9)  28-7
 *   27-4   26-6  (27-10) 28-6   27-3
 *   26-7  (26-9)  26-25 (26-24) 26-23
 *  (28-10) 27-9   28-3   27-25 (28-4)
 */
void multiplexaFilasLed(){
  apagaMatrizLed();
  digitalWrite(pinFilas[fila],HIGH);
  for (byte i=0; i<9; i++){
    digitalWrite(pinColumnas[i], !matrizLed[coorY[fila][i]][coorX[fila][i]]);
  }
  fila++;
  if(fila==3) fila=0;
}

/* 
 * delay_
 * Creamos una función que realiza la temporización utilizando
 * la instrucción millis() y genera un nuevo buble que se sigue
 * ejecutando durante el tiempo que hayamos fijado.
 * La variable millisIniciales está declarada como local dentro 
 * de la función.
 * Para hacer ese buble hemos utilizado la instrucción:
 *     while(condición){  instrucciones }
 * mientras que se cumpla la condición se ejecutan las instruciones
 * que hay entre las llaves.
 * En lugar de incluir entre las llaves todas las instrucciones
 * que necesitemos las colocaremos en una nueva función loop_ 
 * que hay que incluir en nuestro programa.
 */
void delay_(long tiempo){
  long millisInicialesDelay_ = millis();
  while(millis() - millisInicialesDelay_ < tiempo){
    loop_();
  }
}

En la primera pestaña escribiremos nuestros programas y podremos utilizar las funciones que hemos añadido. Al guardarlo aparecererán dos archivos .ino, el del programa y el de las funciones. Una vez que tenemos creado funcionesMicrobit.ino lo podemos incluir en otros programas utilizando la opción "Añadir fichero..." del menú "Programa".

miércoles, 1 de enero de 2020

Multiplexado LEDs

Vamos a abordar la realización de unas funciones que nos permitan realizar el multiplexado de la matriz de LEDs y visualizar en ella la imagen que deseemos. La idea es crear una imagen virtual de la matriz, utilizando un array de dos dimensiones:

boolean matrizLed[5][5]={{1,0,0,0,1},
                         {0,1,0,1,0},
                         {0,0,1,0,0},
                         {0,1,0,1,0},
                         {1,0,0,0,1}}; //matrizLed[fila][columna]

Con los ceros y los unos indicamos el estado de los LEDs (0 apagado, 1 encendido). Cada 6 milisegundos apagaremos, inicialmente, todos los LEDS, activaremos una de las tres filas internas y llevaremos a cabo el encendido/apagado de los LEDS correspondientes (teniendo en cuenta los datos de esta imagen virtual). En definitiva, los LEDs de la primera fila interna se encenderan durante 6 milisegundos, después se apagarán y serán los de la segunda fila los que se enciendan ese mismo tiempo y, finalmente, después de apagarse todos se encenderan los de la tercera fila otro 6 milisegundos y así sucesivamente. El programa es el siguiente:
/*
 * multiplexadoLed.ino
 * Multiplexado de la matriz de LEDs y creación de una
 * imagen virtual de la misma, que servirá para visualizar
 * con facilidad cualquier figura.
 */


byte pinFilas[3] = {26, 27, 28};
byte pinColumnas[9] = {3, 4, 10, 23, 24, 25, 9, 7, 6};

/*
 * boolean matrizLed[5][5];
 * Vamos a crear una imagen virtual de la matriz de LEDs,
 * para ello utilizamos un array de tipo booleano de dos
 * dimensiones (fila-Columna). 
 * Un 1 es encendido y un 0 apagado. Hemos dibujado una X
 */
boolean matrizLed[5][5]={{1,0,0,0,1},
                         {0,1,0,1,0},
                         {0,0,1,0,0},
                         {0,1,0,1,0},
                         {1,0,0,0,1}}; //matrizLed[fila][columna]

byte fila=0;       //la fila actual a encender en el multiplexado.

long millisInicialesLed=0;

void setup(){
  pinMatrizLedSalidas();
}

void loop(){
  multiplexaMatrizLed();
}

/************************************************* 
 *  Ahora vienen las funciones que hemos creado.
 *************************************************/

/*
 * pinMatrizLedSalidas()
 * Programa como salidas los 3 pines de las filas internas
 * y los 9 pines de las columnas
 */
void pinMatrizLedSalidas(){
  for (byte i=0; i<9; i++){
    pinMode(pinColumnas[i], OUTPUT);
  }
  for (byte i=0; i<3; i++){
    pinMode(pinFilas[i], OUTPUT);
  }
}

/*
 * multiplexaMatrizLed()
 * Cada 6 milisegundos llama a la función
 * multiplexadoFilasLed.
 */
void multiplexaMatrizLed(){
  if (millis() - millisInicialesLed > 6) {
    millisInicialesLed = millis();
    multiplexaFilasLed();
  }
}

/*
 * apagaMatrizLed()
 * Desactiva todos los pines tanto de las tres filas
 * como de las nueve columnas de la matriz de LEDS.
 */
void apagaMatrizLed(){
  for (byte i=0; i<3; i++){
    digitalWrite(pinFilas[i], LOW);
  }
  for (byte i=0; i<9; i++){
    digitalWrite(pinColumnas[i], HIGH);
  }
}

/*
 * multiplexaFilasLed()
 * Primero apaga toda los LEDs y después transfiere los 0 y 1
 * de la matriz virtual a los LEDs correspondiente.
 * Cada vez que se ejecuta (cada 6 mseg)se actualiza una sola
 * de las tres filas internas.
 * El código se puede simplificar utilizando "for" como veremos
 * posteriormente.
 * Recordamos los pines (fila columna) de los LEDs:
 *  (26-3)  27-23  26-4   27-24 (26-10)
 *   28-23 (28-24) 28-25 (28-9)  28-7
 *   27-4   26-6  (27-10) 28-6   27-3
 *   26-7  (26-9)  26-25 (26-24) 26-23
 *  (28-10) 27-9   28-3   27-25 (28-4)
 */
void multiplexaFilasLed(){
  apagaMatrizLed();
  if(fila==0){
    digitalWrite(26,HIGH);             //Activamos la fila 0.
    digitalWrite(3,!matrizLed[0][0]);  //Vamos transfiriendo
    digitalWrite(4,!matrizLed[0][2]);  //la imagen a los LEDs  
    digitalWrite(10,!matrizLed[0][4]);
    digitalWrite(23,!matrizLed[3][4]);
    digitalWrite(24,!matrizLed[3][3]);
    digitalWrite(25,!matrizLed[3][2]);
    digitalWrite(9,!matrizLed[3][1]);
    digitalWrite(7,!matrizLed[3][0]);
    digitalWrite(6,!matrizLed[2][1]);
  }
  else if(fila==1){
    digitalWrite(27,HIGH);             //Activamos la fila 1.
    digitalWrite(3,!matrizLed[2][4]);  //Vamos transfiriendo
    digitalWrite(4,!matrizLed[2][0]);  //la imagen a los LEDs
    digitalWrite(10,!matrizLed[2][2]);
    digitalWrite(23,!matrizLed[0][1]);
    digitalWrite(24,!matrizLed[0][3]);
    digitalWrite(25,!matrizLed[4][3]);
    digitalWrite(9,!matrizLed[4][1]);
    digitalWrite(7,1);
    digitalWrite(6,1);
  }
  else if(fila==2){
    digitalWrite(28,HIGH);             //Activamos la fila 2.
    digitalWrite(3,!matrizLed[4][2]);  //Vamos transfiriendo
    digitalWrite(4,!matrizLed[4][4]);  //la imagen a los LEDs
    digitalWrite(10,!matrizLed[4][0]);
    digitalWrite(23,!matrizLed[1][0]);
    digitalWrite(24,!matrizLed[1][1]);
    digitalWrite(25,!matrizLed[1][2]);
    digitalWrite(9,!matrizLed[1][3]);
    digitalWrite(7,!matrizLed[1][4]);
    digitalWrite(6,!matrizLed[2][3]);
  }
  fila++;
  if(fila==3) fila=0;
}

Para simplificar esta última función usando la instrucción "for" tenemos que declarar, al inicio del programa, dos nuevos array de 3x9. En ellos relacionamos la fila (Y) y la columna (X) de cada LED (5x5) con su posición en la matriz interna:
/*
 * coorY y coorX son dos array de 3x9 que representan la
 * fila (Y) y columna (X) de cada uno de los LED (matriz de 5x5)
 * en relación con su posición en la matriz interna de 3x9.
 */
byte coorY [3][9] = {{0,0,0,3,3,3,3,3,2},
                     {2,2,2,0,0,4,4,0,0},
                     {4,4,4,1,1,1,1,1,2}};                 
byte coorX [3][9] = {{0,2,4,4,3,2,1,0,1},
                     {4,0,2,1,3,3,1,0,0},
                     {2,4,0,0,1,2,3,4,3}};

Utilizando estos datos ya podemos incluir un "for" que simplifica considerablemente el código:
void multiplexaFilasLed(){
  apagaMatrizLed();
  digitalWrite(pinFilas[fila],HIGH);
  for (byte i=0; i<9; i++){
    digitalWrite(pinColumnas[i], !matrizLed[coorY[fila][i]][coorX[fila][i]]);
  }
  fila++;
  if(fila==3) fila=0;
}


En este programa se visualiza una X en la matriz de LEDs. Lógicamente, cambiando los ceros y unos del array matrizLed podemos ver la figura o las letras y números que deseemos.