// POV code 5.00 BlinkM version

// Tested on real hardware

// CHANGELOG:

// 5.00 Fixed most, if not all bugs! Will add serial in the future

// 4.00 Complete rewrite, removed POV programming except over serial

// due to complexity - also moved character arrays to Flash using PROGMEM

// 3.01 BETA Oops, forgot to include some of the code! Fixed

// Little more cleanup

// Going to add serial support, probably in 3.10 or higher.

// 3.00 BETA Now with support for saving up to 16 RGB color mixes

// Support for up to 16 custom characters

// Status LED added to design

// 2.10 Cleaned up some more

// 2.00 Ultra fix, POV should work properly, lot of bad code replaced

// Also added BlinkM extra options and POV timing options

// 1.20 Cleanup, still pretty crappy code in my opinion

// 1.10 Fixed critical POV display bug

// 1.00 Initial crappy release

// TODO:

// More cleanup

// Incorporate serial programming methods

// Test the code out on the real thing!

/*

You need:

ATMega328 chip

16MHz crystal oscillator

8 LEDs

8-switch DIP switch

8 100-ohm resistors (for 3.2V forward voltage LED)

3 push buttons

3-way switch (on-on)

10k-ohm resistor (plus optional button for reset)

TPIC6A595 or comparable shift register

BlinkM

Connect DIP switch to digital pins 5-8/Analog In 0-3 and ground

Connect pushbuttons to digital pins 2-4 and ground

Connect 3-way switch like this:

5V - SYS - GND

Connect TPIC6A595 registers:

dataPin (12) connects to SERIN

clockPin (11) connects to SRCK

latchPin (10) connects to RCK

BlinkM should be connected to Analog In 4/5, 5V and GND.

Refer to wiring diagram for wiring details.

*/

// Let's include the libraries we'll need

// This includes switch debouncing, EEPROM

// read/write access, I2C library, PROGMEM,

// specialized BlinkM functions

#include <Bounce.h>

#include <EEPROM.h>

#include <Wire.h>

#include <BlinkM_funcs.h>

#include <avr/pgmspace.h>

#include <Flash.h>

// Character set - A-Z, a-z, 0-9, some symbols

PROGMEM prog_uchar POVA [ ] = { 254 , 25 , 25 , 254 , 0 } ;

PROGMEM prog_uchar POVB [ ] = { 255 , 153 , 153 , 118 , 0 } ;

PROGMEM prog_uchar POVC [ ] = { 126 , 129 , 129 , 66 , 0 } ;

PROGMEM prog_uchar POVD [ ] = { 255 , 129 , 129 , 126 , 0 } ;

PROGMEM prog_uchar POVE [ ] = { 255 , 137 , 137 , 137 , 0 } ;

PROGMEM prog_uchar POVF [ ] = { 255 , 9 , 9 , 9 , 0 } ;

PROGMEM prog_uchar POVG [ ] = { 126 , 129 , 145 , 241 , 0 } ;

PROGMEM prog_uchar POVH [ ] = { 255 , 24 , 24 , 255 , 0 } ;

PROGMEM prog_uchar POVI [ ] = { 129 , 255 , 255 , 129 , 0 } ;

PROGMEM prog_uchar POVJ [ ] = { 24 , 129 , 129 , 127 , 0 } ;

PROGMEM prog_uchar POVK [ ] = { 255 , 24 , 24 , 231 , 0 } ;

PROGMEM prog_uchar POVL [ ] = { 255 , 128 , 128 , 128 , 0 } ;

PROGMEM prog_uchar POVM [ ] = { 255 , 2 , 12 , 2 , 255 , 0 } ;

PROGMEM prog_uchar POVN [ ] = { 255 , 6 , 24 , 96 , 255 , 0 } ;

PROGMEM prog_uchar POVO [ ] = { 126 , 129 , 129 , 126 , 0 } ;

PROGMEM prog_uchar POVP [ ] = { 255 , 9 , 9 , 6 , 0 } ;

PROGMEM prog_uchar POVQ [ ] = { 126 , 129 , 129 , 255 , 0 } ;

PROGMEM prog_uchar POVR [ ] = { 255 , 9 , 25 , 230 , 0 } ;

PROGMEM prog_uchar POVS [ ] = { 134 , 137 , 137 , 131 , 0 } ;

PROGMEM prog_uchar POVT [ ] = { 1 , 255 , 255 , 1 , 0 } ;

PROGMEM prog_uchar POVU [ ] = { 127 , 128 , 128 , 127 , 0 } ;

PROGMEM prog_uchar POVV [ ] = { 63 , 192 , 192 , 63 , 0 } ;

PROGMEM prog_uchar POVW [ ] = { 127 , 128 , 112 , 128 , 127 , 0 } ;

PROGMEM prog_uchar POVX [ ] = { 231 , 24 , 24 , 231 , 0 } ;

PROGMEM prog_uchar POVY [ ] = { 15 , 240 , 240 , 15 , 0 } ;

PROGMEM prog_uchar POVZ [ ] = { 225 , 145 , 137 , 135 , 0 } ;

PROGMEM prog_uchar POVAL [ ] = { 64 , 168 , 168 , 112 , 0 } ;

PROGMEM prog_uchar POVBL [ ] = { 248 , 160 , 160 , 64 , 0 } ;

PROGMEM prog_uchar POVCL [ ] = { 112 , 136 , 136 , 80 , 0 } ;

PROGMEM prog_uchar POVDL [ ] = { 64 , 160 , 160 , 120 , 0 } ;

PROGMEM prog_uchar POVEL [ ] = { 112 , 168 , 168 , 176 , 0 } ;

PROGMEM prog_uchar POVFL [ ] = {

32 , 240 , 40 , 40

, 0 } ;

PROGMEM prog_uchar POVGL [ ] = {

144 , 168 , 168 , 120

, 0 } ;

PROGMEM prog_uchar POVHL [ ] = {

248 , 32 , 32 , 192

, 0 } ;

PROGMEM prog_uchar POVIL [ ] = {

232 , 232

, 0 } ;

PROGMEM prog_uchar POVJL [ ] = {

64 , 128 , 128 , 104

, 0 } ;

PROGMEM prog_uchar POVKL [ ] = {

248 , 64 , 96 , 144

, 0 } ;

PROGMEM prog_uchar POVLL [ ] = {

248 , 128

, 0 } ;

PROGMEM prog_uchar POVML [ ] = {

240 , 8 , 48 , 8 , 240

, 0 } ;

PROGMEM prog_uchar POVNL [ ] = {

248 , 8 , 8 , 240

, 0 } ;

PROGMEM prog_uchar POVOL [ ] = {

112 , 136 , 136 , 112

, 0 } ;

PROGMEM prog_uchar POVPL [ ] = {

248 , 40 , 40 , 16

, 0 } ;

PROGMEM prog_uchar POVQL [ ] = {

16 , 40 , 40 , 248

, 0 } ;

PROGMEM prog_uchar POVRL [ ] = {

248 , 16 , 8 , 8

, 0 } ;

PROGMEM prog_uchar POVSL [ ] = {

144 , 168 , 168 , 72

, 0 } ;

PROGMEM prog_uchar POVTL [ ] = {

16 , 120 , 144

, 0 } ;

PROGMEM prog_uchar POVUL [ ] = {

120 , 128 , 128 , 248

, 0 } ;

PROGMEM prog_uchar POVVL [ ] = {

120 , 192 , 120

, 0 } ;

PROGMEM prog_uchar POVWL [ ] = {

120 , 128 , 96 , 128 , 120

, 0 } ;

PROGMEM prog_uchar POVXL [ ] = {

216 , 32 , 216

, 0 } ;

PROGMEM prog_uchar POVYL [ ] = {

152 , 160 , 120

, 0 } ;

PROGMEM prog_uchar POVZL [ ] = {

136 , 200 , 168 , 152 , 136

, 0 } ;

PROGMEM prog_uchar POV0 [ ] = {

126 , 225 , 153 , 135 , 126

, 0 } ;

PROGMEM prog_uchar POV1 [ ] = {

132 , 130 , 255 , 128

, 0 } ;

PROGMEM prog_uchar POV2 [ ] = {

194 , 161 , 145 , 142

, 0 } ;

PROGMEM prog_uchar POV3 [ ] = {

137 , 137 , 137 , 118

, 0 } ;

PROGMEM prog_uchar POV4 [ ] = {

24 , 20 , 18 , 255

, 0 } ;

PROGMEM prog_uchar POV5 [ ] = {

79 , 137 , 137 , 113

, 0 } ;

PROGMEM prog_uchar POV6 [ ] = {

126 , 145 , 145 , 98

, 0 } ;

PROGMEM prog_uchar POV7 [ ] = {

193 , 49 , 9 , 7

, 0 } ;

PROGMEM prog_uchar POV8 [ ] = {

118 , 137 , 137 , 118

, 0 } ;

PROGMEM prog_uchar POV9 [ ] = {

78 , 145 , 145 , 126

, 0 } ;

PROGMEM prog_uchar POVSP [ ] = {

0

} ;

PROGMEM prog_uchar POVcolon [ ] = {

102 , 102

, 0 } ;

PROGMEM prog_uchar POVsemicolon [ ] = {

70 , 54

, 0 } ;

PROGMEM prog_uchar POVquestion [ ] = {

2 , 177 , 9 , 6

, 0 } ;

PROGMEM prog_uchar POVdash [ ] = {

24 , 24 , 24 , 24

, 0 } ;

PROGMEM prog_uchar POVperiod [ ] = {

192 , 192

, 0 } ;

PROGMEM prog_uchar POVexclamation [ ] = {

223 , 223

, 0 } ;

// Define constants here

#define DATAPIN 12

#define CLOCKPIN 10

#define LATCHPIN 11

// Note: 0x00 means general call in I2C

// It will call ALL devices on the I2C bus

#define BLINKM_ADDR 0x00

// Connect pushbuttons to pins 2,3,4

// No pullup/pulldown resistor

byte textPOV [ 128 ] ;

int arrayused = 0 ;

byte columnDelay = 0 ; // set delay between column flashes in ms

byte wordDelay = 0 ; // set delay between words in ms

char displayString [ ] = "KNIGHTS" ;

Bounce button2 = Bounce ( 2 , 5 ) ;

Bounce button3 = Bounce ( 3 , 5 ) ;

Bounce button4 = Bounce ( 4 , 5 ) ;

void setup ( ) {

// For debugging purposes

Serial. begin ( 9600 ) ;

Serial. println ( "Setting up" ) ;

// We set shift register pins to output for SPI communication

pinMode ( DATAPIN , OUTPUT ) ;

pinMode ( CLOCKPIN , OUTPUT ) ;

pinMode ( LATCHPIN , OUTPUT ) ;

writeToRegister ( 0 ) ;

// Set pins to input state and activate pullup resistors

// This will allow us to read the DIP switch/pushbuttons

for ( int i = 2 ; i < 9 ; i ++ ) {

pinMode ( i , INPUT ) ;

digitalWrite ( i , HIGH ) ;

}

for ( int i = 14 ; i < 18 ; i ++ ) {

pinMode ( i , INPUT ) ;

digitalWrite ( i , HIGH ) ;

}

stringParse ( ) ;

// Update button states

button2. update ( ) ;

button3. update ( ) ;

button4. update ( ) ;

// Initialize BlinkM

BlinkM_begin ( ) ;

BlinkM_stopScript ( 0x00 ) ;

BlinkM_setRGB ( BLINKM_ADDR , 0 , 0 , 0 ) ;

delay ( 100 ) ;

}

void loop ( )

{

// Is a pushbutton pressed?

button2. update ( ) ;

button3. update ( ) ;

button4. update ( ) ;

// Switch to programming mode

/*if (button2.read() == LOW)

programText();

*/

// Strobe light/white light

if ( button2. read ( ) == LOW )

lightLED ( ) ;

// Switch to BlinkM flashlight

if ( button3. read ( ) == LOW )

BlinkM ( ) ;

// Adjust delay speed

if ( button4. read ( ) == LOW )

delaySpeed ( ) ;

// If not, run POV

printWord ( ) ;

writeToRegister ( 0 ) ;

//delay(5);

delay ( wordDelay ) ; //Wait a little bit between each display of the word

}

void lightLED ( ) {

while ( button2. read ( ) == LOW ) {

button2. update ( ) ;

}

writeToRegister ( 255 ) ;

while ( button2. read ( ) == HIGH ) {

button2. update ( ) ;

}

while ( button2. read ( ) == LOW ) {

button2. update ( ) ;

}

byte temp = DIPInput ( ) ;

do {

button2. update ( ) ;

writeToRegister ( 0 ) ;

delay ( temp ) ;

writeToRegister ( 255 ) ;

delay ( temp ) ;

} while ( button2. read ( ) == HIGH ) ;

writeToRegister ( 0 ) ;

}

// Start BlinkM flashlight

void BlinkM ( ) {

//Serial.println("BlinkM mode");

// Initialize variables

static byte RGB [ 3 ] ;

static byte scriptnum = 0 ;

// Turn off all the POV LEDs

writeToRegister ( 0 ) ;

// Set up BlinkM speed

BlinkMSetSpeed ( ) ;

// Let's set up the BlinkM's color

// Set script to default - no color

BlinkM_playScript ( BLINKM_ADDR , scriptnum , 0 , 0 ) ;

// Read color data from EEPROM

readColorFromEEPROM ( RGB ) ;

// Send it a 3 byte RGB color value

BlinkM_setRGB ( BLINKM_ADDR , RGB [ 0 ] , RGB [ 1 ] , RGB [ 2 ] ) ;

// Wait for user to release the mode switch button

while ( button3. read ( ) == LOW ) {

button3. update ( ) ;

}

// Main BlinkM loop

// Executes until mode switch button is pressed

// It will then return to the main POV loop

do {

// Update button states

button2. update ( ) ;

button3. update ( ) ;

button4. update ( ) ;

// Are any buttons pressed?

// Program button

if ( button2. read ( ) == LOW )

programRGB ( RGB ) ;

// Light script switch button

if ( button4. read ( ) == LOW ) {

BlinkMSetSpeed ( ) ;

BlinkM_playScript ( BLINKM_ADDR , scriptnum , 0 , 0 ) ;

scriptnum ++;

if ( scriptnum > 18 )

scriptnum = 0 ;

while ( button4. read ( ) == LOW ) {

button4. update ( ) ;

}

}

// Wait for button to be released

while ( button2. read ( ) == LOW || button3. read ( ) == LOW || button4. read ( ) == LOW ) {

button2. update ( ) ;

button3. update ( ) ;

button4. update ( ) ;

}

}

// Keep looping until mode switch button is pressed

while ( button3. read ( ) == HIGH ) ;

// Let's turn off the BlinkM

BlinkM_stopScript ( BLINKM_ADDR ) ;

BlinkM_setRGB ( BLINKM_ADDR , 0 , 0 , 0 ) ;

// Return to POV code

return ;

}

// Display the POV text

void printWord ( ) {

for ( int i = 0 ; i < arrayused ; i ++ ) {

writeToRegister ( textPOV [ i ] ) ;

delay ( columnDelay ) ;

}

}

// Uses SPI to clock in data, then latches to set LED on/off

void writeToRegister ( byte data ) {

shiftOut ( DATAPIN , CLOCKPIN , MSBFIRST , data ) ;

digitalWrite ( LATCHPIN , HIGH ) ;

digitalWrite ( LATCHPIN , LOW ) ;

}

// Change BlinkM's RGB color

void programRGB ( byte * colorarray ) {

byte RGBState = 0 ;

while ( button2. read ( ) == LOW ) {

button2. update ( ) ;

}

do {

// Update the button

button3. update ( ) ;

// To completely change the color, you need to press the pushbutton 3 times

// and adjust DIP switches 3 times

// Wait for button press, if pressed then save + update color information

if ( button3. read ( ) == LOW ) {

colorarray [ RGBState ] = DIPInput ( ) ;

RGBState ++;

BlinkM_fadeToRGB ( BLINKM_ADDR , colorarray [ 0 ] , colorarray [ 1 ] , colorarray [ 2 ] ) ;

while ( button3. read ( ) == LOW ) {

button3. update ( ) ;

}

}

}

// Keep looping until programming button pressed

while ( RGBState < 3 ) ;

RGBState = 0 ;

writeColorToEEPROM ( colorarray [ 0 ] , colorarray [ 1 ] , colorarray [ 2 ] ) ;

return ;

}

// Reads the DIP switch for 1 byte input

byte DIPInput ( ) {

// Initialize variables

byte readDIP = 0 ;

// Every read, if on, add 1

// Then bitshift left by 1

for ( int i = 5 ; i < 9 ; i ++ ) {

if ( digitalRead ( i ) == LOW )

readDIP += 1 ;

readDIP = readDIP << 1 ;

}

for ( int i = 14 ; i < 18 ; i ++ ) {

if ( digitalRead ( i ) == LOW )

readDIP += 1 ;

readDIP = readDIP << 1 ;

}

return readDIP ;

}

// Set POV delay speed

void delaySpeed ( ) {

// Clear POV LEDs

writeToRegister ( 0 ) ;

// Wait for user to release button

while ( button4. read ( ) == LOW ) {

button4. update ( ) ;

}

while ( button4. read ( ) == HIGH ) {

button4. update ( ) ;

}

// Get input from switches and save

wordDelay = DIPInput ( ) ;

while ( button4. read ( ) == LOW ) {

button4. update ( ) ;

}

while ( button4. read ( ) == HIGH ) {

button4. update ( ) ;

}

columnDelay = DIPInput ( ) ;

// Save delay information to EEPROM

EEPROM. write ( 0 , wordDelay ) ;

EEPROM. write ( 1 , columnDelay ) ;

while ( button4. read ( ) == LOW ) {

button4. update ( ) ;

}

}

// This sets fade speed and time adjustment on the BlinkM

void BlinkMSetSpeed ( ) {

// initialize our variables

byte dip = 0 ;

byte fade = 0 ;

byte time = 0 ;

// Read information from DIP switches

dip = DIPInput ( ) ;

// Map our 4 bit inputs (0-15) to 8 bit values (0-255)

fade = map ( ( dip & B11110000 ) << 3 , 0 , 15 , 0 , 255 ) ;

time = map ( ( dip & B00001111 ) << 1 , 0 , 15 , 0 , 255 ) ;

// Adjust fade speed and time adjustment

BlinkM_setFadeSpeed ( BLINKM_ADDR , fade ) ;

BlinkM_setTimeAdj ( BLINKM_ADDR , time ) ;

}

void readColorFromEEPROM ( byte * colors ) {

colors [ 0 ] = EEPROM. read ( 64 ) ;

colors [ 1 ] = EEPROM. read ( 65 ) ;

colors [ 2 ] = EEPROM. read ( 66 ) ;

}

void writeColorToEEPROM ( byte red , byte blue , byte green ) {

EEPROM. write ( 64 , red ) ;

EEPROM. write ( 65 , blue ) ;

EEPROM. write ( 66 , green ) ;

}

void stringParse ( ) {

for ( int i = 0 ; i < sizeof ( displayString ) - 1 ; i ++ ) {

charLookup ( displayString [ i ] ) ;

}

}

void copyFromFlash ( prog_uchar chardata [ ] ) {

byte temp = 0 ;

if ( arrayused >= sizeof ( textPOV ) ) {

Serial. print ( "Array out of space" ) ;

return ;

}

for ( int i = 0 ; true ; i ++ ) {

temp = pgm_read_byte_near ( chardata + i ) ;

if ( temp == 0 ) break ;

textPOV [ arrayused ] = temp ;

arrayused ++;

}

textPOV [ arrayused ] = 0 ;

arrayused ++;

}

// Simply lookup the character and return the LED flash placement data

void charLookup ( char inputchar ) {

switch ( inputchar ) {

case 'A' :

copyFromFlash ( POVA ) ;

break ;

case 'B' :

copyFromFlash ( POVB ) ;

break ;

case 'C' :

copyFromFlash ( POVC ) ;

break ;

case 'D' :

copyFromFlash ( POVD ) ;

break ;

case 'E' :

copyFromFlash ( POVE ) ;

break ;

case 'F' :

copyFromFlash ( POVF ) ;

break ;

case 'G' :

copyFromFlash ( POVG ) ;

break ;

case 'H' :

copyFromFlash ( POVH ) ;

break ;

case 'I' :

copyFromFlash ( POVI ) ;

break ;

case 'J' :

copyFromFlash ( POVJ ) ;

break ;

case 'K' :

copyFromFlash ( POVK ) ;

break ;

case 'L' :

copyFromFlash ( POVL ) ;

break ;

case 'M' :

copyFromFlash ( POVM ) ;

break ;

case 'N' :

copyFromFlash ( POVN ) ;

break ;

case 'O' :

copyFromFlash ( POVO ) ;

break ;

case 'P' :

copyFromFlash ( POVP ) ;

break ;

case 'Q' :

copyFromFlash ( POVQ ) ;

break ;

case 'R' :

copyFromFlash ( POVR ) ;

break ;

case 'S' :

copyFromFlash ( POVS ) ;

break ;

case 'T' :

copyFromFlash ( POVT ) ;

break ;

case 'U' :

copyFromFlash ( POVU ) ;

break ;

case 'V' :

copyFromFlash ( POVV ) ;

break ;

case 'W' :

copyFromFlash ( POVW ) ;

break ;

case 'X' :

copyFromFlash ( POVX ) ;

break ;

case 'Y' :

copyFromFlash ( POVY ) ;

break ;

case 'Z' :

copyFromFlash ( POVZ ) ;

break ;

case 'a' :

copyFromFlash ( POVAL ) ;

break ;

case 'b' :

copyFromFlash ( POVBL ) ;

break ;

case 'c' :

copyFromFlash ( POVCL ) ;

break ;

case 'd' :

copyFromFlash ( POVDL ) ;

break ;

case 'e' :

copyFromFlash ( POVEL ) ;

break ;

case 'f' :

copyFromFlash ( POVFL ) ;

break ;

case 'g' :

copyFromFlash ( POVGL ) ;

break ;

case 'h' :

copyFromFlash ( POVHL ) ;

break ;

case 'i' :

copyFromFlash ( POVIL ) ;

break ;

case 'j' :

copyFromFlash ( POVJL ) ;

break ;

case 'k' :

copyFromFlash ( POVKL ) ;

break ;

case 'l' :

copyFromFlash ( POVLL ) ;

break ;

case 'm' :

copyFromFlash ( POVML ) ;

break ;

case 'n' :

copyFromFlash ( POVNL ) ;

break ;

case 'o' :

copyFromFlash ( POVOL ) ;

break ;

case 'p' :

copyFromFlash ( POVPL ) ;

break ;

case 'q' :

copyFromFlash ( POVQL ) ;

break ;

case 'r' :

copyFromFlash ( POVRL ) ;

break ;

case 's' :

copyFromFlash ( POVSL ) ;

break ;

case 't' :

copyFromFlash ( POVTL ) ;

break ;

case 'u' :

copyFromFlash ( POVUL ) ;

break ;

case 'v' :

copyFromFlash ( POVVL ) ;

break ;

case 'w' :

copyFromFlash ( POVWL ) ;

break ;

case 'x' :

copyFromFlash ( POVXL ) ;

break ;

case 'y' :

copyFromFlash ( POVYL ) ;

break ;

case 'z' :

copyFromFlash ( POVZL ) ;

break ;

case '0' :

copyFromFlash ( POV0 ) ;

break ;

case '1' :

copyFromFlash ( POV1 ) ;

break ;

case '2' :

copyFromFlash ( POV2 ) ;

break ;

case '3' :

copyFromFlash ( POV3 ) ;

break ;

case '4' :

copyFromFlash ( POV4 ) ;

break ;

case '5' :

copyFromFlash ( POV5 ) ;

break ;

case '6' :

copyFromFlash ( POV6 ) ;

break ;

case '7' :

copyFromFlash ( POV7 ) ;

break ;

case '8' :

copyFromFlash ( POV8 ) ;

break ;

case '9' :

copyFromFlash ( POV9 ) ;

break ;

case '.' :

copyFromFlash ( POVperiod ) ;

break ;

case '?' :

copyFromFlash ( POVquestion ) ;

break ;

case '!' :

copyFromFlash ( POVexclamation ) ;

break ;

case ':' :

copyFromFlash ( POVcolon ) ;

break ;

case ';' :

copyFromFlash ( POVsemicolon ) ;

break ;

case '-' :

copyFromFlash ( POVdash ) ;

break ;

/*

case 1:

for (int i=0; i < sizeof(POVC0); i++) {

textPOV[POVBlength] = POVC0[i];

POVBlength++;

}

break;

case 2:

for (int i=0; i < sizeof(POVC1); i++) {

textPOV[POVBlength] = POVC1[i];

POVBlength++;

}

break;

case 3:

for (int i=0; i < sizeof(POVC2); i++) {

textPOV[POVBlength] = POVC2[i];

POVBlength++;

}

break;

case 4:

for (int i=0; i < sizeof(POVC3); i++) {

textPOV[POVBlength] = POVC3[i];

POVBlength++;

}

break;

case 5:

for (int i=0; i < sizeof(POVC4); i++) {

textPOV[POVBlength] = POVC4[i];

POVBlength++;

}

break;

case 6:

for (int i=0; i < sizeof(POVC5); i++) {

textPOV[POVBlength] = POVC5[i];

POVBlength++;

}

break;

case 7:

for (int i=0; i < sizeof(POVC6); i++) {

textPOV[POVBlength] = POVC6[i];

POVBlength++;

}

break;

case 8:

for (int i=0; i < sizeof(POVC7); i++) {

textPOV[POVBlength] = POVC7[i];

POVBlength++;

}

break;

case 9:

for (int i=0; i < sizeof(POVC8); i++) {

textPOV[POVBlength] = POVC8[i];

POVBlength++;

}

break;

case 10:

for (int i=0; i < sizeof(POVC9); i++) {

textPOV[POVBlength] = POVC9[i];

POVBlength++;

}

break;

case 11:

for (int i=0; i < sizeof(POVC10); i++) {

textPOV[POVBlength] = POVC10[i];

POVBlength++;

}

break;

case 12:

for (int i=0; i < sizeof(POVC11); i++) {

textPOV[POVBlength] = POVC11[i];

POVBlength++;

}

break;

case 13:

for (int i=0; i < sizeof(POVC12); i++) {

textPOV[POVBlength] = POVC12[i];

POVBlength++;

}

break;

case 14:

for (int i=0; i < sizeof(POVC13); i++) {

textPOV[POVBlength] = POVC13[i];

POVBlength++;

}

break;

case 15:

for (int i=0; i < sizeof(POVC14); i++) {

textPOV[POVBlength] = POVC14[i];

POVBlength++;

}

break;

case 16:

for (int i=0; i < sizeof(POVC15); i++) {

textPOV[POVBlength] = POVC15[i];

POVBlength++;

}

break;

*/

default :

textPOV [ arrayused ] = 0 ;

Serial. print ( "Writing byte 0" ) ;

arrayused ++;

textPOV [ arrayused ] = 0 ;

Serial. print ( "Writing byte 0" ) ;

arrayused ++;

// copyFromFlash(58);

break ;

}

arrayused ++;

textPOV [ arrayused ] = 0 ;

}

/*

// Program new text for POV

// If mode switch button is pressed, read DIP switches and change text accordingly

// Press programming button again to exit

void programText() {

// Initialize our variables

byte num = 0;

byte temp = 0;

POVlength = 0;

POVBlength = 0;

// Clear the POV LEDs

writeToRegister(0);

// Let's clear the button state

while (button2.read() == LOW){

button2.update();

}

if (DIPInput() & B11110000 == 16) {

byte temp2 = 0;

byte temp3[8];

num = DIPInput() & B1111 + 1;

do {

button3.update();

if (button3.read() == LOW) {

temp = DIPInput();

// Show which character was saved

writeToRegister(temp);

temp3[temp2] = temp;

temp2++;

}

}

while (button4.read() == HIGH && temp2 < 8);

writeCharData(num,temp3);

return;

}

// wait for button press, then read DIP switch and save data

do {

button3.update();

if (button3.read() == LOW) {

temp = DIPInput();

// Does the input exceed character database limits?

// If so, fix it to a space

if (temp > sizeof(charTable))

temp = 0;

// Lookup the character

charPOV[POVlength] = charTable[temp];

charLookup(charTable[temp]);

POVlength++;

// Show which character was saved

writeToRegister(temp);

}

// Update the button state

button2.update();

}

// Keep going until text length is 64 or user exits mode

while (button2.read() == HIGH && POVlength < 64);

// Write the data to EEPROM

writeTextToEEPROM(charPOV,POVlength);

return;

}

// Write POV data to EEPROM

void writeTextToEEPROM(byte wordVar[], byte length) {

// Save delay information

EEPROM.write(0,wordDelay);

EEPROM.write(1,columnDelay);

length += 1;

for(int i = 1; i < length; i++) {

EEPROM.write(i+2,wordVar[i]);

}

// Save length information

EEPROM.write(2,length);

}

// Read saved text from EEPROM

byte readTextFromEEPROM() {

// Initialize variables

byte temp = 0;

byte length = 0;

byte size = 0;

POVlength = 0;

POVBlength = 0;

// If length = 0, we'll load default text

if (EEPROM.read(2) == 0)

return 0;

// Load delay/length information

wordDelay = EEPROM.read(0);

columnDelay = EEPROM.read(1);

length = EEPROM.read(2);

// Read and save data

for (int i = 1; i < length; i++) {

// Do we have enough space? If not, increase the size of textPOV

if (sizeof(textPOV) < POVBlength + 9) {

realloc(textPOV, sizeof(textPOV) + 9);

}

temp = EEPROM.read(i+2);

charPOV[POVlength] = charTable[temp];

charLookup(charTable[temp]);

POVlength++;

}

return length;

}

// Get custom character size from EEPROM

byte readCharSize(byte num) {

return EEPROM.read(175 + num);

}

// Read custom character data from EEPROM

byte *readCharData(byte num, byte cdata[]) {

byte temp = readCharSize(num);

for (int i = 0; i < temp; i++){

cdata[i] = EEPROM.read(176 + 8 * num + i);

}

return cdata;

}

// Stores custom character data to EEPROM

void writeCharData(byte num, byte cdata[]) {

EEPROM.write(175 + num, sizeof(cdata));

for (int i = 0; i < sizeof(cdata); i++) {

EEPROM.write(176 + 8 * num + i, cdata[i]);

}

}

// If EEPROM is empty, load default text

byte loadDefaultText() {

// Initialize variables

byte temp = 0;

POVlength = 0;

POVBlength = 0;

// Let's copy defaultText into the POV buffer

realloc(charPOV, sizeof(defaultText));

memcpy(charPOV, defaultText, sizeof(defaultText));

POVlength = sizeof(charPOV);

// Convert the POV buffer into the binary LED states

for(int i = 0; i < POVlength; i++) {

if (sizeof(textPOV) < POVBlength + 6) {

realloc(textPOV, sizeof(textPOV) + 6);

}

charLookup(charPOV[i]);

}

}

// Blink the status LED on pin 13

void blinkLED(byte blinkDelay) {

// The first time the function is called, blinkStatus will be set to 0

static unsigned long blinkStatus;

if (millis() > abs(blinkStatus) + blinkDelay) {

if (blinkStatus < 0) {

digitalWrite(13,LOW);

blinkStatus = millis();

}

else {

digitalWrite(13,HIGH);

blinkStatus = -millis();

}

}

}