/* POV LED Message Display from RS232 Serial Port www.catahoulatech.com Original Author: Jon B Stanley Version history: 1.0 - August 4, 2014 This Arduino sketch is released in the public domain. Please maintain this header and revision history. */ // Font for ASCII to 5x10 pixel bitmap int alphabet[][5] = { {0,0,0,0,0}, // space ASCII 32 {0,0,895,0,0}, // ! ASCII 33 {0,7,0,7,0}, // " ASCII 34 {80,248,80,248,80}, // # ASCII 35 {140,282,819,354,196}, // $ ASCII 36 {390,70,48,392,390}, // % ASCII 37 {476,546,578,396,320}, // & ASCII 38 {0,0,7,0,0}, // ' ASCII 39 {0,252,258,513,0}, // ( ASCII 40 {0,513,258,252,0}, // ) ASCII 41 {40,24,14,24,40}, // * ASCII 42 {32,32,248,32,32}, // + ASCII 43 {0,768,384,0,0}, // , ASCII 44 {32,32,32,32,32}, // - ASCII 45 {0,768,768,0,0}, // . ASCII 46 {768,448,120,14,3}, // / ASCII 47 {510,513,513,513,510}, // 0 ASCII 48 {0,514,1023,512,0}, // 1 ASCII 49 {900,578,545,546,540}, // 2 ASCII 50 {388,514,545,546,476}, // 3 ASCII 51 {96,88,70,1023,64}, // 4 ASCII 52 {399,521,521,529,481}, // 5 ASCII 53 {508,546,529,529,482}, // 6 ASCII 54 {3,897,97,25,7}, // 7 ASCII 55 {492,530,529,273,238}, // 8 ASCII 56 {398,529,529,273,254}, // 9 ASCII 57 {0,204,204,0,0}, // : ASCII 58 {0,716,460,0,0}, // ; ASCII 59 {0,48,72,132,258}, // < ASCII 60 {80,80,80,80,80}, // = ASCII 61 {258,132,72,48,0}, // > ASCII 62 {6,1,865,17,14}, // ? ASCII 63 {510,513,753,657,510}, // @ ASCII 64 {1022,17,17,17,1022}, // A ASCII 65 {1023,529,529,529,510}, // B ASCII 66 {510,513,513,513,390}, // C ASCII 67 {1023,513,513,258,252}, // D ASCII 68 {1023,529,529,529,513}, // E ASCII 69 {1023,17,17,17,1}, // F ASCII 70 {510,513,545,545,482}, // G ASCII 71 {1023,32,32,32,1023}, // H ASCII 72 {0,513,1023,513,0}, // I ASCII 73 {385,513,513,511,1}, // J ASCII 74 {1023,16,40,196,771}, // K ASCII 75 {1023,512,512,512,512}, // L ASCII 76 {1023,2,60,2,1023}, // M ASCII 77 {1023,4,120,128,1023}, // N ASCII 78 {510,513,513,513,510}, // O ASCII 79 {1023,17,17,17,14}, // P ASCII 80 {510,513,641,257,766}, // Q ASCII 81 {1023,49,81,145,782}, // R ASCII 82 {398,529,529,529,486}, // S ASCII 83 {1,1,1023,1,1}, // T ASCII 84 {511,512,512,512,511}, // U ASCII 85 {31,224,768,224,31}, // V ASCII 86 {511,512,992,512,511}, // W ASCII 87 {899,108,16,108,899}, // X ASCII 88 {3,28,992,28,3}, // Y ASCII 89 {769,705,561,525,515}, // Z ASCII 90 {0,1023,513,513,0}, // [ ASCII 91 {3,14,120,448,768}, // \ ASCII 92 {0,513,513,1023,0}, // ] ASCII 93 {8,6,1,6,8}, // ^ ASCII 94 {512,512,512,512,512}, // _ ASCII 95 {0,0,7,0,0}, // ` ASCII 96 {448,548,548,548,1016}, // a ASCII 97 {1023,528,528,528,480}, // b ASCII 98 {496,520,520,520,272}, // c ASCII 99 {480,528,528,528,1023}, // d ASCII 100 {496,584,584,584,368}, // e ASCII 101 {16,1022,17,17,2}, // f ASCII 102 {312,580,580,580,504}, // g ASCII 103 {1023,32,16,16,992}, // h ASCII 104 {0,516,1021,512,0}, // i ASCII 105 {256,512,512,528,500}, // j ASCII 106 {1023,64,160,272,520}, // k ASCII 107 {0,513,1023,512,0}, // l ASCII 108 {1016,8,1016,8,1008}, // m ASCII 109 {1016,8,8,8,1008}, // n ASCII 110 {496,520,520,520,496}, // o ASCII 111 {1020,68,68,68,56}, // p ASCII 112 {56,68,68,68,1020}, // q ASCII 113 {1016,16,8,8,16}, // r ASCII 114 {304,584,584,584,400}, // s ASCII 115 {16,511,528,528,256}, // t ASCII 116 {504,512,512,256,1016}, // u ASCII 117 {56,448,512,448,56}, // v ASCII 118 {504,768,192,768,504}, // w ASCII 119 {520,432,64,432,520}, // x ASCII 120 {316,576,576,576,508}, // y ASCII 121 {776,648,584,552,536}, // z ASCII 122 {0,16,494,513,0}, // { ASCII 123 {0,0,1023,0,0}, // | ASCII 124 {0,513,494,16,0}, // } ASCII 125 }; // Arduino pin locations of LEDs in column int leds[10] = {4,5,6,7,8,9,10,11,12,13}; // Pin 3 = ISR0 = Index sensor // Pin 4 = ISR1 = Pushbutton sensor // Display resolution (number of LED columns in 1 revolution) // Note: This number should be a multiple of 6 #define displayRes 240 // Message buffer size (max number of characters from RS232) // Note: Each character + column space in the look up table is 6 columns #define msgSize displayRes/6 // 0 = Disable display scrolling, 1 = enable display scrolling #define scrollEnable 1 // Select if bitmap should read legitibly at top or bottom #define msgDispMode 1 // Variables int displayIndex = 0; int col=0; int i; int j; int scrollIndex = 0; byte msgIndex=0; unsigned long lastTime = 0; unsigned long displayColTime = 0; int charbitmap[displayRes]; char msg[msgSize]; // initial routine that runs after power on reset void setup() { // initialize the LED column pins as outputs. for(i=0; i<10; i++) { pinMode(leds[i], OUTPUT); } // Index sensor calls "indexDisplay" routine attachInterrupt(0,indexDisplay,FALLING); // Set up serial port Serial.begin(9600); // Clear the display bitmap for(j=0;j0 && checkColTime(displayIndex)) { if(displayIndex<=displayRes) { // Subtract 1 from displayIndex because after index sensor pulses // the "indexDisplay" ISR will set displayIndex to 1 and this value // is used as the bitmap array index which is 0 indexed. // displayIndex indicates which column from 1 to displayRes that // the LEDs are physically located at this given instant // scrollIndex artifically moves the column 1 location to create // a message scrolling effect when outputting column values to the LEDs if((displayIndex-1+scrollIndex)>displayRes-1) { // Message is readable at bottom, scrolls clockwise if(msgDispMode==0) { outputLedColumn(charbitmap[(displayIndex-1)+scrollIndex-displayRes],1); } // Message is readable at top, scrolls counterclockwise else { outputLedColumn(charbitmap[(displayIndex-1)+scrollIndex-displayRes],0); } } else { if(msgDispMode == 0) { outputLedColumn(charbitmap[(displayIndex-1)+scrollIndex],1); } else { outputLedColumn(charbitmap[(displayIndex-1)+scrollIndex],0); } } // Increment the displayIndex so the next iteration of this loop // the checkColTime routine will ensure the LEDs have been lit for the // proper duration of the rotation time displayIndex++; // Display bitmap will shift by 1 column on every 120th column display // Select a value smaller than 120 for faster scrolling, larger than 120 for slower if(displayIndex%120==0 and scrollEnable==1) { // Message is readable at bottom, scrolls clockwise if(msgDispMode == 0) { if(scrollIndex0) { scrollIndex--; } else { scrollIndex=(displayRes-1); } } } } else { // Entire bitmap has been displayed, turn off LEDs and // wait until next index pulse. Normally this will happen // just right before the next index pulse arrives. displayIndex=0; outputLedColumn(0,0); } } } // This ISR routine runs whenever the Index sensor pulses // When this happens, the time of the last revolution is // recorded and used for display timing in the next revolution // to make the display independent of motor speed void indexDisplay() { displayIndex = 1; // Determine column time by difference from last pulsed time. // Subtract 5us to compensate for physical size of IR LED displayColTime = (micros() - lastTime - 5)/displayRes; lastTime = micros(); } // Function to output integer value to LED array void outputLedColumn(int colValue, int bitDir) { // Currently configured for 10 LEDs for(i=0;i<10;i++) { if(bitDir == 0) { // top to bottom LED bit order digitalWrite(leds[i],bitRead(colValue,9-i)); } else { // bottom to top LED bit order digitalWrite(leds[i],bitRead(colValue,i)); } } } // Functino determines if the current LED pixel column // bas been lit long enough and returns true in that case boolean checkColTime(int colIndex){ if((micros()-lastTime)>=(displayColTime*colIndex)){ return true; } else { return false; } } // Function to ensure RS232 character is in range for // the ASCII font lookup table because there is no // array boundary checking or seg faults to stop you char serialInRange( char x ) { if(x < 32 | x > 125) { return ' '; } else { return x; } }