jueves, 13 de febrero de 2020

mostrar caracteres ASCII

En la entrada anterior ya hicimos un pequeño ejemplo de como se podían visualizar letras y números. Ahora vamos a implementar un array (font) con las imágenes de la mayoría de caracteres ASCII y una función específica (muestraCaracter) para verlos en la matriz de LEDs. Ambos hay que incluirlos en el archivo funcionesMicrobit.ino, el array al principio, donde se declaran las variables, y muestraCaracter con el resto de funciones.

/* font[59][5]
 *  Array con las imagenes bmp de gran parte de los caracteres ASCII
 *  Se inician con el espacio en blanco (código ASCII 32) y finalizan
 *  con la letra Z (código ASCII 91). No hemos incluido
 *  las letras minúsculas.
 */
byte font[59][5] = {{B00000,B00000,B00000,B00000,B00000},  //espacio
                    {B00100,B00100,B00100,B00000,B00100},  //!
                    {B01100,B01100,B00000,B00000,B00000},  //"
                    {B01010,B11111,B01010,B11111,B01010},  //#
                    {B01110,B10100,B01100,B00110,B11100},  //$
                    {B11001,B11010,B00100,B01011,B10011},  //%
                    {B01100,B10010,B01101,B10010,B01101},  //&
                    {B00100,B00100,B00000,B00000,B00000},  //'
                    {B00100,B01000,B01000,B01000,B00100},  //(
                    {B01000,B00100,B00100,B00100,B01000},  //)
                    {B00000,B01010,B00100,B01010,B00000},  //*
                    {B00000,B00100,B01110,B00100,B00000},  //+
                    {B00000,B00000,B00000,B01000,B01000},  //,
                    {B00000,B00000,B01110,B00000,B00000},  //-
                    {B00000,B00000,B00000,B00100,B00000},  //.
                    {B00001,B00010,B00100,B01000,B10000},  ///
                    {B01100,B10010,B10010,B10010,B01100},  //0
                    {B00100,B01100,B00100,B00100,B01110},  //1
                    {B11100,B00010,B01100,B10000,B11110},  //2
                    {B11100,B00010,B11100,B00010,B11100},  //3
                    {B10010,B10010,B01110,B00010,B00010},  //4
                    {B11110,B10000,B11100,B00010,B11100},  //5
                    {B01110,B10000,B11100,B10010,B01100},  //6
                    {B11110,B00010,B00100,B00100,B00100},  //7
                    {B01100,B10010,B01100,B10010,B01100},  //8
                    {B01100,B10010,B01110,B00010,B01100},  //9
                    {B00000,B01000,B00000,B01000,B00000},  //:
                    {B00000,B01000,B00000,B01000,B01000},  //;
                    {B00010,B00100,B01000,B00100,B00010},  //<
                    {B00000,B01110,B00000,B01110,B00000},  //=
                    {B01000,B00100,B00010,B00100,B01000},  //>
                    {B11100,B00010,B01100,B00000,B01000},  //?
                    {B01110,B10001,B10101,B10110,B01100},  //@
                    {B01100,B10010,B11110,B10010,B10010},  //A
                    {B11100,B10010,B11100,B10010,B11100},  //B
                    {B01110,B10000,B10000,B10000,B01110},  //C
                    {B11100,B10010,B10010,B10010,B11100},  //D
                    {B01110,B10000,B11110,B10000,B01110},  //E
                    {B01110,B10000,B11110,B10000,B10000},  //F
                    {B01110,B10000,B10110,B10010,B01110},  //G
                    {B10010,B10010,B11110,B10010,B10010},  //H
                    {B01110,B00100,B00100,B00100,B01110},  //I
                    {B01110,B00010,B00010,B00010,B11100},  //J
                    {B10010,B10010,B11100,B10010,B10010},  //K
                    {B10000,B10000,B10000,B10000,B11110},  //L
                    {B10001,B11011,B10101,B10001,B10001},  //M
                    {B10001,B11001,B10101,B10011,B10001},  //N
                    {B01100,B10010,B10010,B10010,B01100},  //O
                    {B11100,B10010,B11100,B10000,B10000},  //P
                    {B01100,B10010,B10010,B01100,B00100},  //Q
                    {B11100,B10010,B11100,B10010,B10010},  //R
                    {B01110,B10000,B01100,B00010,B11100},  //S
                    {B11111,B00100,B00100,B00100,B00100},  //T
                    {B10010,B10010,B10010,B10010,B01100},  //U
                    {B10001,B10001,B01010,B01010,B00100},  //V
                    {B10001,B10001,B10101,B11011,B10001},  //W
                    {B10001,B01010,B00100,B01010,B10001},  //X
                    {B10001,B10001,B01110,B01110,B00100},  //Y
                    {B11110,B00100,B01000,B10000,B11110}}; //Z

La función es bastante sencilla, simplemente utilizamos muestraImagenesBmp y le restamos al código ASCII el número 32, así empezamos en el primer elemento de nuestro array (font).

void muestraCaracter(byte ascii){
  muestraImagenBmp(font[ascii-32]);
}

El programa adjunto va mostrando todos los caracteres a intervalos de un segundo.

/* muestraCaraceresAscii.ino
 * Visualizamos en la matriz de LEDs los
 * primeros 59 caracteres ASCII imprimibles.
 */

void setup() {
 pinMatrizLedSalidas();
}

/*
 * El número 32 corresponde al primer
 * caracter imprimible. El 91 a la
 * letra Z, que es la última de nuestro
 * array font.
 */
void loop(){
  for(byte i=32; i<91; i++){
    muestraCaracter(i);
    delay_(1000);
  }
}

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

El parámetro que hay que incluir en la función muestraCaracter(parámetro) puede ser el código ASCII numerico o el caracter encerrado entre comilla simple (por ejemplo: muestraCaracter('F')).



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".