plain text pov - no message generator required

by tldr on Sat Mar 30, 2013 12:29 am

here is some pov code that is able to display multiple messages and does not require a message generator.

place the strings you wish to display in the text array. at the end of each line put a null character. your messages will be displayed one line at a time with a pause of approximately 1/2 a second between lines.

this program will only display ascii text. and only characters between 32 and 127.

there used to be GPL text in the comment at the beginning of the code, but the spam filter found the language objectionable.

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 pauseAfter = 200;   // then wait this long before next line
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) {
  PORTB = buffB;      // ouput one column
  if (c) {         // not at end of string
    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 (pauseAfter) {   // wait a little before next line
    pauseAfter--;
  }
  else {
    c = 0xff;         // force acquisition of 1st char of next line
    glyfColumn = 5;      // ditto
    pauseAfter = 200;
    if (textPtr >= (char*)(text + sizeof(text))) {   // if there's no more text
      textPtr = text;                             // return to beginning
    }
  }
}

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 << CS00);   // and prescale = 1
  OCR0A = 10000;         // gives interrupt freq ca 400Hz
  TIMSK = (1 << TOIE0);      // enable overflow interrupt
  sei ();         // enable interrupts
  MCUCR = (1 << SE);      // enable idle sleep mode
  while (1) {
    sleep_cpu ();
  }
 }


actually, since this code was written for my own use, there is some missing bounds checking and it will attempt to display any character with a value between 1 and 255. this will probably result in parts of the program itself being displayed. an enterprising individual could take advantage of that to display some graphics, but then said individual would probably need a message generating program to produce the data for that.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 464
Joined: Thu Aug 30, 2012 12:34 am

Re: plain text pov - no message generator required

by adafruit_support_bill on Sat Mar 30, 2013 5:43 am

Nicely done! Thanks for posting. :)
User avatar
adafruit_support_bill
 
Posts: 25404
Joined: Sat Feb 07, 2009 9:11 am