Thursday, November 13, 2008

Making a Digital Clock (Updated)

My fist Microcontroller project, PIC Digital Clock, is shown below.
Prototype digital clock on Breadbord

I have added time setting feature to make it to be a usable clock. The updated version is shown below:
7-Segment Digital Clock

More features will be added in the future.
There is no fast or slow time setting as in normal/simple digital clocks. In this clock, each digit of the clock display can be set one by one via 2 setting buttons.
Features
1. Bright Led 7-Segment display without Multiplexing
2. Display: Hour, Minute, Second
3. Set time via 2 buttons
4. Set time Digit by Digit
5. Use internal oscillator of PIC16F627a or PIC16F628
6. Use 32.768KHz crystal for better clock accuracy


Setting Time:
1. The clock shows 12:34:56 when power the clock on. The first digit of hour (it's number 1 in this case) will be blinking to notify that the time is not correct and need to be set.
2. Press SET button to count up the digit.
3. Press MODE button when the digit is the correct time. The next digit will be blinking.
4. Repeat step 2 and 3 for setting minute and second.
5. Make sure that pressing MODE button for setting the second digit of second at the correct time.


Shecmatic of the Digital Clock
Schematic of a Digital Clock using PIC16F627a or PIC16F628 and Led 7-Segment with showing second

Example of a PCB design of the Digital Clock
PCB of a Digital Clock using PIC16F627a or PIC16F628 and Led 7-Segment with showing second

The firmware ( source code in C ) written in MikroC
//6 digit  clock
//Using timer1 16bit counter interrupt
// PIC16F627A or PIC16F628
// Internal Clock 4MHz
// PUNKKY@gmail.com
#define MODE PORTB.F4
#define SET PORTB.F5
#define Sec_port_l PORTA.F6
#define Sec_port_h PORTA.F4
#define Min_port_l PORTA.F3
#define Min_port_h PORTA.F2
#define Hr_port_l PORTA.F1
#define Hr_port_h PORTA.F0
#define Blink PORTA.F7
#define HTMR1 0x80
#define LTMR1 0x00
typedef unsigned short uns8;
uns8 i;
uns8 hr_h;
uns8 hr_l;
uns8 min_h;
uns8 min_l;
uns8 sec_h;
uns8 sec_l;
uns8 tick;
uns8 myTimer;
uns8 setting_time;
void setup ();
void set_time ();
void show_time ();
void display (uns8 digit);
void blink_digit (uns8 digit);
void check_bt ();

//void check_bt(); //chech button
void interrupt ()
{
        PIR1.TMR1IF = 0;
        // clears TMR1IF
        TMR1H = HTMR1;
        tick = 1;
        Blink = 1;
        sec_l ++;
        if(sec_l>9){
            sec_l = 0;
            sec_h++;
        }
        if(sec_h>5){
            sec_h=0;
            min_l++;
        }
        if(min_l>9){
            min_l = 0;
            min_h++;
        }
        if(min_h>5){
            min_h = 0;
            hr_l++;
        }
        if(hr_l>9){
            hr_l = 0;
            hr_h++;
        }
        if(hr_h >2){
            hr_h = 0;
        }
        if(hr_h >=2 && hr_l>3){
           hr_h = 0;
           hr_l = 0;
        }
}
void main ()
{
        setup ();
        
        //Set time
        hr_h = 1;
        hr_l = 2;
        min_h = 3;
        min_l = 4;
        sec_h = 5;
        sec_l = 6;
        show_time ();
        setting_time = 1;
        set_time();
        while (1)
        {
                //blink_digit();
                if (tick)
                {
                        tick = 0;
                        show_time ();
                        Delay_ms (300);
                        Blink = 0;
                }
                check_bt ();
        }
}
void setup ()
{
        tick = 0;
//Digital output on PORTA
        CMCON = 0x07;
        //Input buttons + external clock
        TRISB = 0xB0;

        PORTB = 0x00;
        TRISA = 0x00;
        PORTA = 0x00;
        //Internal Clock 4MHz
        PCON.OSCF = 1;
        // Prescaler 1:1   external clock
        T1CON = 0x0F;

        PIE1.TMR1IE = 0;  // disable interupt to stop the clock

        INTCON = 0xC0;
        // Set GIE, PEIE
        TMR1L = LTMR1;
        TMR1H = HTMR1;
        // TMR1 starts at 0x0BDC = 3036 to make TMR1 counts to 62500 and
        // overclows in every 0.1 sec
        // Math: 1/500000*8*62500 = 0.1
        // 1/5000000 : time for 20MHz crystal (internal clock will be 20/4 = 5MHz)
        // 8: prescaler
        // 62500: TMR1 counts to 62500
        // Counting number of overflows to 10 will get 1 sec.

}

void show_time ()
{
        display (1);
        display (2);
        display (3);
        display (4);
        display (5);
        display (6);
}
void display (uns8 digit)
{
        switch (digit)
        {
                case 1 :
                PORTB = hr_h;
                Hr_port_h = 1;
                Hr_port_h = 0;
                break;
                case 2 :
                PORTB = hr_l;
                Hr_port_l = 1;
                Hr_port_l = 0;
                break;
                case 3 :
                PORTB = min_h;
                Min_port_h = 1;
                Min_port_h = 0;
                break;
                case 4 :
                PORTB = min_l;
                Min_port_l = 1;
                Min_port_l = 0;
                break;
                case 5 :
                PORTB = sec_h;
                Sec_port_h = 1;
                Sec_port_h = 0;
                break;
                case 6 :
                PORTB = sec_l;
                Sec_port_l = 1;
                Sec_port_l = 0;
                break;
        }
}
void blink_digit (uns8 digit)
{
        switch (digit)
        {
                case 1 :
                PORTB = 0xFF;
                Hr_port_h = 1;
                Hr_port_h = 0;
                Delay_ms (100);
                display (1);
                Delay_ms (100);
                break;
                case 2 :
                PORTB = 0xFF;
                Hr_port_l = 1;
                Hr_port_l = 0;
                Delay_ms (100);
                display (2);
                Delay_ms (100);
                break;
                case 3 :
                PORTB = 0xFF;
                Min_port_h = 1;
                Min_port_h = 0;
                Delay_ms (100);
                display (3);
                Delay_ms (100);
                break;
                case 4 :
                PORTB = 0xFF;
                Min_port_l = 1;
                Min_port_l = 0;
                Delay_ms (100);
                display (4);
                Delay_ms (100);
                break;
                case 5 :
                PORTB = 0xFF;
                Sec_port_h = 1;
                Sec_port_h = 0;
                Delay_ms (100);
                display (5);
                Delay_ms (100);
                break;
                case 6 :
                PORTB = 0xFF;
                Sec_port_l = 1;
                Sec_port_l = 0;
                Delay_ms (100);
                display (6);
                Delay_ms (100);
                break;
        }
}
void set_time ()
{

        i = 1;
        while (setting_time)
        {
                blink_digit (i);
                while (SET == 0)
                {
                        Delay_ms (5);
                        switch (i)
                        {
                                case 1 :
                                hr_h ++;
                                if (hr_h > 2)
                                {
                                        hr_h = 0;
                                }
                                break;
                                case 2 :
                                hr_l ++;
                                if (hr_l > 9)
                                {
                                        hr_l = 0;
                                }
                                if (hr_h >= 2 && hr_l > 3)
                                {
                                        hr_l = 0;
                                }
                                break;
                                case 3 :
                                min_h ++;
                                if (min_h > 5)
                                {
                                        min_h = 0;
                                }
                                break;
                                case 4 :
                                min_l ++;
                                if (min_l > 9)
                                {
                                        min_l = 0;
                                }
                                break;
                                case 5 :
                                sec_h ++;
                                if (sec_h > 5)
                                {
                                        sec_h = 0;
                                }
                                break;
                                case 6 :
                                sec_l ++;
                                if (sec_l > 9)
                                {
                                        sec_l = 0;
                                }
                                break;
                        }
                        while (SET == 0)
                        {
                                Delay_ms (5);
                        }
                }
                while (MODE == 0)
                {
                        Delay_ms (5);
                        i ++;
                        if (i > 6)
                        {
        sec_l--;
        TMR1H = 0x80;
        TMR1L = 0x00;
        PIE1.TMR1IE = 1;
        setting_time = 0;
                                break;
                        }
                        while (MODE == 0)
                        {
                                Delay_ms (5);
                        }
                }
        }
}
void check_bt ()
{
        myTimer = 0;
        if (setting_time == 0)
        {
                while (MODE == 0)
                {
                        Delay_ms (5);
                        myTimer ++;
                        if (myTimer > 200)
                        {
                                setting_time = 1;
                                myTimer = 0;
                                break;
                        }
                }
        }
        while (MODE == 0)
        {
                PIE1.TMR1IE = 0;
                //Stop clock
                Delay_ms (5);
                blink_digit (1);
        }
        set_time ();
}

I don't have the picture of the prototype as I haven't made it yet. But I have tested the circuit and firmware with proteus already.

--- Update ---
- The prototype of this updated version is done. Please see its photographs at 7-Segment PIC Digital Clock : The photographs
- The PCB is ready: please check out PCB for PIC Digital Clock

34 comments:

Nathan True said...

Seems to me like this is a very part-heavy project, without really having to be. I would think it would be possible to use row/column addressing and reverse parallel to get all 44 LED segments on something like 10 I/O pins, all without supporting hardware. The PIC16F628 has 15 I/O pins (1 I-only) with all accessories off, minus two for the crystal oscillator gives us three extra pins to use still, if we wanted to get lazy with the multiplexing. Buttons can be multiplexed with the display pins too using a few resistors.

punkky said...

Thank you for your comment. You are right this clock uses too many components but it was my intention. I made this clock to test my ideas and to learn Microcontroller. However, it is not easy to do led multiplexing with PIC16F627A/628 without using port expansion via shift register or something like that. Because, multiplexing 6x7-segment led requires 7 (for driving each segment)+ 6 (for commond cathode/anode) = 13 I/O pins and 2 pins are used for x-tal osc so I don't have pins for time setting buttons and for blinking second dots. Anyways, it's doable by multiplexing buttons and display as you suggested. I have done another updated version using multiplexing via 74HC595 shift register. I will post it soon, please come back again.
Thank you.

PANDILLA FELIZ said...

Hi, your project is very good, but I can't do work fine. in all digits show zeros. what is the error?.

sorry for my english but I'm from PERU.

thank you

punkky said...

The clock should display 12:34:56 when it's powered on. I am not sure what's cause the problem. Please make this 10-second counter http://picnote.blogspot.com/2008/11/10-second-counter.html for testing your equipment and wiring.

PANDILLA FELIZ said...

OK. thank you.

now All work fine!!!

PANDILLA FELIZ said...

what is the config of pic?

wachtdog on/off?
lvp on/off?

i don't know the config(the fuses)

punkky said...

Please check out http://picnote.blogspot.com/2008/11/10-second-counter.html for the config.
WDT : Off
LVP : Off
INTOSC_OSC_NOCLKOUT

zohaibmalik said...

Hi, please send me eagle sch and brd files Thanks.
Also, is 4543n is bcd to seven segment or any oyhrt buffer?

Paulito240 said...

This might help you out if you want to cut down on display drivers.

http://datasheets.maxim-ic.com/en/ds/ICM7218-ICM7228.pdf

PANDILLA FELIZ said...

hi. i want to know if i can used the pic 16f628A.

or is only with 16f627A or 16f628

thanks.

punkky said...

Yes, you can use the PIC16f628A. But, the PIC16f627 is a little bit cheaper.

Ucok Agus said...

hii nathan, your digital clock are seems like this http://www.youtube.com/watch?v=BT-aQeqnPdw
but your clock doesnt have real time sync to PC. Actually i'm trying to build the same stuff as in youtube link, but i'm in stuck to figure out the sync and multiplexing process. i already contact alphap8, but there is no answer yet.
Do you have suggestion how the process does and how to build it?

thanks b4
uaps at gmail dot com

Ucok Agus said...

oupss sorry , my last comment is for punkky not nathan.

thanks b4
uaps at gmail dot com

thaithien said...

Hi,Please send me your circuit simulated in Proteus.My email:
ngththien@gmail.com.Thanks very much!!!

Cristiano said...

No need of all those shift registers. You can drive 8 7-seg displays with only 9 pins. This is called charlieplexing.

Have a look at my project for an example.

http://tinyurl.com/nx56jo

joel said...

Dear sir,
your digital clock was so amazing. . Sir can you send me the materials that you have use for that clock right n0w please. This my email add bloodyrole.amate@gmail.com

ferdz_12345abuan said...

sir i am in a college in the philippines and i would like to know more about your digital clock cam you share to me the eagle file and the name of the materials including the name of the ic`s it an honor working with you sir this is my email: ferdz_14abuan@yahoo.com

JoJo said...

Regards

I was looking for digital clock and came across on this post. it help me. Can it be possible if you can send me the PCB layout so i can develop it.
Secondly it it possible to make modifify it to Alarm clock or Digital temp. meter
My E-Mail add is "sadeekey@hotmail.com"

Thank you
Regards

ll ρhö ll said...

Hi, im new in this! if you could help me out, im trying to program a pic 16f887, what i need is to control a servomotor, i have the program already, but it doesnt seem to work. my e-mail is llrholl@hotmail.com, thanx a lot

chiangyaw said...

hey, I'm new on this. I want to build a 7 segment clock display like yours but an additional hourly alarm system. Basically, the buzzer will buzz every hour but I have no idea where should i connect the buzzer to. Please reply me on this as soon as possible, my email is mist_rival@hotmail.com

naz said...

hi,
I would like to know how a 4-digit seven segment display can be interfaced with PIC16F877A using mplab IDE software.
Thank you.

MARKERICVON said...

Wow! Just the project that I was looking for! Please, can you email me the files for this project? also, if you have the multiplexed version too? Thank you very much! markdguzman@yahoo.com

naz said...

hi...
i couldn't figure out how a 4-digit display can b interfaced... I've worked on 3-digit seven segment display... I'll send you the program... u need to have MPlab IDE 7.5 for this program to work...

LU3EI said...

HI PUNKKY: DO YOU SEND MI THE .HEX FILE OF YOUR PROYECT. I´M NOT HAVE EXPERIENCE WHITH PIC COMPILE.
THANK YOU
Washington Rojas
LU3EI
Radioamateur station from La Plata, Buenos Aires, Argentina

kitt7974 said...

Hi Punkky~Can u send me the .hex to me? Currently i'm stuck at firmware file when im try to simulate at Protues. My email is kitt7974@hotmail.com.

Sorry for bad in english.

mai said...

hi, can you send me the .hex. i don't complete. thanks
my mail: vaa.admin@gmail.com

Guowei said...

Hi, is it possible ICD 2 use for MikroC programming? What programing hardware you are using?

°¨¨™¤¦ H . U . S . A . M ¦¤™¨¨° . said...
This comment has been removed by the author.
°¨¨™¤¦ H . U . S . A . M ¦¤™¨¨° . said...

Hello sir...
i am a university student,I study Engineering of Electronic Systems. sir i want to create this digital clock.would you mind give me a PCB layout of this circuit ? .please kindly request thanks sir ...
I like your posts sir , keep up ..

umax1989@hotmail.com

°¨¨™¤¦ H . U . S . A . M ¦¤™¨¨° . said...
This comment has been removed by the author.
Varsha Mandapalli said...

hello sir..
m studying electronics engineering..i need to do project on 'digital watch without microprocessor'..so can u please guide me with the apparatus,circuit etc.. and this is my first project..just mail me to my ID mandapallivarsha@gmail.com
thank u

Hacker Patel said...

Bro....its better to use multiplexing...becoz with very less components you can easily make it :) i have multiplexed 6 Digits..easily using PIC 16F877A :) i m too learning but it rocks...mux is the best...way...and professional too

jhavik said...

hey, i'm jhavik. i'm a student on electronics engineering, your project is amazing and i would like to make a project like yours can you please send me a digital circuit on email please.
bferndejhavik@gmail.com

Belal Ahmed said...

I am new in microcontroller. I do not understand your osc. because i was trying its but not works as per your osc 32.768khz setting in RB7 and RB6 but d clock pulse setting then works and blinking led. belal08mg@gmail.com