Sunday, December 5, 2021

LED Matrix 8x8

Require components:

  • 1x Arduino Uno
  • 8x 1000ohm Resistor
  • 2x SN74HC595N
  • Wires


Tools help you change code show LEDs:

https://zxcongducxz.000webhostapp.com/arduino/LEDMatrix8x8.html


Video:




1. Code test all LEDs from top to bottom, from left to right:

const byte BIT_ORDER = MSBFIRST;    // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;     // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;        // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;     // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = {8137110614};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte TOTAL_ROWS = sizeof(BIT_ROWS);                     // total row pins
const byte BIT_COLUMNS[] = {122395101415};      // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
const byte TOTAL_COLUMNS = sizeof(BIT_COLUMNS);               // total column pins

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
}

unsigned short markColumn(byte indexColumnOn) {  // column is cathod, set indexColumnOn value to 0 to LED on, other columns value to 1 to LED off
  unsigned short dataColumn = 0;
  for(byte indexColumn = 0; indexColumn < TOTAL_COLUMNS; indexColumn++) {
    if(indexColumn != indexColumnOn) { // set all toher cathod column value to 1 (LED off)
      dataColumn |= 1 << BIT_COLUMNS[indexColumn];
    }
  }
  return dataColumn;
}

unsigned short markRow(byte indexRowOn) { // row is anode, set current row value to 1 to LED on, other rows value to 0 to LED off
  unsigned short dataRow = 0;
  return dataRow | (1 << BIT_ROWS[indexRowOn]);
}

void loop() { // turn on 1 LED, from left to right, from top to bottom
  for(byte indexRow = 0; indexRow < TOTAL_ROWS; indexRow++) { // each row from top to bottom
    unsigned short dataRow = markRow(indexRow);
    
    for(byte indexColumn = 0; indexColumn < TOTAL_COLUMNS; indexColumn++) { // each column from left to right
      unsigned short dataColumn = markColumn(indexColumn); 
    
      unsigned short dataLED = dataRow | dataColumn; // combine column & row
      digitalWrite(PIN_LATCH_ST_CP, LOW); // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
      shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8); // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
      shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED); // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
      digitalWrite(PIN_LATCH_ST_CP, HIGH); // return the latch pin high to signal chip that it no longer needs to listen for information

      delay(100); // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
    }
  }  
}



2. Code test all rows:

const byte BIT_ORDER = MSBFIRST;    // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;     // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;        // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;     // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = {8137110614};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte TOTAL_ROWS = sizeof(BIT_ROWS);                     // total row pins
const byte BIT_COLUMNS[] = {122395101415};      // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
const byte TOTAL_COLUMNS = sizeof(BIT_COLUMNS);               // total column pins

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
}

void loop() {
  for(byte indexRow = 0; indexRow < TOTAL_ROWS; indexRow++) { // each row from top to bottom
    // there are 16 bits, turn on current row by set row value to 1, all columns values to 0
    unsigned short dataLED = 0 | (1 << BIT_ROWS[indexRow]);

    digitalWrite(PIN_LATCH_ST_CP, LOW); // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8); // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED); // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    digitalWrite(PIN_LATCH_ST_CP, HIGH); // return the latch pin high to signal chip that it no longer needs to listen for information

    delay(500); // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
  } 
}


Code test all columns:

const byte BIT_ORDER = MSBFIRST;    // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;     // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;        // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;     // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = {8137110614};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte TOTAL_ROWS = sizeof(BIT_ROWS);                     // total row pins
const byte BIT_COLUMNS[] = {122395101415};      // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
const byte TOTAL_COLUMNS = sizeof(BIT_COLUMNS);               // total column pins

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
}

void loop() {
  for(byte indexColumn = 0; indexColumn < TOTAL_COLUMNS; indexColumn++) { // each row from top to bottom
    // there are 16 bits used for 16 pins.
    // all index bit of rows are on = 8 bits (row anode value = 1)
    // 1 index bit of column are on (column anode value = 0), 7 other columns are off (value = 1)
    // so there is 1 bit value = 0, all bits are 16 = decimal: 65535, xor current index column let it's value to 0;
    unsigned short dataLED = 65535 ^ (1 << BIT_COLUMNS[indexColumn]);

    digitalWrite(PIN_LATCH_ST_CP, LOW); // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8); // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED); // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    digitalWrite(PIN_LATCH_ST_CP, HIGH); // return the latch pin high to signal chip that it no longer needs to listen for information

    delay(500); // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
  } 
}


3. Code display human animation 8x8:

const byte BIT_ORDER = MSBFIRST;    // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;     // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;        // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;     // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = {8137110614};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {122395101415};      // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
unsigned short DURATION_COLUMN = 2;                          // value too high make you see LED blink, should <=3 is OK

unsigned short DURATION_FRAME = 500;
byte ANIMATION1_DATA[] = {
  16,144,87,61,87,144,16,0,8,144,87,61,87,144,8,0,0,152,87,61,87,152,0,0,8,136,87,61,87,136,8,0,4,136,87,61,87,136,4,0,0,140,87,61,87,140,0,0,
  0,140,87,61,87,140,0,0,4,136,87,61,87,136,4,0,8,136,87,61,87,136,8,0,0,152,87,61,87,152,0,0,8,144,87,61,87,144,8,0,16,144,87,61,87,144,16,0,
};

byte indexColumnDisplaying = 0; // store current index column for avoid column on the right display less than column on the left

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
}

unsigned short convertByteColumnTo16Bit(byte byteColumnbyte indexColumnTurnOn) {
  unsigned short dataLED = 0;

  // row is anode, set indexBit of row value to 1 to LED on, value 0 to LED off
  for (byte indexBit = 0; indexBit < 8; indexBit++) {
    bool isOn = byteColumn & (1 << indexBit);
    if (isOn) {
      dataLED |= 1 << BIT_ROWS[indexBit]; 
    }
  }

  // column is cathod, set column value to 0 to LED on, value 1 to LED off, code below mark all other columns off
  for(byte indexColumn = 0; indexColumn < sizeof(BIT_COLUMNS); indexColumn++){
    bool isOn = indexColumn == indexColumnTurnOn;
    if (!isOn) {
      dataLED |= 1 << BIT_COLUMNS[indexColumn]; 
    }    
  }
  
  return dataLED;
}

void display8x8(byte bytesAnimation[], int offsetColumnunsigned short durationFrame) {
  while(durationFrame >= DURATION_COLUMN) {
    byte byteDisplay = bytesAnimation[offsetColumn + indexColumnDisplaying];
    unsigned short dataLED = convertByteColumnTo16Bit(byteDisplay, indexColumnDisplaying);

    digitalWrite(PIN_LATCH_ST_CP, LOW); // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8); // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED); // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    digitalWrite(PIN_LATCH_ST_CP, HIGH); // return the latch pin high to signal chip that it no longer needs to listen for information

    delay(DURATION_COLUMN); // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
    durationFrame -= DURATION_COLUMN;
    indexColumnDisplaying = (indexColumnDisplaying + 1) % sizeof(BIT_COLUMNS);
  }
}

void animationDisplayFrameByFrame(unsigned short durationFramebyte bytesAnimation[], size_t totalColumns) {
  for(byte offsetColumn = 0; offsetColumn < totalColumns; offsetColumn+=sizeof(BIT_COLUMNS)) {
    display8x8(bytesAnimation, offsetColumn, durationFrame);
  }
}

void loop() {
  animationDisplayFrameByFrame(DURATION_FRAME, ANIMATION1_DATA, sizeof(ANIMATION1_DATA));
}


4. Code run animation text from left to right

const byte BIT_ORDER = MSBFIRST;    // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;     // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;        // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;     // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = {8137110614};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {122395101415};      // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
unsigned short DURATION_COLUMN = 2;                          // value too high make you see LED blink, should <=3 is OK

unsigned short DURATION_FRAME = 100;
byte ANIMATION1_DATA[] = {
  62,81,73,69,62,0,68,66,127,64,64,0,98,81,73,73,70,0,34,65,73,73,54,0,24,20,18,127,16,0,39,69,69,69,57,0,62,73,73,73,50,0,1,113,9,5,3,0,54,73,73,73,54,0,38,73,73,73,62
};

byte indexColumnDisplaying = 0; // store current index column for avoid column on the right display less than column on the left

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
}

unsigned short convertByteColumnTo16Bit(byte byteColumnbyte indexColumnTurnOn) {
  unsigned short dataLED = 0;

  // row is anode, set indexBit of row value to 1 to LED on, value 0 to LED off
  for (byte indexBit = 0; indexBit < 8; indexBit++) {
    bool isOn = byteColumn & (1 << indexBit);
    if (isOn) {
      dataLED |= 1 << BIT_ROWS[indexBit]; 
    }
  }

  // column is cathod, set column value to 0 to LED on, value 1 to LED off, code below mark all other columns off
  for(byte indexColumn = 0; indexColumn < sizeof(BIT_COLUMNS); indexColumn++){
    bool isOn = indexColumn == indexColumnTurnOn;
    if (!isOn) {
      dataLED |= 1 << BIT_COLUMNS[indexColumn]; 
    }    
  }
  
  return dataLED;
}

void display8x8(byte bytesAnimation[], size_t totalColumnsint offsetColumnunsigned short durationFrame) {
  while(durationFrame >= DURATION_COLUMN) {
    byte byteDisplay = bytesAnimation[(offsetColumn + indexColumnDisplaying) % totalColumns];
    unsigned short dataLED = convertByteColumnTo16Bit(byteDisplay, indexColumnDisplaying);

    digitalWrite(PIN_LATCH_ST_CP, LOW); // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8); // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED); // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    digitalWrite(PIN_LATCH_ST_CP, HIGH); // return the latch pin high to signal chip that it no longer needs to listen for information

    delay(DURATION_COLUMN); // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
    durationFrame -= DURATION_COLUMN;
    indexColumnDisplaying = (indexColumnDisplaying + 1) % sizeof(BIT_COLUMNS);
  }
}

void animationLeftToRight(unsigned short durationFramebyte bytesAnimation[], size_t totalColumns) {
  for(byte offsetColumn = 0; offsetColumn < totalColumns; offsetColumn++) {
    display8x8(bytesAnimation, totalColumns, offsetColumn, durationFrame);
  }
}

void loop() {
  animationLeftToRight(DURATION_FRAME, ANIMATION1_DATA, sizeof(ANIMATION1_DATA));
}



5. Code run animation text from right to left

const byte BIT_ORDER = MSBFIRST;    // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;     // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;        // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;     // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = {8137110614};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {122395101415};      // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
unsigned short DURATION_COLUMN = 2;                          // value too high make you see LED blink, should <=3 is OK

unsigned short DURATION_FRAME = 100;
byte ANIMATION1_DATA[] = {
  62,81,73,69,62,0,68,66,127,64,64,0,98,81,73,73,70,0,34,65,73,73,54,0,24,20,18,127,16,0,39,69,69,69,57,0,62,73,73,73,50,0,1,113,9,5,3,0,54,73,73,73,54,0,38,73,73,73,62
};

byte indexColumnDisplaying = 0; // store current index column for avoid column on the right display less than column on the left

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
}

unsigned short convertByteColumnTo16Bit(byte byteColumnbyte indexColumnTurnOn) {
  unsigned short dataLED = 0;

  // row is anode, set indexBit of row value to 1 to LED on, value 0 to LED off
  for (byte indexBit = 0; indexBit < 8; indexBit++) {
    bool isOn = byteColumn & (1 << indexBit);
    if (isOn) {
      dataLED |= 1 << BIT_ROWS[indexBit]; 
    }
  }

  // column is cathod, set column value to 0 to LED on, value 1 to LED off, code below mark all other columns off
  for(byte indexColumn = 0; indexColumn < sizeof(BIT_COLUMNS); indexColumn++){
    bool isOn = indexColumn == indexColumnTurnOn;
    if (!isOn) {
      dataLED |= 1 << BIT_COLUMNS[indexColumn]; 
    }    
  }
  
  return dataLED;
}

void display8x8(byte bytesAnimation[], size_t totalColumnsint offsetColumnunsigned short durationFrame) {
  while(durationFrame >= DURATION_COLUMN) {
    byte byteDisplay = bytesAnimation[(totalColumns - offsetColumn + indexColumnDisplaying) % totalColumns];
    unsigned short dataLED = convertByteColumnTo16Bit(byteDisplay, indexColumnDisplaying);

    digitalWrite(PIN_LATCH_ST_CP, LOW); // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8); // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED); // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    digitalWrite(PIN_LATCH_ST_CP, HIGH); // return the latch pin high to signal chip that it no longer needs to listen for information

    delay(DURATION_COLUMN); // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
    durationFrame -= DURATION_COLUMN;
    indexColumnDisplaying = (indexColumnDisplaying + 1) % sizeof(BIT_COLUMNS);
  }
}

void animationLeftToRight(unsigned short durationFramebyte bytesAnimation[], size_t totalColumns) {
  for(byte offsetColumn = 0; offsetColumn < totalColumns; offsetColumn++) {
    display8x8(bytesAnimation, totalColumns, offsetColumn, durationFrame);
  }
}

void loop() {
  animationLeftToRight(DURATION_FRAME, ANIMATION1_DATA, sizeof(ANIMATION1_DATA));
}


6. Code animation clock 2 lines:

const byte BIT_ORDER = MSBFIRST;  // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;   // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;      // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;   // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = { 8137110614 };       // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = { 122395101415 };  // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
const unsigned short DURATION_COLUMN = 2;                   // value too high make you see LED blink, should <=3 is OK
const unsigned short DURATION_MINUTE = 50;                   // default is 1000ms * 60s = 60 000ms, value current testing
const unsigned short TOTAL_MINUTES = 12 * 60;               // total minutes in 
const unsigned short START_MINUTES = 0;                     // value of minutes when start project, range from 0 to TOTAL_MINUTES

byte HOURS[12][8] = {
  {000012000},
  {00008400},
  {00008800},
  {0000161600},
  {0000163200},
  {000048000},
  {000480000},
  {0032160000},
  {0016160000},
  {00880000},
  {00480000},
  {000120000}
};
byte MINUTES[60][8] = {
  {000015000},
  {000014100},
  {000012300},
  {00008700},
  {00008610},
  {00008430},
  {00008421},
  {00008422},
  {00008442},
  {00008444},
  {00008844},
  {00008884},
  {00008888},
  {0000161688},
  {00001616168},
  {000016161616},
  {000016161632},
  {000016163232},
  {000016323232},
  {000016323264},
  {000016326464},
  {0000163264128},
  {000016321920},
  {000016961280},
  {00001622400},
  {00004819200},
  {000011212800},
  {0000240000},
  {00048192000},
  {000112128000},
  {0002400000},
  {001281120000},
  {00192480000},
  {00224160000},
  {012896160000},
  {019232160000},
  {1286432160000},
  {646432160000},
  {643232160000},
  {323232160000},
  {323216160000},
  {321616160000},
  {161616160000},
  {1616880000},
  {168880000},
  {88880000},
  {48880000},
  {44880000},
  {44480000},
  {24480000},
  {22480000},
  {12480000},
  {03480000},
  {01680000},
  {00780000},
  {003120000},
  {001140000},
  {000150000},
  {000312000},
  {000114000}
};
byte indexColumnDisplaying = 0;  // store current index column for avoid column on the right display less than column on the left

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
  Serial.begin(9600);
}

unsigned short convertByteColumnTo16Bit(byte byteColumnbyte indexColumnTurnOn) {
  unsigned short dataLED = 0;

  // row is anode, set indexBit of row value to 1 to LED on, value 0 to LED off
  for (byte indexBit = 0; indexBit < 8; indexBit++) {
    bool isOn = byteColumn & (1 << indexBit);
    if (isOn) {
      dataLED |= 1 << BIT_ROWS[indexBit];
    }
  }

  // column is cathod, set column value to 0 to LED on, value 1 to LED off, code below mark all other columns off
  for (byte indexColumn = 0; indexColumn < sizeof(BIT_COLUMNS); indexColumn++) {
    bool isOn = indexColumn == indexColumnTurnOn;
    if (!isOn) {
      dataLED |= 1 << BIT_COLUMNS[indexColumn];
    }
  }

  return dataLED;
}

void display8x8(byte bytesDisplay[]) {
  unsigned short duration = DURATION_MINUTE;
  while (duration >= DURATION_COLUMN) {
    byte byteDisplay = bytesDisplay[indexColumnDisplaying];
    unsigned short dataLED = convertByteColumnTo16Bit(byteDisplay, indexColumnDisplaying);

    digitalWrite(PIN_LATCH_ST_CP, LOW);                              // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8);  // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED);       // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    digitalWrite(PIN_LATCH_ST_CP, HIGH);                             // return the latch pin high to signal chip that it no longer needs to listen for information

    delay(DURATION_COLUMN);  // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
    duration -= DURATION_COLUMN;
    indexColumnDisplaying = (indexColumnDisplaying + 1) % sizeof(BIT_COLUMNS);
  }
}

void drawClock(unsigned short totalMinutes) {
  Serial.print("totalMinutes=");
  Serial.print(totalMinutes);
  byte indexHour = totalMinutes / 60;
  byte indexMinute = totalMinutes % 60;
  Serial.print(", indexHour=");
  Serial.print(indexHour);
  Serial.print(", indexMinute=");
  Serial.print(indexMinute);
  byte bytesDisplay[sizeof(BIT_COLUMNS)];
  for(byte indexColumn=0; indexColumn < sizeof(BIT_COLUMNS); indexColumn++){
    bytesDisplay[indexColumn] = HOURS[indexHour][indexColumn] | MINUTES[indexMinute][indexColumn]; // combine data from HOURS & MINUTES
  }
  display8x8(bytesDisplay);

  Serial.println(" ");
  unsigned short nextMinute = (totalMinutes+1) % TOTAL_MINUTES;
  drawClock(nextMinute);
}

void loop() {
  drawClock(START_MINUTES);
}

replace value below to display hour as dot

byte HOURS[12][8] = {
  {00001000},
  {00000010},
  {00000002},
  {000000016},
  {000000064},
  {0000001280},
  {0001280000},
  {0128000000},
  {640000000},
  {160000000},
  {20000000},
  {01000000}
};


replace value below to change clock display text

byte HOURS[24][8] = {
  {159150159150},
  {15915091580},
  {1591501311110},
  {159150911150},
  {15915032150},
  {1591501111130},
  {1591501510140},
  {15915011150},
  {1591501411150},
  {15915075150},
  {91580159150},
  {9158091580},
  {915801311110},
  {91580911150},
  {9158032150},
  {915801111130},
  {915801510140},
  {9158011150},
  {915801411150},
  {9158075150},
  {1311110159150},
  {131111091580},
  {13111101311110},
  {1311110911150}
};
byte MINUTES[60][8] = {
  {02401442400240144240},
  {02401442400144240128},
  {02401442400208176176},
  {02401442400144176240},
  {024014424004832240},
  {02401442400176176208},
  {02401442400240160224},
  {024014424001616240},
  {02401442400224176240},
  {0240144240011280240},
  {01442401280240144240},
  {01442401280144240128},
  {01442401280208176176},
  {01442401280144176240},
  {014424012804832240},
  {01442401280176176208},
  {01442401280240160224},
  {014424012801616240},
  {01442401280224176240},
  {0144240128011280240},
  {02081761760240144240},
  {02081761760144240128},
  {02081761760208176176},
  {02081761760144176240},
  {020817617604832240},
  {02081761760176176208},
  {02081761760240160224},
  {020817617601616240},
  {02081761760224176240},
  {0208176176011280240},
  {01441762400240144240},
  {01441762400144240128},
  {01441762400208176176},
  {01441762400144176240},
  {014417624004832240},
  {01441762400176176208},
  {01441762400240160224},
  {014417624001616240},
  {01441762400224176240},
  {0144176240011280240},
  {048322400240144240},
  {048322400144240128},
  {048322400208176176},
  {048322400144176240},
  {0483224004832240},
  {048322400176176208},
  {048322400240160224},
  {0483224001616240},
  {048322400224176240},
  {04832240011280240},
  {01761762080240144240},
  {01761762080144240128},
  {01761762080208176176},
  {01761762080144176240},
  {017617620804832240},
  {01761762080176176208},
  {01761762080240160224},
  {017617620801616240},
  {01761762080224176240},
  {0176176208011280240}
};


7. last animation:

const byte BIT_ORDER = MSBFIRST;    // Most Significant Bit First = 1
const byte PIN_LATCH_ST_CP = 8;     // Pin connected to ST_CP of 74HC595
const byte PIN_DATA_DS = 11;        // Pin connected to DS of 74HC595. The pin on which to output each bit. Allowed data types: int. Should be ~ pin.
const byte PIN_CLOCK_SHCP = 12;     // Pin connected to SH_CP of 74HC595. The pin to toggle once the PIN_DATA_DS has been set to the correct value. Allowed data types: int.

const byte BIT_ROWS[] = {8137110614};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {122395101415};      // index column bits: C1/Q3, Q1/C2, C3, C4, C5, C6, C7, C8; index value start from 0, -1 each pin
unsigned short DURATION_COLUMN = 2;                          // value too high make you see LED blink, should <=3 is OK

unsigned short DURATION_FRAME = 500;
byte ANIMATION1_DATA[] = {
  0,0,0,63,0,0,0,0,0,0,30,33,30,0,0,0,0,30,33,33,33,30,0,0,12,18,33,33,33,18,12,0,0,30,33,33,33,30,0,0,0,0,30,33,30,0,0,0,0,0,0,63,0,0,0,0,
  0,0,0,24,24,0,0,0,0,0,24,36,36,24,0,0,0,24,36,66,66,36,24,0,24,36,66,129,129,66,36,24,36,66,129,0,0,129,66,36,66,129,0,0,0,0,129,66,129,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,129,66,129,0,0,0,0,129,66,36,66,129,0,0,129,66,36,24,36,66,129,129,66,36,24,0,24,36,66,66,36,24,0,0,0,24,36,36,24,0,0,0,0,0,24,24,0,0,0  ,
  255,129,129,129,129,129,129,255,0,126,66,66,66,66,126,0,0,0,60,36,36,60,0,0,0,0,0,24,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,0,0,0,0,0,60,36,36,60,0,0,0,126,66,66,66,66,126,0,255,129,129,129,129,129,129,255
};

byte indexColumnDisplaying = 0; // store current index column for avoid column on the right display less than column on the left

void setup() {
  pinMode(PIN_LATCH_ST_CP, OUTPUT);
  pinMode(PIN_DATA_DS, OUTPUT);
  pinMode(PIN_CLOCK_SHCP, OUTPUT);
}

unsigned short convertByteColumnTo16Bit(byte byteColumnbyte indexColumnTurnOn) {
  unsigned short dataLED = 0;

  // row is anode, set indexBit of row value to 1 to LED on, value 0 to LED off
  for (byte indexBit = 0; indexBit < 8; indexBit++) {
    bool isOn = byteColumn & (1 << indexBit);
    if (isOn) {
      dataLED |= 1 << BIT_ROWS[indexBit]; 
    }
  }

  // column is cathod, set column value to 0 to LED on, value 1 to LED off, code below mark all other columns off
  for(byte indexColumn = 0; indexColumn < sizeof(BIT_COLUMNS); indexColumn++){
    bool isOn = indexColumn == indexColumnTurnOn;
    if (!isOn) {
      dataLED |= 1 << BIT_COLUMNS[indexColumn]; 
    }    
  }
  
  return dataLED;
}

void display8x8(byte bytesAnimation[], int offsetColumnunsigned short durationFrame) {
  while(durationFrame >= DURATION_COLUMN) {
    byte byteDisplay = bytesAnimation[offsetColumn + indexColumnDisplaying];
    unsigned short dataLED = convertByteColumnTo16Bit(byteDisplay, indexColumnDisplaying);

    digitalWrite(PIN_LATCH_ST_CP, LOW); // ground PIN_LATCH_ST_CP and hold low for as long as you are transmitting
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED >> 8); // shift out highbyte, it's U2 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    shiftOut(PIN_DATA_DS, PIN_CLOCK_SHCP, BIT_ORDER, dataLED); // shift out lowbyte, it's U1 in proteus, doc: https://www.arduino.cc/reference/en/language/functions/advanced-io/shiftout/
    digitalWrite(PIN_LATCH_ST_CP, HIGH); // return the latch pin high to signal chip that it no longer needs to listen for information

    delay(DURATION_COLUMN); // delay(ms), doc: https://www.arduino.cc/reference/en/language/functions/time/delay/
    durationFrame -= DURATION_COLUMN;
    indexColumnDisplaying = (indexColumnDisplaying + 1) % sizeof(BIT_COLUMNS);
  }
}

void animationDisplayFrameByFrame(unsigned short durationFramebyte bytesAnimation[], size_t totalColumns) {
  for(byte offsetColumn = 0; offsetColumn < totalColumns; offsetColumn+=sizeof(BIT_COLUMNS)) {
    display8x8(bytesAnimation, offsetColumn, durationFrame);
  }
}

void loop() {
  animationDisplayFrameByFrame(DURATION_FRAME, ANIMATION1_DATA, sizeof(ANIMATION1_DATA));
}

No comments: