/** * Dual RG LED matrix (16 x 8) * * This is a demo for scrolling text on the "Dual RG matrix shield" which can be * found here: http://timewitharduino.blogspot.com/2010/02/dual-bi-color-led-matrix-shield.html */ #include #include // used to enable/disable Serial.print, time-consuming operation; // to minimize the code size, all references to Serial should be commented out; //#define _DEBUG_ 1 // display colours; #define BLACK 0 #define RED 1 #define GREEN 2 #define ORANGE 3 byte soft_prescaler = 0; byte activeRow = 0; #define CLOCK_PIN 4 #define LATCH_PIN 5 #define SER_DATA_PIN 6 // pins assigned to LED matrix rows; byte pinForRow[8] = {8, 9, 10, 11, 12, 13, 7, 3}; #define MAX_OPTION 1 // maximum number of options in the menu; #define DEFAULT_OPTION 0 #define OPTION_MESSAGE 0 #define OPTION_CLOCK 1 // general-purpose setting; particularly used to set the scrolling speed (wait); // values from 0 to 7; byte level = 1; // used to adjust the scrolling speed; // user can set it through the menu option 3; // may be also set through other means, e.g. potentiometer on analog pin (not implemented yet); byte wait = (8-level) * 30; // used to be initially set to 200; // video memory is two arrays of 16 bit integers, one per colour; volatile uint16_t screenMemR[8] = {0}; volatile uint16_t screenMemG[8] = {0}; byte sprites[][8] = { { 0x00, // ________ blank 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x00 // ________ }, { 0x00, // ________ A 0x18, // ___XX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x3C, // __XXXX__ 0x24, // __X__X__ 0x24, // __X__X_ 0x00 // ________ }, { 0x00, // ________ B 0x38, // __XXX___ 0x24, // __X__X__ 0x38, // __XXX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x38, // __XXX__ 0x00 // ________ }, { 0x00, // ________ C 0x18, // ___XX___ 0x24, // __X__X__ 0x20, // __X_____ 0x20, // __X_____ 0x24, // __X__X__ 0x18, // ___XX__ 0x00 // ________ }, { 0x00, // ________ D 0x38, // __XXX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x38, // __XXX__ 0x00 // ________ }, { 0x00, // ________ E 0x3C, // __XXXX__ 0x20, // __X_____ 0x38, // __XXX___ 0x20, // __X_____ 0x20, // __X_____ 0x3C, // __XXXX__ 0x00 // ________ }, { 0x00, // ________ F 0x3C, // __XXXX__ 0x20, // __X_____ 0x38, // __XXX___ 0x20, // __X_____ 0x20, // __X_____ 0x20, // __X_____ 0x00 // ________ }, { 0x00, // ________ G 0x1C, // ___XXX__ 0x20, // __X_____ 0x20, // __X_____ 0x2C, // __X_XX__ 0x24, // __X__X__ 0x1C, // __XXXX__ 0x00 // ________ }, { 0x00, // ________ H 0x24, // __X__X__ 0x24, // __X__X__ 0x3C, // __XXXX__ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x00 // ________ }, { 0x00, // ________ I 0x1C, // ___XXX__ 0x08, // ____X___ 0x08, // ____X___ 0x08, // ____X___ 0x08, // ____X___ 0x1C, // ___XXX__ 0x00 // ________ }, { 0x00, // ________ J 0x3C, // __XXXX__ 0x04, // _____X__ 0x04, // _____X__ 0x04, // _____X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00 // ________ }, { 0x00, // ________ K 0x24, // __X__X__ 0x28, // __X_X___ 0x30, // __XX____ 0x28, // __X_X___ 0x24, // __X__X__ 0x24, // __X__X__ 0x00, // ________ }, { 0x00, // ________ L 0x20, // __X_____ 0x20, // __X_____ 0x20, // __X_____ 0x20, // __X_____ 0x20, // __X_____ 0x3C, // __XXXX__ 0x00, // ________ }, { 0x00, // ________ M 0x22, // __X___X_ 0x36, // __XX_XX_ 0x2A, // __X_X_X_ 0x22, // __X___X_ 0x22, // __X___X_ 0x22, // __X___X_ 0x00, // ________ }, { 0x00, // ________ N 0x24, // __X__X__ 0x34, // __XX_X__ 0x2C, // __X_XX__ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x00, // ________ }, { 0x00, // ________ O 0x18, // ___XX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ P 0x38, // __XXX___ 0x24, // __X__X__ 0x38, // __XXX___ 0x20, // __X_____ 0x20, // __X_____ 0x20, // __X_____ 0x00, // ________ }, { 0x00, // ________ Q 0x18, // ___XX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x2C, // __X_XX__ 0x1A, // ___XX_X_ 0x00, // ________ }, { 0x00, // ________ R 0x38, // __XXX___ 0x24, // __X__X__ 0x38, // __XXX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x00, // ________ }, { 0x00, // ________ S 0x1C, // ___XXX__ 0x20, // __X_____ 0x18, // ___XX___ 0x04, // _____X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ T 0x3E, // __XXXXX_ 0x08, // ____X___ 0x08, // ____X___ 0x08, // ____X___ 0x08, // ____X___ 0x08, // ____X___ 0x00, // ________ }, { 0x00, // ________ U 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ V 0x22, // __X___X_ 0x22, // __X___X_ 0x22, // __X___X_ 0x14, // ___X_X__ 0x14, // ___X_X__ 0x08, // ____X___ 0x00, // ________ }, { 0x00, // ________ W 0x22, // __X___X_ 0x22, // __X___X_ 0x22, // __X___X_ 0x2A, // __X_X_X_ 0x2A, // __X_X_X_ 0x14, // ___X_X__ 0x00, // ________ }, { 0x00, // ________ X 0x24, // __X__X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x18, // ___XX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x00, // ________ }, { 0x00, // ________ Y 0x22, // __X___X_ 0x22, // __X___X_ 0x14, // ___X_X__ 0x08, // ____X___ 0x08, // ____X___ 0x08, // ____X___ 0x00, // ________ }, { 0x00, // ________ Z 0x3E, // __XXXXX_ 0x24, // __X__X__ 0x08, // ____X___ 0x10, // ___X____ 0x22, // __X___X_ 0x3E, // __XXXXX_ 0x00, // ________ }, { // index 27 0x00, // ________ 0 0x18, // ___XX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ 1 0x08, // ____X___ 0x18, // ___XX___ 0x28, // __X_X___ 0x08, // ____X___ 0x08, // ____X___ 0x1C, // ___XXX__ 0x00, // ________ }, { 0x00, // ________ 2 0x18, // ___XX___ 0x24, // __X__X__ 0x08, // ____X___ 0x10, // ___X____ 0x20, // __X_____ 0x3C, // __XXXX__ 0x00, // ________ }, { 0x00, // ________ 3 0x3C, // __XXXX__ 0x04, // _____X__ 0x18, // ___XX___ 0x04, // _____X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ 4 0x04, // _____X__ 0x0C, // ____XX__ 0x14, // ___X_X__ 0x3C, // __XXXX__ 0x04, // _____X__ 0x04, // _____X__ 0x00, // ________ }, { 0x00, // ________ 5 0x3C, // __XXXX__ 0x20, // __X_____ 0x38, // __XXX___ 0x04, // _____X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ 6 0x18, // ___XX___ 0x20, // __X_____ 0x38, // __XXX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ 7 0x3C, // __XXXX__ 0x04, // _____X__ 0x08, // ____X__ 0x10, // ___X___ 0x10, // ___X____ 0x10, // ___X____ 0x00, // ________ }, { 0x00, // ________ 8 0x18, // ___XX___ 0x24, // __X__X__ 0x18, // ___XX___ 0x24, // __X__X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ 9 0x18, // ___XX___ 0x24, // __X__X__ 0x1C, // ___XXX__ 0x04, // _____X__ 0x24, // __X__X__ 0x18, // ___XX___ 0x00, // ________ }, { 0x00, // ________ . 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x30, // __XX____ 0x30, // __XX____ 0x00, // ________ }, { 0x00, // ________ , 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x00, // ________ 0x30, // __XX____ 0x10, // ___X____ 0x20, // __X_____ }, { 0x00, // ________ ! 0x10, // ___X____ 0x10, // ___X____ 0x10, // ___X____ 0x10, // ___X____ 0x00, // ________ 0x10, // ___X____ 0x10, // ________ }, { // index 40 0x00, // ________ : 0x00, // ________ 0x18, // ___XX___ 0x18, // ___XX___ 0x00, // ________ 0x18, // ___XX___ 0x18, // ___XX___ 0x00, // ________ }, }; char msgBuffer[] = " 1. A ROBOT MAY NOT INJURE A HUMAN BEING OR, THROUGH INACTION, ALLOW A HUMAN BEING TO COME TO HARM. 2. A ROBOT MUST OBEY ORDERS GIVEN TO IT BY HUMAN BEINGS EXCEPT WHERE SUCH ORDERS WOULD CONFLICT WITH THE FIRST LAW. 3. A ROBOT MUST PROTECT ITS OWN EXISTENCE AS LONG AS SUCH PROTECTION DOES NOT CONFLICT WITH THE FIRST OR SECOND LAW. "; byte msgBufferPos = 0; byte msgBufferSize = 0; // this is the screen memory; it stores 4 chars (ascii rather than sprites); byte char1 = 0; byte char2 = 0; byte char3 = 0; byte char4 = 0; byte char5 = 0; void setup() { // Calculation for timer 2 // 16 MHz / 8 = 2 MHz (prescaler 8) // 2 MHz / 256 = 7812 Hz // soft_prescaler = 15 ==> 520.8 updates per second // 520.8 / 8 rows ==> 65.1 Hz for the complete display TCCR2A = 0; // normal operation TCCR2B = (1<> 8; byte redLo = screenMemR[activeRow] & 0xFF; byte greenHi = screenMemG[activeRow] >> 8; byte greenLo = screenMemG[activeRow] & 0xFF; shiftOutRow(redHi, greenHi, redLo, greenLo); // switch to new row; digitalWrite(pinForRow[activeRow], HIGH); } void shiftOutRow(byte redHi, byte greenHi, byte redLo, byte greenLo) { digitalWrite(LATCH_PIN, LOW); shiftOut(SER_DATA_PIN, CLOCK_PIN, LSBFIRST, greenHi); shiftOut(SER_DATA_PIN, CLOCK_PIN, LSBFIRST, redHi); shiftOut(SER_DATA_PIN, CLOCK_PIN, LSBFIRST, greenLo); shiftOut(SER_DATA_PIN, CLOCK_PIN, LSBFIRST, redLo); // return the latch pin high to signal chip that it // no longer needs to listen for information digitalWrite(LATCH_PIN, HIGH); } void resetDisplay() { for (byte i = 0; i < 8; i++) screenMemR[i] = 0; for (byte i = 0; i < 8; i++) screenMemG[i] = 0; char1 = 0; char2 = 0; char3 = 0; char4 = 0; char5 = 0; // reset the buffer pointers; msgBufferPos = 0; } void loop() { #ifdef _DEBUG_ Serial.print("loop char="); Serial.println(msgBuffer[msgBufferPos]); #endif displayAndScroll(msgBuffer[msgBufferPos]); msgBufferPos++; if (msgBufferPos >= msgBufferSize) msgBufferPos = 0; } void displayAndScroll(char crtChar) { #ifdef _DEBUG_ Serial.print("crtChar="); Serial.println(crtChar); #endif switch (crtChar) { case ' ': char1 = char2; char2 = char3; char3 = char4; char4 = 0; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': char1 = char2; char2 = char3; char3 = char4; char4 = crtChar - 'A' + 1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': char1 = char2; char2 = char3; char3 = char4; char4 = crtChar - '0' + 27; break; case '.': // definition of the bitmaps for digits start at index 37; char1 = char2; char2 = char3; char3 = char4; char4 = 37; // dot has index 37 in the character definition array; break; case ',': char1 = char2; char2 = char3; char3 = char4; char4 = 38; // comma has index 38 in the character definition array; break; case '!': char1 = char2; char2 = char3; char3 = char4; char4 = 39; // exclamation has index 39 in the character definition array; break; case ':': char1 = char2; char2 = char3; char3 = char4; char4 = 40; // colon has index 40 in the character definition array; break; } setScreenMem(ORANGE, sprites[char1], sprites[char2], sprites[char3], sprites[char4]); } void setScreenMem(byte color, byte sprite1[8], byte sprite2[8], byte sprite3[8], byte sprite4[8]) { unsigned long row[16] = {0}; // for each row; for (byte i = 0; i < 8; i++) { byte c1 = sprite1[i] >> 1; byte c2 = sprite2[i] >> 1; byte c3 = sprite3[i] >> 1; byte c4 = sprite4[i] >> 1; row[i] = ((((((unsigned long) c1 << 5) + c2) << 5) + c3) << 5) + c4; #ifdef _DEBUG_ Serial.print(c1, DEC); Serial.print(", "); Serial.print(c2, DEC); Serial.print(", "); Serial.print(c3, DEC); Serial.print(", "); Serial.print(c4, DEC); Serial.print(", "); Serial.println(row[i]); #endif } // scroll 5 times to the left (5 being the width of a char, as defined); for (byte x = 1; x <= 5; x++) { // for each row; for (byte i = 0; i < 8; i++) { switch (color) { case RED: screenMemR[i] = row[i] >> (5-x); break; case GREEN: screenMemG[i] = row[i] >> (5-x); break; case ORANGE: screenMemR[i] = row[i] >> (5-x); screenMemG[i] = row[i] >> (5-x); break; } } delay(wait); } } // statically displays the given character/sprite; // used to display the menu option (number); void setScreenMem(byte color, byte sprite[8]) { uint16_t row; for (byte i = 0; i < 8; i++) { row = sprite[i]; if ((color & RED) == RED) screenMemR[i] = row; if ((color & GREEN) == GREEN) screenMemG[i] = row; } }