Sunday, September 28, 2008

Led Dot Matrix Scrolling Sign

Starting from the 5x7 led dot matrix clock, now, the Led Dot Matrix is one of my favorite topics for my projects. I have some led dot matrix projects in progress. They are all watch/clock related projects. Now, I am thinking that using led dot matrix to display only numbers is just a waste. A scrolling sign would be a nice project to utilize all of the power of led dot matrix. The above photo is a Mini Scrolling LED Sign. It's available as a kit from ElectronicKits.com. I think it's a great kit to start with. This scrolling sign has 96 different characters, and can store messages up to 80 characters long.

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


Tuesday, September 16, 2008

Schematic of the 5x7 Led Dot Matrix Clock

Schematic of the 5x7 Led Dot Matrix Clock
The above image is the schematic of the 5x7 led dot matrix digital clock. It includes a custom made component in Eagle, small 5x7 led dot matrix. However, this schematic is also working for any size of the 5x7 led dot matrix.I will post the detail about the firmware later.
-- updated 29 Nov 2009 ---
There is an error in the schematic, the MCU in the schematic is PIC16F887 (not PIC16F877)which has an internal oscillator so you don't need the external oscillator for the MCU. But you still need the 32.768 KHz for timebase.

Sunday, September 7, 2008

Just came back from Phuket

I arrived at my home about 24:04 last night, very tried.
Tonight, I have to work on an e-Marketplace report. I will be very busy in the next couple weeks so the detail about PIC projects will be posted after that.