PIC16F876A RTC with seven segments display

I made a seven segments clock display with ds1307 RTC. It feature an 8-digit hh-mm-ss with adjustment and alarm setting. Due to a design and PCB fabrication difficulties, I decided to divide two distinct board, one’s for the main controller board and another one is a display board that stack on the main controller board. The schematic below is the main controller board powered by PIC16F876A.

SSD_CLOCK_MAINBOARD
Schematic Circuit 7404 is just use for simulation only not for PCB design. ULN2804 is not include in simulation but for PCB design.

copper side
copper soldering side

component side
component side

A 7-segments display board stack above the main board.

Multiplexed display board
Schematic of multiplexed seven segments display board

7-segment display board
7-segment display board copper side

component side
components legend side

Completed project
I have assembled and test this project with error-free.

Making the PCB for this project by hands could spend a lot times etching, drilling and soldering. The user could select a PCB service from a PCB supplier.

PIC16F876A is an 8-bit PIC microcontroller with 28-pin package. its package is also come with a DIP version suitable for hobbyist projects and experiment.

This device is fairly fit to this project referring to the numbers of I/O pins requirement, RAM and ROM space.

An I2C peripheral is also require because it needs to read/write timing data between the DS1307 real time clock chip.

The CPU uses its timer0 timer ticks to multiplex an 8-digits 7-segments display. The display made from eight individual 0.8 inch hi-read common cathode display.

I put some buttons to adjust the HH:MM:SS and also the alarm setting. An output active buzzer beeps any time the alarm time is reached. Buttons and buzzer active time is implemented using the timer0 timer ticks method.

MPLABX XC8 is a compiler of choice for this project. Using this free compiler, the coder can access all the registers definition of the SFR just like one’s the the assembly language programming.

Source code and completed PCB project could be get from GitHub.

https://github.com/BongPeav/xc8/raw/master/SSD_CLOCK.X.rar

MPLABX XC8 source code lists below:

#include <xc.h>
#include "config.h"
#include "defination.h"
#include "i2c.h"

unsigned char T0Cnt;
unsigned char T1Cnt;
unsigned char ssdCnt;
unsigned char _time[3];
unsigned char _timeAlarm[3];
unsigned char modeSel;
unsigned char buzTimer;
unsigned char _PORTB;
unsigned int ssdBlink;
bit             blink;
bit             swOn;

void T0Init(void);
void timersTick(void);
void T1Init(void);
void ioInit(void);
void varInit(void);
void clockSetup(void);
void clockAdj(void);
void alarmSet(void);
void alarmCheck(void);
void SSDout(unsigned char hrs,unsigned char mns,unsigned char scs);

unsigned char getDate(unsigned char add);
unsigned char bcd2dec(unsigned char bcd);
unsigned char dec2bcd(unsigned char dec);
void    rtcInit(void);

unsigned char eeRead(unsigned char add);
void eeCommand(void);
void eeWrite(unsigned char add,unsigned char dat);
void alarmLoad(void);

__EEPROM_DATA(12,30,10,0,0,0,0,0);

void interrupt ISR(void){
    if(TMR0IF&&TMR0IE){
        T0Cnt++;
        TMR0=-78;
        TMR0IF=0;
    }

    if(TMR1IF&&TMR1IE){
        T1Cnt++;
        TMR1IF=0;
    }
}

void main(){
    
    ioInit();
    T0Init();
    i2cMasterInit(100000);
    varInit();
    alarmLoad();
    rtcInit();
    T1Init();
    while(1){
        timersTick();
        SSDout(_time[2],_time[1],_time[0]);
        if(modeSel==0)  clockAdj();
        clockSetup();
        alarmCheck();
    }
}

void T0Init(void){
    T0CS=0;
    PSA=0;
    OPTION_REGbits.PS=0x05; // 1:64
    GIE=1;
    TMR0IE=1;
    TMR0IF=0;
}

void timersTick(void){

    if(T0Cnt>=2){
        ssdCnt++;
        ssdBlink++;
        T0Cnt=0;
    }

    if(ssdBlink>=blinkRate){
        blink^=1;
        if(modeSel==0)
        for(int i=0;i<3;i++){
            _time[i]=getDate(i);
            _time[i]=bcd2dec(_time[i]);
        }
        buzTimer++;
        ssdBlink=0;
    }

    if(T1Cnt>=7){
        swOn^=1;
        T1Cnt=0;
    }
}

void ioInit(void){
    TRISA=0xFC;
    TRISB=0x00;
    TRISC=0x00;
    PORTB=0;
    ADCON1bits.PCFG=0x06;   // all digital
    CMCONbits.CM=0x07;      // comparator off
}

void varInit(void){
    T0Cnt=0;
    ssdCnt=0;
    ssdBlink=0;
    modeSel=0;
    T1Cnt=0;
    buzTimer=0;
}

void SSDout(unsigned char hrs,unsigned char mns,unsigned char scs){
    // COMMON CATHODE
    const unsigned char SEG[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    unsigned char hrs10,hrs1,mns10,mns1,scs10,scs1;
/*
    hrs10=hrs>>4;
    hrs1=hrs&0x0F;
    mns10=mns>>4;
    mns1=mns&0x0F;
    scs10=scs>>4;
    scs1=scs&0x0F;
*/

    hrs10=hrs/10;
    hrs1=hrs%10;
    mns10=mns/10;
    mns1=mns%10;
    scs10=scs/10;
    scs1=scs%10;
    
    switch(ssdCnt){
        case 1 :
            PORTA=0x00;
            PORTC=0x00;
            PORTB=SEG[hrs10]|_PORTB;
            D1=1;
            break;

        case 2 :
            PORTA=0x00;
            PORTC=0x00;
            PORTB=SEG[hrs1]|_PORTB;
            D2=1;
            break;

        case 3 :
            PORTA=0x00;
            PORTC=0x00;
            if(blink){
                PORTB=64|_PORTB;
                D3=1;
            }
            break;

        case 4 :
            PORTA=0x00;
            PORTC=0x00;
            PORTB=SEG[mns10]|_PORTB;
            D4=1;
            break;

        case 5 :
            PORTA=0x00;
            PORTC=0x00;
            PORTB=SEG[mns1]|_PORTB;
            D5=1;
            break;

       case 6 :
            PORTA=0x00;
            PORTC=0x00;
            if(blink){
                PORTB=64|_PORTB;
                D6=1;
            }
            break;

      case 7 :
            PORTA=0x00;
            PORTC=0x00;
            PORTB=SEG[scs10]|_PORTB;
            D7=1;
            break;

      case 8 :
            PORTA=0x00;
            PORTC=0x00;
            PORTB=SEG[scs1]|_PORTB;
            D8=1;
            break;

      case 9 :   
            PORTA=0x00;
            PORTC=0x00;
            ssdCnt=0;
            break;
    }
}

unsigned char getDate(unsigned char add){
    unsigned char _time;
    i2cMasterStart();
    i2cMasterWrite(ds1307_W);
    i2cMasterWrite(add);
    i2cMasterRepeatedStart();
    i2cMasterWrite(ds1307_R);
    _time=i2cMasterRead(0);
    i2cMasterStop();
    return _time;
}

unsigned char bcd2dec(unsigned char bcd){
    unsigned char dec;
    dec=10*(bcd>>4)+(bcd&0x0F);
    return dec;
}

unsigned char dec2bcd(unsigned char dec){
    unsigned char bcd,bcd10,bcd1;
    bcd10=dec/10;
    bcd1=dec%10;
    bcd=(bcd10<<4)+bcd1;
    return bcd;
}

void clockSetup(void){
    
    if(mSel==0&&swOn==1){
        modeSel++;
        swOn=0;
    }

    switch(modeSel){
        case 1 :
            alarmSet();
            break;
        case 2 :
            modeSel=0;
            break;
       
    }
}

void    rtcInit(void){
        i2cMasterStart();
        i2cMasterWrite(ds1307_W);
        i2cMasterWrite(0x07);       // Select Control Register
        i2cMasterWrite(0x10);       // 1Hz
        i2cMasterStop();
}

void clockAdj(void){
    unsigned char temp;

    if(sAdj==0&&swOn==1){
        _time[0]++;
        if(_time[0]==60) _time[0]=0;
        temp=dec2bcd(_time[0]);
        i2cMasterStart();
        i2cMasterWrite(ds1307_W);
        i2cMasterWrite(0x00);
        i2cMasterWrite(temp);
        i2cMasterStop();
        swOn=0;
    }

    if(mAdj==0&&swOn==1){
        _time[1]++;
        if(_time[1]==60) _time[1]=0;
        temp=dec2bcd(_time[1]);
        i2cMasterStart();
        i2cMasterWrite(ds1307_W);
        i2cMasterWrite(0x01);
        i2cMasterWrite(temp);
        i2cMasterStop();
        swOn=0;
    }

    if(hAdj==0&&swOn==1){
        _time[2]++;
        if(_time[2]==24) _time[2]=0;
        temp=dec2bcd(_time[2]);
        i2cMasterStart();
        i2cMasterWrite(ds1307_W);
        i2cMasterWrite(0x02);
        i2cMasterWrite(temp);
        i2cMasterStop();
        swOn=0;
    }
}

void eeWrite(unsigned char add,unsigned char dat){
    // write address and data to eeprom
    while(EECON1bits.WR);
    EEADR=add;
    EEDATA=dat;
    EECON1bits.EEPGD=0; // point to data memory
    EECON1bits.WREN=1;  // enable write
}

unsigned char eeRead(unsigned char add){
    unsigned char edata;
    EEADR=add;
    EECON1bits.EEPGD=0; // select data space
    EECON1bits.RD=1;    // read
    edata=EEDATA;
    return edata;
}

void eeCommand(void){
    // Special Command
    GIE=0;
    EECON2=0x55;
    EECON2=0xAA;
    EECON1bits.WR=1;
    GIE=1;
    TMR0IE=1;
    TMR0IF=0;
    EECON1bits.WREN=0;
}

void alarmLoad(void){
    for(int i=0;i<3;i++){
        _timeAlarm[i]=eeRead(i);
    }
}

void alarmSet(void){

    _PORTB=0x00;
    PORTB|=_PORTB;
    for(int i=0;i<3;i++){
        _time[i]=_timeAlarm[i];
    }

    if(sAdj==0&&swOn==1){
        _timeAlarm[0]++;
        if(_timeAlarm[0]==60)   _timeAlarm[0]=0;
        eeWrite(sAlarm,_timeAlarm[0]);
        eeCommand();
        swOn=0;
    }

    if(mAdj==0&&swOn==1){
        _timeAlarm[1]++;
        if(_timeAlarm[1]==60)   _timeAlarm[1]=0;
        eeWrite(mAlarm,_timeAlarm[1]);
        eeCommand();
        swOn=0;
    }

    if(hAdj==0&&swOn==1){
        _timeAlarm[2]++;
        if(_timeAlarm[2]==24)   _timeAlarm[2]=0;
        eeWrite(hAlarm,_timeAlarm[2]);
        eeCommand();
        swOn=0;
    }

     alarmLoad();
     
}

void T1Init(void){
    T1CONbits.T1CKPS=0x02;  // 1:4
    T1CONbits.T1OSCEN=0;
    T1CONbits.TMR1CS=0;     //FOSC/4
    T1CONbits.TMR1ON=1;
    TMR1H=0;
    TMR1L=0;
    INTCONbits.PEIE=1;
    PIE1bits.TMR1IE=1;
    PIR1bits.TMR1IF=0;
}

void alarmCheck(void){
    unsigned short long alarmSet;
    unsigned short long timeRun;
    alarmSet=(3600*_timeAlarm[2])+(60*_timeAlarm[1])+_timeAlarm[0];
    timeRun=(3600*_time[2])+(60*_time[1])+_time[0];

    if((timeRun<=alarmSet+10)&&(timeRun>=alarmSet)){
        _PORTB=128;
    }
    else
        _PORTB=0;
    
}

Bill of Material:

Category	References	Value	Stock Code	Unit Cost
Capacitors	C1	10p	Maplin WX44X	
Capacitors	C2	10p	Maplin WX44X	
Capacitors	C3	1000U	Digikey P5142-ND	
Capacitors	C4	100n	Maplin BX03D	
Resistors	R1	220R	M220R	
Resistors	R2	220R	M220R	
Resistors	R3	220R	M220R	
Resistors	R4	220R	M220R	
Resistors	R5	220R	M220R	
Resistors	R6	220R	M220R	
Resistors	R7	220R	M220R	
Resistors	R8	220R	M220R	
Resistors	R9	10k	M10K	
Resistors	R10	10k	M10K	
Resistors	R11	1k	M1k	
Resistors	R12	10k	M10K	
Resistors	R13	10k	M10K	
Resistors	R14	10k	M10K	
Resistors	R15	10k	M10K	
Resistors	R16	10k	M10K	
Resistors	R17	470R	M220R	
Integrated Circuits	U1	CONN-SIL8		
Integrated Circuits	U2	DD7SEG08		
Integrated Circuits	U3	7404		
Integrated Circuits	U4	7404		
Integrated Circuits	U5	ULN2804		
Transistors	Q1	2N3904		
Diodes	D1	CONN-SIL7		
Diodes	D2	LED		
Miscellaneous	BAT1	3V		
Miscellaneous	BUZ1	BUZZER03		
Miscellaneous	BUZ2	BUZZER03		
Miscellaneous	DP1	DD7SEG08		
Miscellaneous	DP2	DD7SEG08		
Miscellaneous	DP3	DD7SEG08		
Miscellaneous	DP4	DD7SEG08		
Miscellaneous	J1	DD7SEG08		
Miscellaneous	J2	CONN-SIL8		
Miscellaneous	J3	CONN-SIL2		
Miscellaneous	J4	ICSP		
Miscellaneous	J5	CONN-SIL7		
Miscellaneous	J6	CONN-SIL8		
Miscellaneous	SW1			
Miscellaneous	SW2			
Miscellaneous	SW3			
Miscellaneous	SW4			
Miscellaneous	SW5			
Miscellaneous	X1	DD7SEG08		
Miscellaneous	X2	CRYSTAL		

Click here to download full PCB project file.

PCB from PCBWay

Leave a comment