chemical pov

MiniPOV4 and previous versions

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

chemical pov

Post by mtbf0 »

when i started building arduino brain machines i had a bunch of minipov boards left lying around, so i built one with uv leds.
safety director wrote:WARNING - do not look directly at uv leds. they will mess you up.
works pretty well. has it's own font built in and room for about 950 characters of message. as presented here, there is an output bug at the end of the second line, but i reckon i'll work on that in the morning.

meanwhile, i can wave it around and wipe poetry onto a piece of butcher paper painted with fluorescent paint.

here's some not very good video of the chemical pov running the above code. the light does persist a little longer than it appears to in the video, but i think it will work better when i replace the current limiting resistors.

thanks to omar khayyam and edward fitzgerald for the poem.

Code: Select all

#include "avr/io.h"             // i/o definitions
#include "avr/interrupt.h"      // definitions for interrupts
#include "avr/pgmspace.h"       // definitions for data in program memory
#include "avr/sleep.h"          // definitions for idling mcu

#define GLYFWIDTH 5

//
//  data in program memory
//
//  foo		- avrobjdump trashes the first symbol after the interrupt vectors,
//		  so we'll just feed it this.
//  text	- display text is a single string with lines delimited with nulls
//  povGlyf	- character bitmaps.  each character is 5 bytes, one per column of
//		  of a 5x8 cell.  low order bit is the top.

int foo PROGMEM = 666;

char text[] PROGMEM = "The Moving Finger writes; and, having writ,\0"
                      "Moves on; nor all your Piety nor Wit\0"
	              "Shall lure it back to cancel half a Line,\0"
	              "Nor all your Tears wash out a Word of it.";

uint8_t povGlyf[] PROGMEM = {
 /*   */ 0x00,0x00,0x00,0x00,0x00, /* ! */ 0x00,0x00,0x5f,0x00,0x00, 
 /* " */ 0x00,0x07,0x00,0x07,0x00, /* # */ 0x14,0x7f,0x14,0x7f,0x14, 
 /* $ */ 0x24,0x2a,0x7f,0x2a,0x12, /* % */ 0x23,0x13,0x08,0x64,0x62, 
 /* & */ 0x36,0x49,0x55,0x22,0x50, /* ' */ 0x00,0x05,0x03,0x00,0x00, 
 /* ( */ 0x00,0x1c,0x22,0x41,0x00, /* ) */ 0x00,0x41,0x22,0x1c,0x00, 
 /* * */ 0x08,0x2a,0x1c,0x2a,0x08, /* + */ 0x08,0x08,0x3e,0x08,0x08, 
 /* , */ 0x00,0x50,0x30,0x00,0x00, /* - */ 0x08,0x08,0x08,0x08,0x08, 
 /* . */ 0x00,0x60,0x60,0x00,0x00, /* / */ 0x20,0x10,0x08,0x04,0x02, 
 /* 0 */ 0x3e,0x51,0x49,0x45,0x3e, /* 1 */ 0x00,0x42,0x7f,0x40,0x00, 
 /* 2 */ 0x42,0x61,0x51,0x49,0x46, /* 3 */ 0x21,0x41,0x45,0x4b,0x31, 
 /* 4 */ 0x18,0x14,0x12,0x7f,0x10, /* 5 */ 0x27,0x45,0x45,0x45,0x39, 
 /* 6 */ 0x3c,0x4a,0x49,0x49,0x30, /* 7 */ 0x01,0x71,0x09,0x05,0x03, 
 /* 8 */ 0x36,0x49,0x49,0x49,0x36, /* 9 */ 0x06,0x49,0x49,0x29,0x1e, 
 /* : */ 0x00,0x36,0x36,0x00,0x00, /* ; */ 0x00,0x56,0x36,0x00,0x00, 
 /* < */ 0x00,0x08,0x14,0x22,0x41, /* = */ 0x14,0x14,0x14,0x14,0x14, 
 /* > */ 0x41,0x22,0x14,0x08,0x00, /* ? */ 0x02,0x01,0x51,0x09,0x06, 
 /* @ */ 0x32,0x49,0x79,0x41,0x3e, /* A */ 0x7e,0x11,0x11,0x11,0x7e, 
 /* B */ 0x7f,0x49,0x49,0x49,0x36, /* C */ 0x3e,0x41,0x41,0x41,0x22, 
 /* D */ 0x7f,0x41,0x41,0x22,0x1c, /* E */ 0x7f,0x49,0x49,0x49,0x41, 
 /* F */ 0x7f,0x09,0x09,0x01,0x01, /* G */ 0x3e,0x41,0x41,0x51,0x32, 
 /* H */ 0x7f,0x08,0x08,0x08,0x7f, /* I */ 0x00,0x41,0x7f,0x41,0x00, 
 /* J */ 0x20,0x40,0x41,0x3f,0x01, /* K */ 0x7f,0x08,0x14,0x22,0x41, 
 /* L */ 0x7f,0x40,0x40,0x40,0x40, /* M */ 0x7f,0x02,0x04,0x02,0x7f, 
 /* N */ 0x7f,0x04,0x08,0x10,0x7f, /* O */ 0x3e,0x41,0x41,0x41,0x3e, 
 /* P */ 0x7f,0x09,0x09,0x09,0x06, /* Q */ 0x3e,0x41,0x51,0x21,0x5e, 
 /* R */ 0x7f,0x09,0x19,0x29,0x46, /* S */ 0x46,0x49,0x49,0x49,0x31, 
 /* T */ 0x01,0x01,0x7f,0x01,0x01, /* U */ 0x3f,0x40,0x40,0x40,0x3f, 
 /* V */ 0x1f,0x20,0x40,0x20,0x1f, /* W */ 0x7f,0x20,0x18,0x20,0x7f, 
 /* X */ 0x63,0x14,0x08,0x14,0x63, /* Y */ 0x03,0x04,0x78,0x04,0x03, 
 /* Z */ 0x61,0x51,0x49,0x45,0x43, /* [ */ 0x00,0x00,0x7f,0x41,0x41, 
 /* \ */ 0x02,0x04,0x08,0x10,0x20, /* ] */ 0x41,0x41,0x7f,0x00,0x00, 
 /* ^ */ 0x04,0x02,0x01,0x02,0x04, /* _ */ 0x40,0x40,0x40,0x40,0x40, 
 /* ` */ 0x00,0x01,0x02,0x04,0x00, /* a */ 0x20,0x54,0x54,0x54,0x78, 
 /* b */ 0x7f,0x48,0x44,0x44,0x38, /* c */ 0x38,0x44,0x44,0x44,0x20, 
 /* d */ 0x38,0x44,0x44,0x48,0x7f, /* e */ 0x38,0x54,0x54,0x54,0x18, 
 /* f */ 0x08,0x7e,0x09,0x01,0x02, /* g */ 0x08,0x14,0x54,0x54,0x3c, 
 /* h */ 0x7f,0x08,0x04,0x04,0x78, /* i */ 0x00,0x44,0x7d,0x40,0x00, 
 /* j */ 0x20,0x40,0x44,0x3d,0x00, /* k */ 0x00,0x7f,0x10,0x28,0x44, 
 /* l */ 0x00,0x41,0x7f,0x40,0x00, /* m */ 0x7c,0x04,0x18,0x04,0x78, 
 /* n */ 0x7c,0x08,0x04,0x04,0x78, /* o */ 0x38,0x44,0x44,0x44,0x38, 
 /* p */ 0x7c,0x14,0x14,0x14,0x08, /* q */ 0x08,0x14,0x14,0x18,0x7c, 
 /* r */ 0x7c,0x08,0x04,0x04,0x08, /* s */ 0x48,0x54,0x54,0x54,0x20, 
 /* t */ 0x04,0x3f,0x44,0x40,0x20, /* u */ 0x3c,0x40,0x40,0x20,0x7c, 
 /* v */ 0x1c,0x20,0x40,0x20,0x1c, /* w */ 0x3c,0x40,0x30,0x40,0x3c, 
 /* x */ 0x44,0x28,0x10,0x28,0x44, /* y */ 0x0c,0x50,0x50,0x50,0x3c, 
 /* z */ 0x44,0x64,0x54,0x4c,0x44, /* { */ 0x00,0x08,0x36,0x41,0x00, 
 /* | */ 0x00,0x00,0x7f,0x00,0x00, /* } */ 0x00,0x41,0x36,0x08,0x00, 
 /* ~ */ 0x08,0x08,0x2a,0x1c,0x08, /*   */ 0x08,0x1c,0x2a,0x08,0x08
}; 

//
//  data in sram
//
char c = 0;			// character being output
uint8_t pauseBefore = 95;	// pause at the end of each line this long
uint8_t blink = 1;		// then turn on indicator for this long
uint8_t pauseAfter = 48;	// then wait this long before next line
volatile uint8_t run = 1;	// main program loop runs while (run);
uint8_t buffB;			// hold PORTB output 'til next interrupt
char* textPtr = text;		// pointer into display text
uint8_t* glyfPtr;		// pointer into character bitmap table
uint8_t glyfColumn;		// how far we are through the current character

ISR (TIMER0_OVF_vect) {
  if (c) {			// not at end of string
    PORTB = buffB;		// ouput one column
    if (glyfColumn++ < GLYFWIDTH) {
      buffB = pgm_read_byte (glyfPtr++);
    }
    else {			// we've output all 5 columns of character
      buffB = 0;		// prepare to put space between characters
      c = pgm_read_byte (textPtr++);	// get next character
      if (c) c -= 31;		// if it's not null, map to glyph array
      glyfPtr = (uint8_t*)((povGlyf - 5) + ((int)c << 2) + (int)c);
      glyfColumn = 0;		// start counting at first column
    }
  }
  else if (pauseBefore) {		// pause before blinking green led
    pauseBefore--;
  }
  else if (blink) {			// turn on green led
    blink--;
    PORTD |= (1 << PD2);
  }
  else if (pauseAfter) {		// pause after blinking green led
    PORTD &= ~(1 << PD2);
    pauseAfter--;
  }
  else if (textPtr < (char*)(text + sizeof(text))) {
    c = pgm_read_byte (textPtr++);
    pauseBefore = 95;
    blink = 1;
    pauseAfter = 48;
  }
  else {
    run = 0;
  }
}

int main (void) {
//
//  set up i/o ports
//
  PORTD = 0x00;					// PD2 out
  PORTB = 0x00;					// all out
  DDRD = (1 << PD2);				// indicator led
  DDRB = 0xff;					// pov display
//
//  setup timer 0, 1/1024 prescale, mode 7, 48Hz, enable interrupt
//
  TCCR0A = (1 << WGM01) | (1 << WGM00);		// select fast pwm w/ top = OCR0A
  TCCR0B = (1 << WGM02) | (1 << CS02) | (1 << CS00);	// and prescale = 1024
  OCR0A = 163;					// gives interrupt freq ca 48Hz
  TIMSK = (1 << TOIE0);				// enable overflow interrupt
  sei ();					// enable interrupts
  MCUCR = (1 << SE);				// enable idle sleep mode
  while (run) {
    sleep_cpu ();
  }
  TCCR0B = 0x00;				// stop timer
  DDRB = 0;
  DDRD = 0;
  PORTB = 0;
  PORTD = 0;
  MCUCR = (1 << SE) | (1 << SM0);		// enable shutdown sleep mode
  sleep_cpu ();					// zzzzzzzzzzzz
}

mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

Re: chemical pov

Post by mtbf0 »

i've got a problem. for some reason the above code does not quite work as intended. when a line has an even number of characters in it, instead of turning off all of the leds at the end of the line like it should, the leds from the last column of the last character in the line stay lit. if you watch the video you will see this happen at the end of the second line.

briefly, what's supposed to happen is pretty much what you see happening. the thing waits two seconds, flashes a green led attached to PD2, then outputs text until it finds a null character. each character consists of five columns of data from the povGlyf table and a blank column output on PORTB. at the end of the line, pause, flash, pause again, then do the next line.

if anyone can see what dumbass thing i'm doing to cause it to screw up only at the end of even length lines, i'd really like to be enlightened.

mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

Re: chemical pov

Post by mtbf0 »

i was fooled by my data. all of the odd length lines ended with punctuation, so the last column of the last character was always blank. once i figured that out, (duh), finding a fix was pretty simple.

change this

Code: Select all

ISR (TIMER0_OVF_vect) {
  if (c) {			// not at end of string
    PORTB = buffB;		// ouput one column
to this

Code: Select all

ISR (TIMER0_OVF_vect) {
  PORTB = buffB;		// ouput one column
  if (c) {			// not at end of string
unfortunately, the gizmo is also mangling the first character of every line. ought to be easy to fix, once i've had a little sleep.

magician13134
 
Posts: 1119
Joined: Wed Jun 13, 2007 9:17 am

Re: chemical pov

Post by magician13134 »

How bad are UV LEDs? I have a 5W UV flashlight I use and have been considering getting some orange goggles for them, is that something I should do?

sparr
 
Posts: 196
Joined: Tue Nov 04, 2008 5:21 pm

Re: chemical pov

Post by sparr »

What is the paper covered with to continue glowing like that?

mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

Re: chemical pov

Post by mtbf0 »

i fixed the bug that was causing the first character in each line to be garbled. i changed this

Code: Select all

  else if (textPtr < (char*)(text + sizeof(text))) {
    c = pgm_read_byte (textPtr++);
    pauseBefore = 95;
    blink = 1;
    pauseAfter = 48;
  }
to this

Code: Select all

  else if (textPtr < (char*)(text + sizeof(text))) {
    c = 0xff;
    glyfColumn = 5;
    pauseBefore = 95;
    blink = 1;
    pauseAfter = 46;
  }
the idea here is to force the bits at the beginning of the isr to read the first character of the next line and to calculate the offset into the povGlyf array. since this causes a delay of two interrupt calls before output begins again i set pauseAfter to 46 instead of 48 in order to give the intended 1 second delay after the indocator led blinks.
magician13134 wrote:How bad are UV LEDs? I have a 5W UV flashlight I use and have been considering getting some orange goggles for them, is that something I should do?

i don't really know, but i was using the leds to display variable values while debugging and although i was looking at them from the side my eyes started feeling a little wierd. coud have been allergies, i guess, but i got out my old minipov with the red leds and used it for debugging.
sparr wrote:What is the paper covered with to continue glowing like that?
fluorescent paint. specifically krylon glowz, but in future i think i'll go with a liquid paint for thicker and more even coverage.

User avatar
amberwolf
 
Posts: 310
Joined: Wed Oct 08, 2008 2:42 am

Re: chemical pov

Post by amberwolf »

"Fluorescent" or "phosphorescent"? I suspect the latter, as the other would not normally continue glowing at all once the UV stopped shining on it.

I have some phosphorescent "glow in the dark" paper for PC printers picked up when CompUSA shutdown, and I like to amaze certain people by "writing" on it in the dark with my Doctor Who Sonic Screwdriver toy that my sister had gotten me for my birthday a couple of years ago--it has a blue LED in it that outputs some UV, enough to notice a bit of fluorescence on my DayGlo Avenger paintjobs on my bikes in an otherwise UV-free room, and enough to cause any phosphorescent paints to glow for a bit if it's held fairly close (a few inches or closer).

It looks just about like the way your video does, regarding the fading "printed" message from the POV.


As for the UV being harmful to the eyes, well, for 5Watt lights they could be harmful even if they were just normal visible light. UV light I am not sure about, but your eyes *can* detect some UV in at least part of the spectrum. I don't know if the LEDs you have output in that part or not. I'm sure you wouldn't want to point them directly at your eye, or at a surface close to you to get a lot of UV reflection, at the least.

UV is one reason why welders use such dark filters on their helmets, because there is a LOT of it generated via the electric arc. Enough to tan any part of my arms and hands and neck that I accidentally leave exposed for even a few minutes while welding, and enough to give me a heck of a headache if I manage to accidentally strike an arc without the filter completely in front of my eyes (that doesnt' happen now, but when I started it did a few times).

mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

Re: chemical pov

Post by mtbf0 »

Amberwolf wrote:"Fluorescent" or "phosphorescent"? I suspect the latter, as the other would not normally continue glowing at all once the UV stopped shining on it.
yeah, i usually try to say what i mean, but that 'uo' diphthong in fluorescent is so seductive, and phophorescence sounds like sylvester the cat with a bad hangover.

i'll try to do better.

mtbf0
 
Posts: 1645
Joined: Sat Nov 10, 2007 12:59 am

Re: chemical pov

Post by mtbf0 »

here's a new video of the thing after the bugs were eradicated.

http://www.youtube.com/watch?v=DunP3g0_7sg

camera kept focusing on my arm and putting the text out of focus, but i think most of it's readable.

Locked
Please be positive and constructive with your questions and comments.

Return to “MiniPOV”