Другой вариант часов. Индикатор с общим катодом. Сегменты -PORTB.Разряды цифр PD2-PD5 через резисторы 220 Ом. Кнопка коррекции PD0. Внешний кварц на 8МГц.
char CharMap[11] = {
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x00, //
};
char Buffer[] = { 1, 2, 5, 9, 0 };
int Size[] = { 2, 10, 6, 10, 60 };
char Columns[4] = { 4, 5, 6, 7};
int Digit;
int Point;
volatile int Counter;
void DisplayNextDigital() {
  char segs;
  Digit = (Digit+1) % 4;//считаем от 0 до 4
  char Char = Buffer[Digit];
  if (Digit == 0 && Char == 0) Char = 10; // delete zero
  if (Digit == 1)segs= CharMap[Char]|Point;
  else segs = CharMap[Char];
  DDRB = DDRB & 0x00;                  // B7-B0 all inputs
  PORTB = PORTB | segs;                 // 1 = high
  DDRB = DDRB | segs;                   // 1 = output
}
void SetTime() {
  int Speed = 2000;
  if ((PIND & 1)==0) Speed = 4;         // Check set time button
  if (Counter == 0) {                   // Runs at 1Hz
    Counter = Speed;
    Point = Point ^ 0x80;    // Flash point
    int Carry = 1;
    for (int p=4; p>=0; p--) {
      char temp = Buffer[p] + Carry;
      Buffer[p] = temp % Size[p];
      Carry = temp / Size[p];
      if (Buffer[0]==2 && Buffer[1]==4) { // 24 hour
        Buffer[0] = 0;
        Buffer[1] = 1;
      }
    }
  }
  Counter--;  
}
ISR (TIMER1_COMPA_vect) {
  pinMode(Columns[Digit], INPUT);       // Turn off display
  DisplayNextDigital();
  SetTime();
}
ISR (TIMER1_COMPB_vect) {
  pinMode(Columns[Digit], OUTPUT);      // Turn  on display
  digitalWrite(Columns[Digit], LOW);
}
void setup() {
  pinMode(0, INPUT);
  
  TCCR1A = 0<<WGM10;
  TCCR1B = 1<<WGM12 | 2<<CS10;           // Divide by 8
  OCR1A = 499;                           // Compare match at 2000Hz
  OCR1B = 0;                           // Brightness; reduce for brighter min=480 max=0
  TIMSK = TIMSK | 1<<OCIE1A | 1<<OCIE1B; // Compare match interrupt enable
}
// All done under interrupt!
void loop() {
}
+DS3231. Внутренний кварц на 8Мгц. Кнопки коррекции PDO - часы,PD1 - минуты
#define SDA  PA0
#define SCL  PA1
// plus_h PDO    
// plus_m PD1   
char CharMap[11] = {
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x00, //
};
char Buffer[] = { 1, 2, 5, 9, 0 };
unsigned long Alarm,debonce;
char Columns[4] = { 4, 5, 6, 7};
int Digit;
int Point;
unsigned char hour,min;
void DisplayNextDigital() {
  char segs;
  Digit = (Digit+1) % 4;//считаем от 0 до 4
  char Char = Buffer[Digit];
  if (Digit == 0 && Char == 0) Char = 10; // delete zero
  if (Digit == 1)segs= CharMap[Char]|Point;
  else segs = CharMap[Char];
  DDRB = DDRB & 0x00;                  // B7-B0 all inputs
  PORTB = PORTB | segs;                 // 1 = high
  DDRB = DDRB | segs;                   // 1 = output
}
// Timer interrupts - multiplex display
ISR (TIMER1_COMPA_vect) {
  pinMode(Columns[Digit], INPUT);       // Turn off display
  DisplayNextDigital();
}
ISR (TIMER1_COMPB_vect) {
  pinMode(Columns[Digit], OUTPUT);      // Turn  on display
  digitalWrite(Columns[Digit], LOW);
}
void setup() {
  pinMode(0, INPUT);
  pinMode(1, INPUT);
 
  TCCR1A = 0<<WGM10;
  TCCR1B = 1<<WGM12 | 2<<CS10;           // Divide by 8
  OCR1A = 499;                           // Compare match at 2000Hz
  OCR1B = 0;                           // Brightness; reduce for brighter min=480 max=0
  TIMSK = TIMSK | 1<<OCIE1A | 1<<OCIE1B; // Compare match interrupt enable
  
}
void loop() {
   read_time();
      Buffer[0] = hour / 10;       
      Buffer[1] = hour % 10;       
      Buffer[2] = min / 10;        
      Buffer[3] = min % 10;          
    if (digitalRead(0) == 0&&millis()-debonce>300) 
        {hour++; 
         if (hour > 23) hour = 0;
         ds_write(0x02,(hour/10<<4)+hour%10);
         debonce= millis(); 
        }
    if (digitalRead(1) == 0&&millis()-debonce>300) 
        {min++;
         if (min > 59) min = 0;
        ds_write(0x01,(min/10<<4)+min%10);
         debonce= millis(); 
        } 
  if(millis()-Alarm>1000){
  Point= Point^0x80; Alarm=millis();
  }
}
bool i2c_read_bit() {
    bool i2c_bit = 1;        
    DDRA &= ~(1 << SDA);            
    delayMicroseconds(10); 
    DDRA &= ~(1 << SCL);                
    if((PINA >> SDA) & 1) i2c_bit=0;                            
    delayMicroseconds(10);  
    DDRA |= (1 << SCL);              
    return i2c_bit;  
}
 
byte i2c_write_byte(byte data){
    for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;}    
    return i2c_read_bit(); 
}
 
byte i2c_read_byte(byte a){
    byte i, data=0;                
    for(i=0; i<8; i++){if (!i2c_read_bit()) data++;if(i!=7) data<<=1;}        
    i2c_write_bit(a);return data;  
}
 
void i2c_write_bit(byte b){
    delayMicroseconds(5);
    if(b){DDRA |= (1 << SDA);}else{DDRA &= ~(1 << SDA);}
    delayMicroseconds(5);
    DDRA &= ~(1 << SCL);       
    delayMicroseconds(10);
    DDRA |= (1 << SCL);
}
 
void i2c_start(){
     delayMicroseconds(10);  
     DDRA &= ~(1 << SDA); DDRA &= ~(1 << SCL); 
     delayMicroseconds(10); 
     DDRA |= (1 << SDA);  PORTA &= ~(1 << SDA);
     delayMicroseconds(10); 
     DDRA |= (1 << SCL);  PORTA &= ~(1 << SCL);   
     delayMicroseconds(10);
}
 
void i2c_stop()  {
     DDRA |= (1 << SDA);            
     delayMicroseconds(10);
     DDRA &= ~(1 << SCL);               
     delayMicroseconds(10); 
     DDRA &= ~(1 << SDA);             
}
 
byte ds_read(byte reg){
     byte data = 0;
     i2c_start();
     i2c_write_byte(0b11010000);
     i2c_write_byte(reg);
     i2c_start(); 
     i2c_write_byte(0b11010001); 
     data = i2c_read_byte(0);
     i2c_stop();
     return data;
  }
 
void ds_write(byte reg, byte data){
     i2c_start();
     i2c_write_byte(0b11010000);
     i2c_write_byte(reg);
     i2c_write_byte(data);
     i2c_stop();
  }  
 
void set_time(byte hours ,byte minute, byte second){
    ds_write(0x00,(second/10<<4)+second%10);
    ds_write(0x01,(minute/10<<4)+minute%10);
    ds_write(0x02,(hours/10<<4)+hours%10);
  }
void read_time(){  
min =  (ds_read(1) & 0x0F) + (((ds_read(1) & 0x70) >> 4) * 10);
hour = (ds_read(2) & 0x0F) + (((ds_read(2) & 0x70) >> 4) * 10);
       
  } 
GPS часы без учета часового пояса.
// David Johnson-Davies - www.technoblogy.com - 9th July 2018
// ATtiny2313 @ 8 MHz (external crystal; BOD disabled)
// Seven-segment definitions
const int charArrayLen = 12;
uint8_t charArray[] = {
//  ABCDEFG  Segments
  0b1111110, // 0
  0b0110000, // 1
  0b1101101, // 2
  0b1111001, // 3
  0b0110011, // 4
  0b1011011, // 5
  0b1011111, // 6
  0b1110000, // 7
  0b1111111, // 8
  0b1111011, // 9
  0b0000001, // 10  '-'
  0b0000000  // 11  Space
};
const int Dash = 10;
const int Space = 11;
uint8_t Buffer[] = { Dash, Dash, Dash, Dash};
uint8_t dp = -1;  // Decimal point position 0 to 3
uint8_t digit = 0;
uint8_t Digits[] = {4, 7, 5, 6};
// Segments must all go to port B; this specifies how they're wired up:
//                    g  f  e  d  c  b  a  dp
uint8_t Segments[] = {2, 4, 5, 3, 1, 6, 7, 0};
//G-PB0,F-PB1..A-PB6,DP-PB6 without void ReorderBits()
void ReorderBits() {         //переупорядить биты.
  uint8_t segs, newsegs;
  for (int i=0; i<charArrayLen; i++) {
    segs = charArray[i];
    newsegs = 0;
    for (int i=0; i<8; i++) {
      newsegs = newsegs | ((segs & 1)<<Segments[i]);
      segs = segs >> 1;
    }
    charArray[i]=newsegs;
  }  
}
void DisplayNextDigit() {
  pinMode(Digits[digit], INPUT);
  digit = (digit+1) % 4;
  uint8_t segs = charArray[Buffer[digit]];
  // Display decimal point?
  if (digit == dp) segs = segs | (1<<Segments[7]);
  DDRB = 0;     // All inputs
  PORTB = segs; // 1 = high
  DDRB = segs;  // 1 = output
  pinMode(Digits[digit], OUTPUT);
  digitalWrite(Digits[digit], LOW);
}
// Display a four/five digit decimal number
void Display (unsigned int number) {
  boolean dig = false;
  int j;
  if (number>9999) { j=10000; dp=2; }
  else { j=1000; dp=1; }
  for (int d=0; d<4 ; d++) {
    int i = (number/j) % 10;
    if (!i && !dig && j>100) Buffer[d]=Space;
    else { Buffer[d]=i; dig = true; }
    j=j/10;
  }
}
// ParseGPS
// Example: $GPRMC,194509.000,A,4042.6142,N,07400.4168,W,2.03,221.11,160412,,,A*77
const char fmt[] PROGMEM =
           "$GPRMC,dddtdd.ddm,A,????.????,?,?????.????,?,djdk,???.??,??????,,,?*??";
int state = 0;
unsigned int temp;
// GPS variables
volatile unsigned int Time;
void ParseGPS (char c) {
  if (c == '$') { state = 0; temp = 0; }
  uint8_t mode = pgm_read_byte_near(fmt + state++);
  // If received character matches format string, or format is '?' - return
  if ((mode == c) || (mode == '?')) return;
  // d=decimal digit
  uint8_t d = c - '0';
  if (mode == 'd') temp = temp*10 + d;
  // t=Time - hhmm
  else if (mode == 't') { Time = temp*10 + d; temp = 0; }
  else state = 0;
}
// Timer interrupt - multiplexes display
ISR (TIMER1_COMPA_vect) {
  DisplayNextDigit();
}
// USART interrupt - receives data from GPS module
ISR (USART_RX_vect) {
  uint8_t c = UDR;
  ParseGPS(c);
}
void setup() {
  ReorderBits();
  // Set up Timer1 to multiplex the display
  TCCR1A = 0<<WGM10;
  TCCR1B = 1<<WGM12 | 2<<CS10;  // Divide by 8
  OCR1A = 4999;                 // Compare match at 200Hz
  TIMSK |= 1<<OCIE1A;           // Compare match interrupt enable
  // Set up USART
  UCSRB = 1<<RXEN | 1<<RXCIE;   // Enable Rx and interrupt
  UCSRC = 3<<UCSZ0;             // 8-bit UART mode
  UBRRL = 51;                   // 9600 baud
}
void loop() {
  unsigned int temp; 
  cli(); temp = Time; sei();
  Display(temp);
  
}