POV & Attiny & GIMP

AttachmentSize
Image icon img1.jpg720.43 KB
Image icon img2.jpg12.5 KB
Image icon img4.jpg60.57 KB
Image icon img42.jpg83.88 KB
Image icon img5.jpg42.84 KB
Image icon img3.jpg39.24 KB
Image icon img41.jpg26.59 KB
Image icon prototipo.JPG695.93 KB
Image icon hykrion.jpg68.98 KB
Image icon Estado "de vacaciones"125.27 KB
Electrónica: 

Como ya sabréis, ayer fué el PiDay (3-14-15) y además era un día especial por ser la despedida de un amigo. Se me ocurrió que sería bonito hacer algo "especial" (léase freaky) pero tenía que ser algo ultra simple y ultra sencillo porque tenía que ser YA.

Hace ya tiempo que tenía un proyectito en mente y éste tenía que ver con POV (Presistence Of Vision) o light painting. En realidad, esto que os voy a mostrar ahora era uno de los pasos previos que ya tenía pensado, así que era perfecto. Además, casualidades de la vida justo el día anterior leí un artículo que hablaba de un formato de imagen que era justo lo que necesitaba: XPM

Básicamente, lo que se hace con POV es tener encendida una fuente de luz y moverla rápidamente para crear líneas, letras, imágenes... en mi caso he utilizado una plaquita con 8 leds de color rojo para poder graficar letras/gráficos de 8 píxeles de altura (el número 8 es importante porque es 8bits es 1byte y es el tamaño de puerto del Attiny84 que he utilizado para el proyecto) La cosa de utilizar un Attiny en lugar de Arduino es que necesitaba algo portable (en realidad veréis que el prototipo que utilizé está inacabado porque no tenía placas libres así que tuve que montarlo en una breadboard).

La forma más gráfica de ver cómo funciona el aparatito es dibujar en una libreta de cuadridos la frase/imágenes que queramos con la limitación de tener que ser de 8 cuadraditos de altura (máximo). Después iremos recorriendo la frase/imagen columna a columna. Por cada columna, si hemos rellenado el cuadradito es que tenemos que encender el led correspondiente. Ya está.

Esta tarea puede ser bastante tediosa y aquí es dónde entra en juego GIMP y el formato XPM.

Abriremos GIMP y crearemos una nueva imagen (normalmente de 640x400). Escribiremos lo que queramos y después lo escalaremos para que tenga una altura de 8píxeles

Como puede observarse nos quedan unas sombras (y nosotros solo sabemos de 0-1 o blanco-negro)

Así que tenemos que indizar la imagen para blanco y negro

y

Ya solo nos queda voltear la imagen (ahora se verá porqué en el código) y recortar el tamaño hasta justo lo que queremos mostrar

Ahora ya solo nos queda exportar la imagen al formato XPM

Si abrimos el fichero xpm con el notepad o similar veremos:

static char * C:\Users\jose_2\Pictures\pov\hykrion_xpm[] = {
"8 113 2 1",
"     c #FFFFFF",
".    c #000000",
"        ",
"        ",
"  ....  ",
"  ....  ",
"    .   ",
"    .   ",
"    .   ",
"    .   ",
"    .   ",
"    .   ",
"  ....  ",
"  ....  ",
"        ",
"        ",
"        ",
"        ",
"    .   ",
".  ..   ",
". ..    ",
" ..     ",
" ..     ",
"  ..    ",
"   ..   ",
"    .   ",
"        ",

 

Ahora adaptaremos este fichero a nuestro formato. Esto es, haremos los siguientes reemplazos:

  • ", --> ,
  • " --> 0b
  • Para ánodo común (mi caso)
    • . --> 1
    • ESPACIO --> 0

Como consejo diré que deberías dejar una última columna en blanco para apagar todos los leds.

Con estas trasformaciones ya podemos copiar el código:

0b11111111,
0b11000011,
0b11000011,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11000011,
0b11000011,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11110111,
0b01100111,
0b01001111,
0b10011111,
0b10011111,
0b11001111, ...

El código fuente del programa es extremadamente sencillo (el código está en C en lugar de C++):

/*
 * GccApplication1.c
 *
 * Created: 12/03/2015 21:06:24
 *  Author: jose_2
 */ 

#define F_CPU 1000000UL

#include <avr/io.h>
#include <util/delay.h>

#define kLED_PORT PORTA
#define kLED_DDR DDRA
#define kDELAY 2 // en ms

// NOTE Es importante notar que el tamaño de cada fila es 1byte porque así podemos utilizar sizeof
//      para calcular el número de filas. Además volcamos todo la fila en el PORTA. Aquí, ánodo común
uint8_t image1[] = {
0b11111111,
0b11111111,
0b11000011,
0b11000011,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11000011,
0b11000011,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11110111,
0b01100111,
0b01001111,
0b10011111,
0b10011111,
0b11001111,
0b11100111,
0b11110111,
0b11111111,
0b11111111,
0b11111111,
0b11000001,
0b11000001,
0b11101111,
0b11101111,
0b11000111,
0b11010111,
0b11110111,
0b11111111,
0b11111111,
0b11111111,
0b11000111,
0b11000111,
0b11110111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11000101,
0b11000101,
0b11111111,
0b11111111,
0b11101111,
0b11000111,
0b11010111,
0b11010111,
0b11010111,
0b11010111,
0b11010111,
0b11010111,
0b11000111,
0b11101111,
0b11111111,
0b11111111,
0b11000111,
0b11000111,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11000111,
0b11000111,
0b11111111,
0b11111111,
0b11111111,
0b10111111,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11101111,
0b11000111,
0b11010111,
0b10110111,
0b10111011,
0b11111111,
0b11111111,
0b11111111,
0b11111111,
0b11101111,
0b11000111,
0b11010111,
0b11010111,
0b11010111,
0b11010111,
0b11010111,
0b11010111,
0b11000111,
0b11101111,
0b11111111,
0b11111111,
0b11000111,
0b11000111,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11000111,
0b11000111,
0b11110111,
0b11110111,
0b11110111,
0b11110111,
0b11000111,
0b11000111,
0b11111111
};

void pov(uint8_t image[], uint8_t numRows)
{
  uint8_t i = 0;
  
  for(i = 0; i < numRows; i++)
  {
    kLED_PORT = image[i];
    _delay_ms(2);
  }
  _delay_ms(10);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

int main(void)
{
  // Puerto de los LEDs como salida
  kLED_DDR = 0xFF;
  
  while(1)
  {
    pov(image1, sizeof(image1));
  }
  
  return 0;
}

Si ahora realizamos las conexiones pertinentes:

Ya podemos ver el resultado de nuestro trabajo:

Nota: No pongo la traducción a Arduino porque es directa... tampoco pongo un esquema porque simplemente conecto Vcc, GND (el condensador que véis en la foto es para desacoplar Vcc y GND... nada importante aquí pero es una costumbre) y ocho pines de un puerto. Para grabar el Attiny he utilizado el usbtinny aunque por supuesto puedes utilizar un Arduino para ello. También he utilizado el AtmelStudio pero por supuesto también, otra vez, puedes utilizar las herramientas de Arduino (aunque no su IDE) para compilar este código C (necesitarás #define __AVR_ATtiny84__)

Social_buttons: 

Comments

0b11111111, 0b10001111, 0b11100111, 0b10000010, 0b01001001, 0b01000011, 0b11000011, 0b01000011, 0b01001001, 0b10000010, 0b11100111, 0b10001111, 0b11111111, 0b11000111, 0b11011011, 0b10000011, 0b11111111, 0b11100111, 0b11011011, 0b11011011, 0b11100111, 0b11111111, 0b11000111, 0b11011011, 0b10000011, 0b11111111, 0b11111111, 0b11100001, 0b01000111, 0b10000010, 0b11001001, 0b11000011, 0b11000011, 0b11001001, 0b10000010, 0b01000111, 0b11100001, 0b11111111