////////////////////////////////////////////////////////////////////////////////
//  16F877 Clock Program
//      (c)2003 JimCom
////////////////////////////////////////////////////////////////////////////////

//  System Headers
#include <16F877.h>
#device *=16
#use delay(clock=12800000)
#fuses HS,PUT,BROWNOUT,NOWDT,NOPROTECT,NOLVP,NOCPD,WRT
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7)

//  IO Port Define
#byte   PA = 5
#byte   PB = 6
#byte   PC = 7
#byte   PD = 8
#byte   PE = 9

////////////////////////////////////////////////////////////////////////////////
//  Timer Counter Value
#define RTCVAL  3125

//  Key Wait Time
#define UPVAL   500

// Tone Freq.
#define TONE    568

//  Global Work
unsigned long  RTC = RTCVAL;
unsigned int   H10 = 0, H1 = 0;
unsigned int   M10 = 0, M1 = 0;
unsigned int   S10 = 0, S1 = 0;
int1           HourFlg = 0;

////////////////////////////////////////////////////////////////////////////////
//  Interrupt Routine
#int_RTCC
RTCC_isr()
{
    RTC--;

    if (RTC == 0)
    {
        RTC = RTCVAL;
        S1++;
        if (S1 > 9) {
            S1 = 0;
            S10++;
            if (S10 > 5) {
                S10 = 0;
                M1++;
                if (M1 > 9) {
                    M1 = 0;
                    M10++;
                    if (M10 > 5) {
                        M10 = 0;
                        H1++;
                        HourFlg = 1;
                        if (H1 > 9) {
                            H1 = 0;
                            H10++;
                        }
                    }
                }
            }
        }
        if ((H10 == 2) && (H1 == 4)) {
                H1  = 0;
                H10 = 0;
        }
        if ((S1 & 1) == 0) {
            if (S10 < 3) {
                PE = 0b011;
            }
            else {
                PE = 0b011;
            }
         }

         else {
           if (S10 < 3) {
                PE = 0b010;
            }
            else {
                PE = 0b001;
            }
         }

    }
}

////////////////////////////////////////////////////////////////////////////////

void timeup(){
    S1++;
    if (S1 > 9) {
        S1 = 0;
        S10++;
        if (S10 > 5) {
            S10 = 0;
            M1++;
            if (M1 > 9) {
                M1 = 0;
                M10++;
                if (M10 > 5) {
                    M10 = 0;
                    H1++;
                    if (H1 > 9) {
                        H1 = 0;
                        H10++;

                    }
                }
            }
        }
    }
    if ((H10 == 2) && (H1 == 4)) {
            H1  = 0;
            H10 = 0;
    }
}

//
void set_zero() {
    S1  = 0;
    if (S10 >= 3 ) {
        M1++;
        if (M1 > 9) {
            M1 = 0;
            M10++;
            if (M10 > 5) {
                M10 = 0;
                H1++;
                if (H1 > 9) {
                    H1 = 0;
                    H10++;

                }
            }
        }
        if ((H10 == 2) && (H1 == 4)) {
              H1  = 0;
              H10 = 0;
        }
     }
     S10 = 0;
     RTC = RTCVAL;
     set_timer0(0);

}

void up_min() {
    M1++;
    if (M1 > 9) {
        M1 = 0;
        M10++;
        if (M10 > 5) {
            M10 = 0;
            H1++;
            if (H1 >9) {
                H1 = 0;
                H10++;
            }
         }
    }
    if ((H10 == 2) && (H1 == 4)) {
                     H1  = 0;
                     H10 = 0;
    }
}

void up_hur() {
    H1++;
    if (H1 > 9) {
        H1 = 0;
        H10++;
    }
    if ((H10 == 2) && (H1 == 4)) {
             H1  = 0;
             H10 = 0;
    }
}


//  Value to 7Seg LED
unsigned int val2led(unsigned int dat) {
    unsigned int const ledtbl[10] = {
                0b00111111,     // 0
                0b00000110,     // 1
                0b01011011,     // 2
                0b01001111,     // 3
                0b01100110,     // 4
                0b01101101,     // 5
                0b01111101,     // 6
                0b00100111,     // 7
                0b01111111,     // 8
                0b01101111 };   // 9

    return ( ledtbl[dat] );
}

//  Display Routine
void LED_disp(){
    unsigned int   col;
    for (col = 0; col < 4; col++) {
           switch (col) {

            case 0 :PB = val2led(H10);
                    PC = 0b0001;
                    break;

            case 1 :PB = val2led(H1);
                    PC = 0b0010;
                    break;

            case 2 :PB = val2led(M10);
                    PC = 0b0100;
                    break;

            case 3 :PB = val2led(M1);
                    PC = 0b1000;
                    break;

            default :

        }
    }
}

//  Beep Routine
void Beep() {
    unsigned long t;
    for (t = 0; t < 1000; t++) {
        output_high(PIN_D0);
        delay_us(TONE);
        output_low(PIN_D0);
        delay_us(TONE);
    }
}

//  Main Routine
void main() {

    setup_adc_ports(NO_ANALOGS);
    setup_adc(ADC_CLOCK_DIV_2);
    setup_psp(PSP_DISABLED);
    setup_spi(FALSE);
    setup_timer_1(T1_DISABLED);
    setup_timer_2(T2_DISABLED,0,1);
    set_tris_A(0b111111);
    set_tris_B(0b00000000);
    set_tris_C(0b00000000);
    set_tris_D(0b00000000);
    set_tris_E(0b000);
    setup_counters(RTCC_INTERNAL,RTCC_DIV_4);

    RTC = RTCVAL;
    H10 = 0; H1 = 0;
    M10 = 0; M1 = 0;
    S10 = 0; S1 = 0;

    HourFlg = 0;

    PB = 0;
    PC = 0;
    PD = 0;
    PE = 0;

    set_timer0(0);
    enable_interrupts(INT_RTCC);
    enable_interrupts(global);

    while(1) {
        LED_disp();

        switch ( PA & 0b111) {
            case 0b110 :set_zero();
                        LED_disp();
                        DELAY_MS(900);
                        break;

            case 0b101 :up_min();
                        LED_disp();
                        DELAY_MS(UPVAL);
                        break;

            case 0b011 :up_hur();
                        LED_disp();
                        DELAY_MS(UPVAL);
                        break;

            default :
        }

        if (HourFlg == 1) {
            HourFlg = 0;
//            Beep();
        }

    }
}
