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++;
   }
}


2 comments:

Alvarito said...

I really like your clock , My question is , Can you upgrade it with the DS1307 and sell me a copy of the software , I want to build it, it´s great Thanx in advance

TinLethax said...

I cant compile a code ช่วยหน่อกับบบบบ ผมมือใหม่ยรแ ส่วนมากผมใช้arduino
48 396 Invalid declarator expected'(' or identifier LTP_305clock.c
131 315 Invalid expression LTP_305clock.c
131 402 ; expected, but 'data' found LTP_305clock.c
131 424 '}' expected ';' found LTP_305clock.c
132 424 '}' expected '}' found LTP_305clock.c
193 396 Invalid declarator expected'(' or identifier LTP_305clock.c
193 310 Constant expression required LTP_305clock.c
193 374 Array dimension must be greater than 0 LTP_305clock.c
194 424 '}' expected '}' found LTP_305clock.c
195 424 '}' expected '}' found LTP_305clock.c
297 315 Invalid expression LTP_305clock.c
297 402 ; expected, but 'data' found LTP_305clock.c
297 424 '}' expected ';' found LTP_305clock.c
313 424 '}' expected '}' found LTP_305clock.c
317 312 Internal error '' LTP_305clock.c
0 102 Finished (with errors): 27 ÁÕ.¤. 2017, 12:40:31 LTP_305clock.mcppi
mikroC v.7.1.0 pic