//////////////////////////
// By Mohamed Elgeweily V2
//////////////////////////
#define enablePin 8
#define latchPin 9
#define clockPin 10
#define dataPin_R 11
#define dataPin_G 12
#define dataPin_B 13
const char selectColor[] = "R"; // select color, either "R", "G", "B", "RG", "RB", "GB", "RGB"
const char textToDraw[] = "T.A.T.W.E.E.R";
// define each letter columns from left to right, letter top is the MSB
const byte emptyLetter[] = {
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000
};
const byte letterA[] = {
B01111111,
B10010000,
B10010000,
B10010000,
B10010000,
B10010000,
B01111111,
B00000000
};
const byte letterB[] = {
B11111111,
B10010001,
B10010001,
B10010001,
B10010001,
B10010001,
B01101110,
B00000000
};
const byte letterC[] = {
B01111110,
B10000001,
B10000001,
B10000001,
B10000001,
B10000001,
B10000001,
B00000000
};
const byte letterD[] = {
B11111111,
B10000001,
B10000001,
B10000001,
B10000001,
B01000010,
B00111100,
B00000000
};
const byte letterE[] = {
B11111111,
B10010001,
B10010001,
B10010001,
B10010001,
B10010001,
B10010001,
B00000000
};
const byte letterF[] = {
B11111111,
B10010000,
B10010000,
B10010000,
B10010000,
B10010000,
B10010000,
B00000000
};
const byte letterG[] = {
B11111111,
B10000001,
B10000001,
B10000001,
B10001001,
B10001001,
B10001111,
B00000000
};
const byte letterH[] = {
B11111111,
B00010000,
B00010000,
B00010000,
B00010000,
B00010000,
B11111111,
B00000000
};
const byte letterI[] = {
B10000001,
B10000001,
B10000001,
B11111111,
B10000001,
B10000001,
B10000001,
B00000000
};
const byte letterJ[] = {
B00001111,
B00000001,
B00000001,
B00000001,
B00000001,
B00000001,
B11111111,
B00000000
};
const byte letterK[] = {
B11111111,
B00011000,
B00100100,
B01000010,
B10000001,
B10000001,
B10000001,
B00000000
};
const byte letterL[] = {
B11111111,
B00000001,
B00000001,
B00000001,
B00000001,
B00000001,
B00000001,
B00000000
};
const byte letterM[] = {
B11111111,
B01000000,
B00100000,
B00010000,
B00100000,
B01000000,
B11111111,
B00000000
};
const byte letterN[] = {
B11111111,
B01000000,
B00100000,
B00011000,
B00000100,
B00000010,
B11111111,
B00000000
};
const byte letterO[] = {
B01111110,
B10000001,
B10000001,
B10000001,
B10000001,
B10000001,
B01111110,
B00000000
};
const byte letterP[] = {
B11111111,
B10010000,
B10010000,
B10010000,
B10010000,
B10010000,
B01100000,
B00000000
};
const byte letterQ[] = {
B01111110,
B10000001,
B10000001,
B10001001,
B10000101,
B10000010,
B01111101,
B00000000
};
const byte letterR[] = {
B11111111,
B10010000,
B10010000,
B10011000,
B10010100,
B10010010,
B11110001,
B00000000
};
const byte letterS[] = {
B01110001,
B10010001,
B10010001,
B10010001,
B10010001,
B10010001,
B10011110,
B00000000
};
const byte letterT[] = {
B10000000,
B10000000,
B10000000,
B11111111,
B10000000,
B10000000,
B10000000,
B00000000
};
const byte letterU[] = {
B11111110,
B00000001,
B00000001,
B00000001,
B00000001,
B00000001,
B11111110,
B00000000
};
const byte letterV[] = {
B11111000,
B00000100,
B00000010,
B00000001,
B00000010,
B00000100,
B11111000,
B00000000
};
const byte letterW[] = {
B11111111,
B00000001,
B00000010,
B00000100,
B00000010,
B00000001,
B11111111,
B00000000
};
const byte letterX[] = {
B10000001,
B01000010,
B00100100,
B00011000,
B00100100,
B01000010,
B10000001,
B00000000
};
const byte letterY[] = {
B11000000,
B00100000,
B00010000,
B00001111,
B00010000,
B00100000,
B11000000,
B00000000
};
const byte letterZ[] = {
B10000011,
B10000011,
B10000101,
B10011001,
B10100001,
B11000001,
B11000001,
B00000000
};
void setup() {
pinMode(enablePin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin_R, OUTPUT);
pinMode(dataPin_B, OUTPUT);
pinMode(dataPin_G, OUTPUT);
digitalWrite(enablePin, LOW); // matrix enabled all the time for testing purpose
digitalWrite(latchPin, LOW); // latch requires rising edge
}
void loop() {
drawSlidingText(textToDraw, selectColor);
}
void shiftOutRGB(byte Pin_R, byte Pin_G, byte Pin_B, byte clkPin, byte bitOrder, byte val_R, byte val_G, byte val_B) {
for (byte i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST) {
digitalWrite(Pin_R, !! (val_R & (1 << i)));
digitalWrite(Pin_G, !! (val_G & (1 << i)));
digitalWrite(Pin_B, !! (val_B & (1 << i)));
}
else {
digitalWrite(Pin_R, !! (val_R & (1 << (7 - i))));
digitalWrite(Pin_G, !! (val_G & (1 << (7 - i))));
digitalWrite(Pin_B, !! (val_B & (1 << (7 - i))));
}
digitalWrite(clkPin, HIGH);
digitalWrite(clkPin, LOW);
}
}
void drawFrame(int rows_R[8], int rows_G[8], int rows_B[8]) {
for (byte i = 0; i < 8; i++) { // 1 iteration for each row
shiftOutRGB(dataPin_R, dataPin_G, dataPin_B, clockPin, MSBFIRST, rows_R[i] >> 8, rows_G[i] >> 8, rows_B[i] >> 8); // draw higher byte
shiftOutRGB(dataPin_R, dataPin_G, dataPin_B, clockPin, MSBFIRST, rows_R[i], rows_G[i], rows_B[i]); // draw lower byte
}
// latch data to LED drivers
digitalWrite(latchPin, HIGH);
digitalWrite(latchPin, LOW); // latching requires only a rising edge
}
byte getColumnFromLetter(char letter, byte colIndex) {
// return a specific column from a specific letter
switch (letter) {
case 'A':
return letterA[colIndex];
case 'B':
return letterB[colIndex];
case 'C':
return letterC[colIndex];
case 'D':
return letterD[colIndex];
case 'E':
return letterE[colIndex];
case 'F':
return letterF[colIndex];
case 'G':
return letterG[colIndex];
case 'H':
return letterH[colIndex];
case 'I':
return letterI[colIndex];
case 'J':
return letterJ[colIndex];
case 'K':
return letterK[colIndex];
case 'L':
return letterL[colIndex];
case 'M':
return letterM[colIndex];
case 'N':
return letterN[colIndex];
case 'O':
return letterO[colIndex];
case 'P':
return letterP[colIndex];
case 'Q':
return letterQ[colIndex];
case 'R':
return letterR[colIndex];
case 'S':
return letterS[colIndex];
case 'T':
return letterT[colIndex];
case 'U':
return letterU[colIndex];
case 'V':
return letterV[colIndex];
case 'W':
return letterW[colIndex];
case 'X':
return letterX[colIndex];
case 'Y':
return letterY[colIndex];
case 'Z':
return letterZ[colIndex];
case '.':
return emptyLetter[colIndex];
default:
return 0;
}
}
void drawSlidingText(const char* text, const char* color_s) {
byte textLength = strlen(text);
byte newTextLength = textLength + 4; // will add 2 empty letters at start and 2 empty letters at end (empty letter is represented by '.')
const char newText[newTextLength];
strcpy(newText, "..");
strcat(newText, text);
strcat(newText, "..");
int frameBuffer[8]; // will hold full frame
int zeroes[8] = {0}; // will be used to turn off unselected colors
int* frameBuffer_R = zeroes;
int* frameBuffer_G = zeroes;
int* frameBuffer_B = zeroes;
if (strcmp(color_s, "R") == 0) {
frameBuffer_R = frameBuffer;
}
else if (strcmp(color_s, "G") == 0) {
frameBuffer_G = frameBuffer;
}
else if (strcmp(color_s, "B") == 0) {
frameBuffer_B = frameBuffer;
}
else if (strcmp(color_s, "RG") == 0) {
frameBuffer_R = frameBuffer;
frameBuffer_G = frameBuffer;
}
else if (strcmp(color_s, "RB") == 0) {
frameBuffer_R = frameBuffer;
frameBuffer_B = frameBuffer;
}
else if (strcmp(color_s, "GB") == 0) {
frameBuffer_G = frameBuffer;
frameBuffer_B = frameBuffer;
}
else { // RGB case
frameBuffer_R = frameBuffer;
frameBuffer_G = frameBuffer;
frameBuffer_B = frameBuffer;
}
for (byte colOffset = 0; colOffset < (newTextLength * 8); colOffset++) {
memset(frameBuffer, 0, sizeof(frameBuffer)); // erase frameBuffer for each new frame
byte letterIndex = colOffset / 8;
byte letterOffset = colOffset % 8;
for (byte col = 0; col < 16; col++) {
if (letterOffset == 8 && letterIndex < newTextLength - 1) { //finished the current letter and there is still remaining letter(s), go to next letter
letterIndex++;
letterOffset = 0;
}
else if (letterOffset == 8 && letterIndex == newTextLength - 1) { // finished the current letter and there are no more letters
break;
}
byte currentColumn = getColumnFromLetter(newText[letterIndex], letterOffset++);
// write current column to frame buffer
for (byte row = 0; row < 16; row++) {
if (bitRead(currentColumn, row)) {
bitSet(frameBuffer[row], col);
}
}
}
drawFrame(frameBuffer_R, frameBuffer_G, frameBuffer_B);
delay(100);
}
}