Showing posts with label MikroC. Show all posts
Showing posts with label MikroC. Show all posts

Wednesday, March 11, 2009

Setting Internal Oscillator for PIC16F627A

I love to use PIC16F627A and PIC16F628 because they come with internal oscillators. That means I can make a project with lower component count (without 1 crystal and 2 load capacitors). The project setting of MikroC for using internal oscillator of the PIC16F627A shows below:
Setting MikroC for Internal Oscillator

Tuesday, January 20, 2009

2-digit BCD to decimal conversion

Now, I'm working on the full feature clock using DS1307. In the clock, I use many BCD to decimal (bcd2dec) and decimal to BCD conversions for reading and setting time of the DS1307 RTC. MikroC provides buit-in functions for these conversions but the functions consume modest amount of MCU memory space. I have came up with simple functions that consume less memory for doing 2-digit BCD to decimal and the reverse conversions.

2-digit BCD to Decimal conversion function:
unsigned short myBcd2Dec(unsigned short bcd){
return ((bcd >> 4)*10+(bcd & 0x0F));
}

Example: myBcd2Dec(01000101) = 45

2-digit Decimal to BCD conversion function:
unsigned short myDec2Bcd(unsigned short dec){
return (((dec/10)<<4)(dec%10));
}

Example: myDec2Bcd(45) = 01000101

Wednesday, December 31, 2008

6 Digits 7-Segment LED Multiplexing using a Shift Register

Multiplexing technique can reduce number of needed I/O pins of the MCU as I have explained in 'LED 7-Segment Multiplexing' and '6 Digits LED 7-Segment Multiplexing'. In those posts, I used 13 I/O pins for driving 6 digits LED 7-Segment. However, the PIC16F627A and PIC16F628 have only 15 usable I/O pins that include 2 pins for external 32.768KHz oscillator. So, there is no pin left for time setting buttons. I can change to the PIC that has more I/O pins, but I don't think it's a good solution. From my searches, I can overcome this I/O pins shortage problem by using shift register to expand the MCU I/O pins.

The concept is very similar to led dot matrix driving technique. Each digit is multiplexed via a shift register 74HC595 which is required 3 pins of the MCU. Each segment of the 7-segment display is driven by PORTA of the PIC16F628. As a result, the required pins for driving 6-Digit 7-Segment display are just 3+7 = 10 pins!. With this configuration, there are 3 I/O pins that are free for time setting buttons and driving blinking second LEDs.

I use TMR2 module for scanning digits. TMR2 is an 8-bit timer which overflows every 256 (0xFF) counts. It's known that the refresh rate above 50Hz would be enough for human's eyes to see the display without recognizing the flickering. If I set TMR2 with 1:8 Prescaler (T2CON = 0x3C), the multiplexing frequency will be 81.3Hz (4MHz/4/256/8/6 = 81.3Hz) which is enough for flicker free display.

PORTA is used to drive each segment of the 7-segment displays. However, I have to skip the RA5 as it's a MCLR pin and it can be only input pin. So, my 7-segment digit mask is different then the normal 7-segment digit mask.

my PORTA 7-segment digit mask : {0x5F, 0x06, 0x9b, 0x8f, 0xC6, 0xCd,0xDD, 0x07,
0xDf, 0xCf}
Normal 7-segment digit mask : {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f} for number 0-9 respectively.


Below is the example schematic of 999999-second counter using the PIC16F627A or PIC16F628 and a shift register. I will not implement a clock with this configuration as I need more free MCU pins for driving Alarm buzzer and other things.

pic16F627a PIC16F628 74HC595 LED 7-segment multiplex

The source code for 999999-second counter in MikroC is listed below

//PIC16F627A or PIC16F628
//4MHz Internal OSC
//MUX by using Shift Register 595
// Critical parameters:
// Delay, Postscaler, Prescaler
// Low delay + High Prescaler
// 03/11/2008
// punkky@gmail.com
#define SH_CP PORTB.F0
#define DS PORTB.F1
#define ST_CP PORTB.F2
// 7-Segment code is skipping RA5, so the code is not as normal 7-segment coding
unsigned short number [10] = {
    0x5F0x060x9b0x8f0xC60xCd, 0xDD0x07,
    0xDf, 0xCf
};
unsigned short digit [6] = {
    000000
};
unsigned short i;
unsigned short n;
unsigned short counter;
unsigned short tick;
unsigned short shift_register;
unsigned short x1;
unsigned short x2;
unsigned short x3;
unsigned short x4;
unsigned short x5;
unsigned short x6;
void interrupt ()
{
    if (PIR1.TMR2IF)
    {
        PIR1.TMR2IF = 0;
        if (counter == 5)
        {
            //Shift data
            DS = 0;
            //Store data
            SH_CP = 1;
            SH_CP = 0;
            Delay_us (250);
            counter = 0;
        }else
        {
            //Shift data
            DS = 1;
            //Store
            SH_CP = 1;
            SH_CP = 0;
            Delay_us (250);
            counter ++;
        }
        ST_CP = 1;
        ST_CP = 0;
        PORTA = 0x00;
        PORTA = number [digit [counter]];
    }
    if (PIR1.TMR1IF)
    {
        TMR1H = 0x80;
        PIR1.TMR1IF = 0;
        tick = 1;
        x6 ++;
        if (x6 > 9)
        {
            x6 = 0;
            x5 ++;
            if (x5 > 9)
            {
                x5 = 0;
                x4 ++;
                if (x4 > 9)
                {
                    x4 = 0;
                    x3 ++;
                    if (x3 > 9)
                    {
                        x3 = 0;
                        x2 ++;
                        if (x2 > 9)
                        {
                            x2 = 0;
                            x1 ++;
                            if (x1 > 9)
                            {
                                x1 = 0;
                            }
                        }
                    }
                }
            }
        }
    }
}
void main ()
{
    //Digital I/O for PORTA
    CMCON = 0x07;
    TRISA = 0x00;
    PORTA = 0x00;
    TRISB = 0x00;
    PORTB = 0x00;
    //Internal Clock 4MHz
    PCON.OSCF = 1;
    counter = 0;
    // Set GIE, PEIE
    INTCON = 0xC0;
    //1:8 post scaler
    T2CON = 0x3C;
    // enable interupt
    PIE1.TMR2IE = 1;
    T1CON = 0x0F;
    //Initial value TMR1: 0x8000
    TMR1H = 0x80;
    TMR1L = 0x00;
    // enable interupt
    PIE1.TMR1IE = 1;
    //Data
    DS = 0;
    //Store
    SH_CP = 0;
    ST_CP = 0;
    x1 = 0;
    x2 = 0;
    x3 = 0 ;
    x4 = 0;
    x5 = 0;
    x6 = 0;
    while (1)
    {
        if (tick)
        {
            tick = 0;
            digit [0] = x1;
            digit [1] = x2;
            digit [2] = x3;
            digit [3] = x4;
            digit [4] = x5;
            digit [5] = x6;
        }
    }
}

Wednesday, November 12, 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

Thursday, November 6, 2008

10-Second Counter

I have made a 10-Second Counter by using a PIC16F627a and a CD4543 BCD to 7-Segment decoder. This circuit and source code are just a demonstration of using MCU to drive an LED 7-Segment Display via CD4543. The 7-Segment displays from 0 to 9 and the number will roll over to 0 again. The interval between change is 1 second. So, this circuit counts 10 seconds between the roll over. I use TIMER1 module and 32.768KHz crystal to make 1 second timebase (see Clock with 32.768KHz Crystal for more info ).

The schematic of the 10-Second counter
Schematic of 10-Second counter
Project setting of MikroC for using internal oscillator of the PIC16f627a.
Setting MikroC for Internal Oscillator

The firmware is written in MikroC and you can find it below.

//PIC16F627A
//4MHz Internal OSC
// One Digit Counter
// 06/11/2008
//Punkky
unsigned short counter;
unsigned short tick;
void interrupt ()
{

        PIR1.TMR1IF = 0;        // clears TMR1IF
        TMR1H = 0x80;
        tick = 1;
}

void main(){
        CMCON = 0x07;   //Digital I/O for PORTA
  TRISA = 0x00;
  PORTA = 0x00;
  TRISB = 0x00;
  PORTB = 0x00
  T1CON = 0x0F
         
  // Prescaler 1:1   external clock 
  PIE1.TMR1IE = 1;  // enable interupt to start the clock 
  INTCON = 0xC0;   // Set GIE, PEIE 
  TMR1L = 0x00
  TMR1H = 0x80
  PCON.OSCF = 1//Internal Clock 4MHz
  //PCON.OSCF = 0; //Internal Clock 48KHz doesn't work well
  counter = 0;
  tick = 0;
  PORTA.F0 = 1// Enable 4345 BCD to 7-Segment
  while(1){
    if(tick){
       tick = 0;
       counter++;
       PORTB = counter;
       if(counter>9){
       counter = 0;
    }
   }
  }
}

Wednesday, October 22, 2008

MikroC "Hello World!" LCD example


Just an example of using MikroC to make a simple "Hello World!" PIC Microcontroller LCD project. The MCU is PIC16F877A (of course, it can be PIC16F887). The LCD display word "Hellow World!" on the first line and counting number on the second line. The image above is a screen capture of a simulation. I use the Proteus 7 VSM simulator to simulate my programs.

The source code in MikroC
//Test LCD
char *text = "Hello World!";
char mytext[3];
int i;
void main() {
// pic16f887
// ANSEL = 0x00; //Digital I/O for PORTA
// ANSELH = 0x00; //Digital Input for PORTB

// pic16f877A

CMCON = 0x07; //Set PORTA to Digital input
TRISB = 0; // PORTB is output
TRISA = 0x07; //PORTA as the input/output 0000 0111
i=0;
Lcd_Init(&PORTB); // Initialize LCD connected to PORTB
Lcd_Cmd(Lcd_CLEAR); // Clear display
Lcd_Cmd(Lcd_CURSOR_OFF); // Turn cursor off
Lcd_Out(1, 1, text); // Print text to LCD, 2nd row
while(1){
while(i<200){
IntToStr(i,mytext);
Lcd_Out(2,1,mytext);
Delay_ms(500);
i++;
}

i=0;
}

}


Tuesday, October 21, 2008

MikroC for PIC Microcontroller Programming

MikroC user interface
As a beginner in PIC Microcontroller, MikroC is my favorite compiler for my Microcontroller projects. I know 'C' already so it's very easy to use MikroC no complex settings involved. MikroC provides a lot of useful and handy libraries for example, LCD interface , UART, I2C, SD card access and many more. Good new, there is a free lite version that can compile code upto 2Kbyte which is enough for beginner projects. The commercial version is also affordable. Of course, I am not selling MikroC :) I just want to share information. Please visit their site for more info: http://www.mikroe.com/

MikroC sample for sending "Hello World!" to LCD

Lcd_Init(&PORTB); // Initialize LCD connected to PORTB
Lcd_Cmd(Lcd_CLEAR); // Clear display
Lcd_Cmd(Lcd_CURSOR_OFF); // Turn cursor off
Lcd_Out(1, 1, "Hello World!");

Friday, September 26, 2008

Source Code for one chip 5x7 led dot matrix clock

As promised, listed below is the source code in MikroC for the 5x7 Led Dot Matrix Clock. The free demo version of MikroC can compile this code without any problem. Of course, the code is just for educational purpose only and use it with your own risk. The explanation about the source code will come later.
Setting time
- Press and hold MODE button until the digits blink
- The blinking digits are the hour is being set
- Press SET button to count up the hour
- When get the right hour, press MODE button to confirm hour setting
- Now the minute digits are blinking and ready to be set
- Press SET button to count up the minute
- When get the right minute, press MODE button to confirm minute setting and the second will be set to 0 automatically
- Now, the clock is set and the clock is running

Have fun!!!

Next improvements:
1. Using DS1307 as the time base will improve the clock accuracy and backup battery is also a nice feature of the DS1307
2. Dot matrix will be scanned and updated via interrupt routine to give the PIC more free time for doing something else

== Updated on 29 Nov 2009 ===
This firmware is written for The 5x7 Dot matrix Cathode Row. If you use Anode Row you have to make change to make_dotmatrix() by inverting the output PORTB and PORTD
===========================

//One 5x7 Led Dot Matrix Clock
// PIC16F887
// I will use DS1307 as the RTC for the next improvement
// punkky@gmail.com
// 26 Sep 2008

#define MYMODE PORTA.F0
#define SET  PORTA.F1

//External OSC 32.768KHz
#define HTMR1    0x80
#define LTMR1    0x00

//Constants for 4MHz Internal Clock 
#define PAUSE_TIME 40
#define SCROLL_TIME_DELAY 60
#define HM_PAUSE_TIME  8

#define DTime 200

//Cursor Positions
#define HR_H_POS  0
#define HR_L_POS  0
#define DOT_1_POS 32
#define MIN_H_POS 12
#define MIN_L_POS 12
#define DOT_2_POS 56
#define SEC_H_POS 64
#define SEC_L_POS 72
//5x7 font
//Vertical scan ,  Little endian order
const unsigned char char2[][4]={
{0x1F,0x11,0x1F,0x00},   //0
{0x09,0x1F,0x01,0x00},
{0x17,0x15,0x1D,0x00},
{0x11,0x15,0x1F,0x00},
{0x1C,0x04,0x1F,0x00},
{0x1D,0x15,0x17,0x00},
{0x1F,0x15,0x17,0x00},
{0x10,0x10,0x1F,0x00},
{0x1F,0x15,0x1F,0x00},
{0x1D,0x15,0x1F,0x00},   //9
{0x0E,0x0E,0x0E,0x00},  //Comma1
{0x04,0x0E,0x04,0x00}   //Comma2
};

unsigned char output[8];
unsigned char data[40];
unsigned char ptr;
unsigned char base_ptr;
unsigned char result_ptr;
unsigned char pp;
unsigned char pause_cnt;
unsigned char hr_pause_cnt;
unsigned char min_pause_cnt;
unsigned short counter;
unsigned short sec_h;
unsigned short sec_l;
unsigned short min_h;
unsigned short min_l;
unsigned short hr_h;
unsigned short hr_l;
unsigned short tick;
unsigned short num;
unsigned short i;
unsigned short j;
unsigned short time[8];
unsigned short setting_time;
unsigned short change_MYMODE;
void check_bt();
void button_fn(unsigned short param1unsigned short pos1unsigned short pos2);
void make_dotmatrix();

void interrupt() { //Internal clock
    PIR1.TMR1IF = 0;          // clears TMR1IF
    TMR1H = HTMR1;  //Set only high byte
    tick  = 1;                   // increment counter
}
void update_time();
void make_time();
void fill_data();
void show_digit(unsigned short pos);
void scroll();
void pause_digit(unsigned short position,unsigned short pause_delay);

unsigned short shift_register;
void main(){
  setting_time = 0;
  change_MYMODE = 0;
  ANSEL = 0x00;    //Digital I/O for PORTA
  TRISA = 0x03;
  PORTA = 0x03;
  TRISB = 0x00;
  PORTB = 0xFF;
  TRISC = 0x0E;
  TRISD = 0x00;
  PORTD = 0x00;
  ANSELH = 0x00//Digital Input for PORTB

  OSCCON = 0x65 ; //pic16f887 : 0110 0101, Internal Osc at 4MHz for lowest power consumption

  counter = 0;
  shift_register = 0x01;
  hr_h = 1;
  hr_l = 2;
  min_h = 3;
  min_l =4;
  sec_h = 0;
  sec_l = 0;
  tick = 0;
  fill_data();
  pause_cnt =0;
  hr_pause_cnt = 0;
  min_pause_cnt = 0;
//TMR1 setup
     T1CON =  0x8F;                      // 887 TMR1 Prescaler 1:1   external clock
     INTCON = 0xC0;                    // Set GIE, PEIE
     TMR1H = 0x80;
     TMR1L = 0x00;
     Delay_ms(10); // Delay for setting up TMR1
     PIE1.TMR1IE = 1;                  // enable interupt
     tick =0;
  while(1){
   scroll();
  }

}

void show_digit(unsigned short pos){
          for(i=0;i<8;i++){
           output[i] = data[i+pos];
          }
}

void update_time(){
    if(tick){
        tick =0;
        sec_l++;
        make_time();
        fill_data();
     }
}

void make_time(){
        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;
            if(setting_time == 0){
               min_h++;
            }
        }
        if(min_h>5){
            min_h = 0;
            if(setting_time == 0){
                hr_l++;
            }
        }
        if(hr_l>9){
            hr_l = 0;
            if(setting_time == 0){
             hr_h++;
            }
        }
        if(hr_h >2){
            hr_h = 0;
        }
        if(hr_h >=2 && hr_l>3){
           if(setting_time == 0){
              hr_h = 0;
           }
           hr_l = 0;
        }

}
void fill_data(){
        time[0] = hr_h;
        time[1] = hr_l;
        time[2] = 10;
        time[3] = min_h;
        time[4] = min_l;
        time[5] = 11;
        time[6] = sec_h;
        time[7] = sec_l;
        for(i = 0;i<8;i++){
          for(j=0;j<4;j++){
           data[j+4*i] = char2[time[i]][j];
          }
        }
}

void button_fn(unsigned short param1unsigned short pos1unsigned short pos2){
      for(;;){
        if(SET == 0){
          Delay_ms(10);
          while(SET == 0);
          Delay_ms(10);
          switch (param1){
            case 1hr_h++; break;
            case 2hr_l++; break;
            case 3min_h++;break;
            case 4min_l++;break;
          }

          make_time();
          fill_data();
          show_digit(pos1);
        }
        if(MYMODE == 0){
          Delay_ms(10);
          while(MYMODE == 0);
          Delay_ms(10);
          ifparam1 == 4){
            setting_time = 0;
            ptr = 0;
            base_ptr = 0;
          }else{
            show_digit(pos2);
          }
          break;
        }
        make_dotmatrix();
        Delay_ms(1);
      }

}
void check_bt(){
    while(MYMODE == 0){
      Delay_ms(10);
      for(i=0;i<100;i++){
        for(j=0;j<10;j++){
          make_dotmatrix();
          Delay_ms(1);
          if(MYMODE != 0){
            setting_time = 0;
            change_MYMODE = 1;
            break;
          }
        }
      }

      while(MYMODE == 0){   // Set Hr high
          setting_time = 1;
          show_digit(HR_H_POS);
          make_dotmatrix();
      }
      if(change_MYMODE){
         ptr=8;
         base_ptr = 0;
         change_MYMODE = 0;
      }
    }
    if(setting_time){
      INTCON.GIE = 0 ;        //Stop time counting

      button_fn(1HR_H_POSHR_L_POS);
      button_fn(2HR_L_POSMIN_H_POS);
      button_fn(3MIN_H_POSMIN_L_POS);
      button_fn(4MIN_L_POS0);

      //Reset timer1
      TMR1L = LTMR1;
      TMR1H = HTMR1;
      INTCON.GIE = 1 ;                        // start clock
      sec_l =0;
      sec_h =0;
      tick=0;
      make_time();
      fill_data();
   }
}

void pause_digit(unsigned short positionunsigned short pause_delay){
           if(base_ptr == position){
        if(pause_cnt<pause_delay){
            base_ptr--;
            pause_cnt++;
         }else{
            base_ptr = position+1;
            pause_cnt=0;
         }

     }

}
void scroll(){
   ptr = 0;   //start pointer
   base_ptr = 0;
   while(base_ptr<41){
      result_ptr = (base_ptr+ptr)%40;
      output[ptr] = data[result_ptr];
      ptr++;
      if(ptr == 8){
                   ptr = 0;
                   base_ptr++;
                   //Sec pause
                   
             pause_digit(25,PAUSE_TIME);
                   //Min pause
                  
                   pause_digit(13,HM_PAUSE_TIME);
                   //Hr pause
                  
                   pause_digit(1,HM_PAUSE_TIME);
                  

      }
      for(pp=0;pp<SCROLL_TIME_DELAY;pp++){
            update_time();
            make_dotmatrix();
      }

      update_time();
      check_bt();
      make_dotmatrix();
  }
}
void make_dotmatrix(){
   if(counter == 7){
        PORTB =    output[counter];   //sent font data to PORTB
        Delay_us(DTime);
        PORTB = 0x00//Turn off dots
        shift_register = 0x01;
        PORTD = ~shift_register;             //sent scan data to PORTD
        counter = 0;
   } else{
        PORTB =   output[counter];
        Delay_us(DTime);
        PORTB = 0x00//Turn off dots
        shift_register = shift_register << 1;
        PORTD = ~shift_register;
        counter++;
   }
}