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[] = {8, 13, 7, 11, 0, 6, 1, 4};           // 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[] = {12, 2, 3, 9, 5, 10, 14, 15};      // 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[] = {8, 13, 7, 11, 0, 6, 1, 4};           // 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[] = {12, 2, 3, 9, 5, 10, 14, 15};      // 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[] = {8, 13, 7, 11, 0, 6, 1, 4};           // 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[] = {12, 2, 3, 9, 5, 10, 14, 15};      // 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[] = {8, 13, 7, 11, 0, 6, 1, 4};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {12, 2, 3, 9, 5, 10, 14, 15};      // 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 byteColumn, byte 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 offsetColumn, unsigned 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 durationFrame, byte 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[] = {8, 13, 7, 11, 0, 6, 1, 4};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {12, 2, 3, 9, 5, 10, 14, 15};      // 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 byteColumn, byte 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 totalColumns, int offsetColumn, unsigned 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 durationFrame, byte 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[] = {8, 13, 7, 11, 0, 6, 1, 4};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {12, 2, 3, 9, 5, 10, 14, 15};      // 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 byteColumn, byte 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 totalColumns, int offsetColumn, unsigned 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 durationFrame, byte 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[] = { 8, 13, 7, 11, 0, 6, 1, 4 };       // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = { 12, 2, 3, 9, 5, 10, 14, 15 };  // 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] = {
  {0, 0, 0, 0, 12, 0, 0, 0},
  {0, 0, 0, 0, 8, 4, 0, 0},
  {0, 0, 0, 0, 8, 8, 0, 0},
  {0, 0, 0, 0, 16, 16, 0, 0},
  {0, 0, 0, 0, 16, 32, 0, 0},
  {0, 0, 0, 0, 48, 0, 0, 0},
  {0, 0, 0, 48, 0, 0, 0, 0},
  {0, 0, 32, 16, 0, 0, 0, 0},
  {0, 0, 16, 16, 0, 0, 0, 0},
  {0, 0, 8, 8, 0, 0, 0, 0},
  {0, 0, 4, 8, 0, 0, 0, 0},
  {0, 0, 0, 12, 0, 0, 0, 0}
};
byte MINUTES[60][8] = {
  {0, 0, 0, 0, 15, 0, 0, 0},
  {0, 0, 0, 0, 14, 1, 0, 0},
  {0, 0, 0, 0, 12, 3, 0, 0},
  {0, 0, 0, 0, 8, 7, 0, 0},
  {0, 0, 0, 0, 8, 6, 1, 0},
  {0, 0, 0, 0, 8, 4, 3, 0},
  {0, 0, 0, 0, 8, 4, 2, 1},
  {0, 0, 0, 0, 8, 4, 2, 2},
  {0, 0, 0, 0, 8, 4, 4, 2},
  {0, 0, 0, 0, 8, 4, 4, 4},
  {0, 0, 0, 0, 8, 8, 4, 4},
  {0, 0, 0, 0, 8, 8, 8, 4},
  {0, 0, 0, 0, 8, 8, 8, 8},
  {0, 0, 0, 0, 16, 16, 8, 8},
  {0, 0, 0, 0, 16, 16, 16, 8},
  {0, 0, 0, 0, 16, 16, 16, 16},
  {0, 0, 0, 0, 16, 16, 16, 32},
  {0, 0, 0, 0, 16, 16, 32, 32},
  {0, 0, 0, 0, 16, 32, 32, 32},
  {0, 0, 0, 0, 16, 32, 32, 64},
  {0, 0, 0, 0, 16, 32, 64, 64},
  {0, 0, 0, 0, 16, 32, 64, 128},
  {0, 0, 0, 0, 16, 32, 192, 0},
  {0, 0, 0, 0, 16, 96, 128, 0},
  {0, 0, 0, 0, 16, 224, 0, 0},
  {0, 0, 0, 0, 48, 192, 0, 0},
  {0, 0, 0, 0, 112, 128, 0, 0},
  {0, 0, 0, 0, 240, 0, 0, 0},
  {0, 0, 0, 48, 192, 0, 0, 0},
  {0, 0, 0, 112, 128, 0, 0, 0},
  {0, 0, 0, 240, 0, 0, 0, 0},
  {0, 0, 128, 112, 0, 0, 0, 0},
  {0, 0, 192, 48, 0, 0, 0, 0},
  {0, 0, 224, 16, 0, 0, 0, 0},
  {0, 128, 96, 16, 0, 0, 0, 0},
  {0, 192, 32, 16, 0, 0, 0, 0},
  {128, 64, 32, 16, 0, 0, 0, 0},
  {64, 64, 32, 16, 0, 0, 0, 0},
  {64, 32, 32, 16, 0, 0, 0, 0},
  {32, 32, 32, 16, 0, 0, 0, 0},
  {32, 32, 16, 16, 0, 0, 0, 0},
  {32, 16, 16, 16, 0, 0, 0, 0},
  {16, 16, 16, 16, 0, 0, 0, 0},
  {16, 16, 8, 8, 0, 0, 0, 0},
  {16, 8, 8, 8, 0, 0, 0, 0},
  {8, 8, 8, 8, 0, 0, 0, 0},
  {4, 8, 8, 8, 0, 0, 0, 0},
  {4, 4, 8, 8, 0, 0, 0, 0},
  {4, 4, 4, 8, 0, 0, 0, 0},
  {2, 4, 4, 8, 0, 0, 0, 0},
  {2, 2, 4, 8, 0, 0, 0, 0},
  {1, 2, 4, 8, 0, 0, 0, 0},
  {0, 3, 4, 8, 0, 0, 0, 0},
  {0, 1, 6, 8, 0, 0, 0, 0},
  {0, 0, 7, 8, 0, 0, 0, 0},
  {0, 0, 3, 12, 0, 0, 0, 0},
  {0, 0, 1, 14, 0, 0, 0, 0},
  {0, 0, 0, 15, 0, 0, 0, 0},
  {0, 0, 0, 3, 12, 0, 0, 0},
  {0, 0, 0, 1, 14, 0, 0, 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);
  Serial.begin(9600);
}
unsigned short convertByteColumnTo16Bit(byte byteColumn, byte 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] = {
  {0, 0, 0, 0, 1, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 1, 0},
  {0, 0, 0, 0, 0, 0, 0, 2},
  {0, 0, 0, 0, 0, 0, 0, 16},
  {0, 0, 0, 0, 0, 0, 0, 64},
  {0, 0, 0, 0, 0, 0, 128, 0},
  {0, 0, 0, 128, 0, 0, 0, 0},
  {0, 128, 0, 0, 0, 0, 0, 0},
  {64, 0, 0, 0, 0, 0, 0, 0},
  {16, 0, 0, 0, 0, 0, 0, 0},
  {2, 0, 0, 0, 0, 0, 0, 0},
  {0, 1, 0, 0, 0, 0, 0, 0}
};
replace value below to change clock display text
byte HOURS[24][8] = {
  {15, 9, 15, 0, 15, 9, 15, 0},
  {15, 9, 15, 0, 9, 15, 8, 0},
  {15, 9, 15, 0, 13, 11, 11, 0},
  {15, 9, 15, 0, 9, 11, 15, 0},
  {15, 9, 15, 0, 3, 2, 15, 0},
  {15, 9, 15, 0, 11, 11, 13, 0},
  {15, 9, 15, 0, 15, 10, 14, 0},
  {15, 9, 15, 0, 1, 1, 15, 0},
  {15, 9, 15, 0, 14, 11, 15, 0},
  {15, 9, 15, 0, 7, 5, 15, 0},
  {9, 15, 8, 0, 15, 9, 15, 0},
  {9, 15, 8, 0, 9, 15, 8, 0},
  {9, 15, 8, 0, 13, 11, 11, 0},
  {9, 15, 8, 0, 9, 11, 15, 0},
  {9, 15, 8, 0, 3, 2, 15, 0},
  {9, 15, 8, 0, 11, 11, 13, 0},
  {9, 15, 8, 0, 15, 10, 14, 0},
  {9, 15, 8, 0, 1, 1, 15, 0},
  {9, 15, 8, 0, 14, 11, 15, 0},
  {9, 15, 8, 0, 7, 5, 15, 0},
  {13, 11, 11, 0, 15, 9, 15, 0},
  {13, 11, 11, 0, 9, 15, 8, 0},
  {13, 11, 11, 0, 13, 11, 11, 0},
  {13, 11, 11, 0, 9, 11, 15, 0}
};
byte MINUTES[60][8] = {
  {0, 240, 144, 240, 0, 240, 144, 240},
  {0, 240, 144, 240, 0, 144, 240, 128},
  {0, 240, 144, 240, 0, 208, 176, 176},
  {0, 240, 144, 240, 0, 144, 176, 240},
  {0, 240, 144, 240, 0, 48, 32, 240},
  {0, 240, 144, 240, 0, 176, 176, 208},
  {0, 240, 144, 240, 0, 240, 160, 224},
  {0, 240, 144, 240, 0, 16, 16, 240},
  {0, 240, 144, 240, 0, 224, 176, 240},
  {0, 240, 144, 240, 0, 112, 80, 240},
  {0, 144, 240, 128, 0, 240, 144, 240},
  {0, 144, 240, 128, 0, 144, 240, 128},
  {0, 144, 240, 128, 0, 208, 176, 176},
  {0, 144, 240, 128, 0, 144, 176, 240},
  {0, 144, 240, 128, 0, 48, 32, 240},
  {0, 144, 240, 128, 0, 176, 176, 208},
  {0, 144, 240, 128, 0, 240, 160, 224},
  {0, 144, 240, 128, 0, 16, 16, 240},
  {0, 144, 240, 128, 0, 224, 176, 240},
  {0, 144, 240, 128, 0, 112, 80, 240},
  {0, 208, 176, 176, 0, 240, 144, 240},
  {0, 208, 176, 176, 0, 144, 240, 128},
  {0, 208, 176, 176, 0, 208, 176, 176},
  {0, 208, 176, 176, 0, 144, 176, 240},
  {0, 208, 176, 176, 0, 48, 32, 240},
  {0, 208, 176, 176, 0, 176, 176, 208},
  {0, 208, 176, 176, 0, 240, 160, 224},
  {0, 208, 176, 176, 0, 16, 16, 240},
  {0, 208, 176, 176, 0, 224, 176, 240},
  {0, 208, 176, 176, 0, 112, 80, 240},
  {0, 144, 176, 240, 0, 240, 144, 240},
  {0, 144, 176, 240, 0, 144, 240, 128},
  {0, 144, 176, 240, 0, 208, 176, 176},
  {0, 144, 176, 240, 0, 144, 176, 240},
  {0, 144, 176, 240, 0, 48, 32, 240},
  {0, 144, 176, 240, 0, 176, 176, 208},
  {0, 144, 176, 240, 0, 240, 160, 224},
  {0, 144, 176, 240, 0, 16, 16, 240},
  {0, 144, 176, 240, 0, 224, 176, 240},
  {0, 144, 176, 240, 0, 112, 80, 240},
  {0, 48, 32, 240, 0, 240, 144, 240},
  {0, 48, 32, 240, 0, 144, 240, 128},
  {0, 48, 32, 240, 0, 208, 176, 176},
  {0, 48, 32, 240, 0, 144, 176, 240},
  {0, 48, 32, 240, 0, 48, 32, 240},
  {0, 48, 32, 240, 0, 176, 176, 208},
  {0, 48, 32, 240, 0, 240, 160, 224},
  {0, 48, 32, 240, 0, 16, 16, 240},
  {0, 48, 32, 240, 0, 224, 176, 240},
  {0, 48, 32, 240, 0, 112, 80, 240},
  {0, 176, 176, 208, 0, 240, 144, 240},
  {0, 176, 176, 208, 0, 144, 240, 128},
  {0, 176, 176, 208, 0, 208, 176, 176},
  {0, 176, 176, 208, 0, 144, 176, 240},
  {0, 176, 176, 208, 0, 48, 32, 240},
  {0, 176, 176, 208, 0, 176, 176, 208},
  {0, 176, 176, 208, 0, 240, 160, 224},
  {0, 176, 176, 208, 0, 16, 16, 240},
  {0, 176, 176, 208, 0, 224, 176, 240},
  {0, 176, 176, 208, 0, 112, 80, 240}
};
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[] = {8, 13, 7, 11, 0, 6, 1, 4};           // index row bit: R1/Q0, R2, R3, R4, R5, R6, R7, R8; index value start from 0, -1 each pin
const byte BIT_COLUMNS[] = {12, 2, 3, 9, 5, 10, 14, 15};      // 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 byteColumn, byte 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 offsetColumn, unsigned 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 durationFrame, byte 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:
Post a Comment