Arduino Persistence of Vision Display
Arduino Persistence of Vision Display
Arduino Persistence of Vision Display
Table of Contents
File Downloads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Related Instructables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
http://www.instructables.com/id/Arduino-Persistence-of-Vision-Display/
Author:Mr.What author's website
Degrees in EE, specializing in Digital Signal Processing. Working as a software engineer for 20+ years.
The hardware setup for a PoV display is fairly straightforward, but this instructable contains code where the display can be controlled and programmed readily over the
serial connection, and display settings can be saved so that they are automatically loaded and run when powered up from a battery.
You will want an Arduino AVR microcontroller board, such as an Uno, Nano, or mini. Around 10 LED's, and 10 resistors from about 100 to 220 ohms.
For our example, we will assume a 10 LED display. Wire the LED's in series with a resistor to digital I/O pins 3-10, and arrange them in a straight row.
From the serial monitor (or terminal emulator), type h to get the help menu. This will show several commands.
My Serial reader class compresses whitespace, so you will want to use . to represent "off" in the line settings. See the attached Quelab.dat sample line setting input file.
The lines of this file can be cut and pasted into a terminal emulator to set the PoV message.
Once your desired display has been loaded, use the s) command to save its settings to EEPROM to be used at next reset.
#define MODE_UNKNOWN 0
#define MODE_PoV 1
#define MODE_RANDOM 2
#define MODE_CYLON 3
#define MAX_COLS 96
#define SERIAL_BUF_LEN (MAX_COLS+15)
#include
SerialLineBuffer LineBuf;
struct {
short nCols; // no. columns in buffer
short spaceCols; // no. columns "space" time before repeat or reverse
short mode; // MODE_ code from above
short cylonCols; // no. cols of time for each cylon flash
int colTime; // milliseconds/column
int misc[3]; // reserved for future use
short disp[MAX_COLS]; // display flags
} State;
#include
void loadState()
{
int n = sizeof(State);
byte *bp = (byte *)(&tate);
for(int i=0; i < n; i++, bp++) *bp = EEPROM.read(i);
if (!validState()) initState();
}
void saveState()
{
int n = sizeof(State);
byte *bp = (byte *)(&tate);
for(int i=0; i < n; i++, bp++) EEPROM.write(i,*bp);
}
void setup()
{
int i;
for (i=0;i {
pinMode(ledPins[i],OUTPUT);
}
pinMode(13,OUTPUT); // use on-board LED
// restore state from EEPROM
loadState();
Serial.begin(9600);
http://www.instructables.com/id/Arduino-Persistence-of-Vision-Display/
}
void loop()
{
checkCommand();
int i,dt,k;
dt = State.colTime;
switch (State.mode)
{
case MODE_CYLON:
dt *= State.cylonCols;
for (i=0; i < NPINS; i++)
{
digitalWrite(ledPins[i],HIGH);
delay(dt);
digitalWrite(ledPins[(i+NPINS-1)%NPINS],LOW);
delay(dt);
}
for (i=NPINS-2; i >= 0; i--)
{
digitalWrite(ledPins[i],HIGH);
delay(dt);
digitalWrite(ledPins[(i+1)%NPINS],LOW);
delay(dt);
}
break;
case MODE_PoV:
for (i=0; i < State.nCols; i++)
{
short mask=1;
for (k=0; k < NPINS; k++, mask <<= 1)
digitalWrite(ledPins[k],(mask &State.disp[i])?HIGH:LOW);
}
for (k=0; k < NPINS; k++) digitalWrite(ledPins[k],LOW);
delay(State.spaceCols*dt);
break;
default: // random default
{
dt *= 10;
k = random(100);
int lvl = (k<50)?LOW:HIGH;
int j = random(NPINS);
digitalWrite(ledPins[j],lvl);
delay(dt);
}
}
digitalWrite(13,digitalRead(13)?LOW:HIGH); // toggle heartbeat
}
void printState()
{
Serial.print(State.nCols);
Serial.print(" Columns ");
Serial.print(State.spaceCols);
Serial.print(" ");
Serial.print(State.colTime);
Serial.println("ms/col");
Serial.flush();
}
void printMsg()
{
int i,k;
Serial.println();
for (i=0; i < State.nCols; i++) Serial.print("-");
short mask=1;
for(k=0; k < NPINS; k++, mask <= 1)
{
for (i=0; i < State.nCols; i++) Serial.print(State.disp[k]&ask?"X":" ");
Serial.println("|");
}
Serial.println();
for (i=0; i < State.nCols; i++) Serial.print("-");
Serial.println();
Serial.flush();
}
bool validState()
{
// check for silly state, set to default if inconsistent
if ((State.mode <= 0) || (State.mode > 3) ||
(State.nCols< 1) || (State.nCols>MAX_COLS)) return false;
if ((State.spaceCols < 1) || (State.spaceCols > 10*MAX_COLS)) return false;
if ((State.colTime < 1) || (State.colTime > 10000)) return false;
if ((State.cylonCols < 1) || (State.cylonCols > 10000)) return false;
return true;
}
-------- ioUtil.h
class SerialLineBufferPrivates;
class SerialLineBuffer
{
public:
SerialLineBuffer();
//~SerialLineBuffer();
bool isComplete(); // reads from serial, return true if 0 or EOLN
void clear();
void begin();
int length() const;
int maxLength() const;
char *get(); // retrieve current buffer and clear
char buf[SERIAL_BUF_LEN+1];
protected:
int _maxLength, _len;
bool _complete;
private:
//class SerialLineBufferPrivates *Priv;
};
------------------------------- ioUtil.cpp
http://www.instructables.com/id/Arduino-Persistence-of-Vision-Display/
#include
#define NULL 0
void SerialLineBuffer::begin()
{
_maxLength = SERIAL_BUF_LEN; // AVR dynamic mem is tricky
_len = 0;
_complete = false;
}
SerialLineBuffer::SerialLineBuffer() { begin(); }
bool isTerminator(int c)
{
if (c == 0) return(true);
if (c == ';') return(true); // sending \n to serial is tricky. accept this too.
//if ((c=='\n') || (c=='\r') || (c=='\m')) return(true);
if ((c>=10) & (c<=13)) return(true); // \r, \n, form feed, vert tab
return(false);
}
if (isBlank(nextByte))
{
//Serial.print("blank ");Serial.println(nextByte);
if (_len > 0) // ignore leading whitespace
{
if (buf[_len-1] != ' ') // compact space to 1 space
{
buf[_len++] = ' '; // convert all space to ' '
}
}
}
else
{
buf[_len++] = (char)nextByte;
}
void SerialLineBuffer::clear()
{
_len = 0;
_complete = false;
}
int SerialLineBuffer::length() const { return(_len); }
int SerialLineBuffer::maxLength() const { return(_maxLength); }
//-----------------------------------------------------------
/// split a keyword-value pair string into a key string and value string
http://www.instructables.com/id/Arduino-Persistence-of-Vision-Display/
const char nullChar = 0; // static is scary on AVR
char *extractKey(char *cmdStr, char **val)
{
*val = (char *)&ullChar;
if (cmdStr == NULL) return(NULL);
char *key = cmdStr;
while (*key) // process comments
{
if (*key == '#') *key=0; // comment
else key++;
}
key = cmdStr;
while(*key & isBlank(*key)) key++; // trim leading space
*val = key;
while(**val & !isBlank(**val)) *val += 1; // skip key
**val = 0;
*val += 1;
while(**val & isBlank(**val)) *val += 1; // skip whitespace
return(key);
}
L0..Q.............l......b....
L1.QQQ............l......b....
L2Q...Q...........l......b....
L3Q...Q.u..u..ee..l..a.a.b.b..
L4Q...Q.u..u.e..e.l.a.aa.bb.b.
L5Q...Q.u..u.e..e.l.a..a.b..b.
L6Q.Q.Q.u..u.eeee.l.a..a.b..b.
L7Q..Q..u..u.e....l.a..a.b..b.
L8.Q.Q..u..u.e..e.l.a.aa.bb.b.
L9.QQ.Q..uu...ee..l..a.a.b.b..
http://www.instructables.com/id/Arduino-Persistence-of-Vision-Display/
File Downloads
ArduinoPoVsource.zip (4 KB)
[NOTE: When saving, if you see .tmp as the file ext, rename it to 'ArduinoPoVsource.zip']
Related Instructables
Comments
2 comments Add Comment
Arduino |\ |
D3,4,5,6,7,8, -----/\/\/\/\/\/\------| \|------- Gnd
9,10,11,12 | /|
|/ |
http://www.instructables.com/id/Arduino-Persistence-of-Vision-Display/