How to make an accurate timer with PIC16F84A

Microcontroller Topics
Post Reply
User avatar
SevenZero
Major
Major
Posts: 263
Joined: Sun Nov 01, 2009 8:37 pm

How to make an accurate timer with PIC16F84A

Post by SevenZero » Sat Oct 20, 2012 1:45 am

The first important is to create 1 second time base. The oscillator for the project is 4MHz, the time that the timer0 overflow is Fosc/4/prescaler/256. The minimum prescaler is 1:2, so timer0 will overflow every 512 us. To have 1 second, the timer0 would have to overflow 1953 times. The GIE bit and T0IE bit of INTCON register must be set to enable timer0 interrupt, also PS2:PS0 bit of OPTION_REG register is 000 to set up prescaler 1:2

Code: Select all

INTCON.GIE = 1; //Enable all unmasked interrupts.
INTCON.T0IE = 1; //enable timer0 interrupt.
OPTION_REG = 0x00; //timer0 prescal 1:2
inside the interrupt routine, a counter variable will increase every time that the timer0 interrupt occur. When the counter is count to 1953, a onesec variable flag is set for next proceed.

Code: Select all

void interrupt(){

counter++;
if(counter >= 1953) onesec = 1; // set a 1 second flag

}
For this project, a Start/Stop switch(SW4) is toggle ON/OFF operation. when it's ON, the display will count down and will stop when it's zero or SW4 is press to stop operation. There are 2 switches for setting up time( SW2 and SW3 ), one for increasing second and another for increasing minute. You also can save current time into EEPROM and recall it later.

Because PIC16F84A does not have enough I/O ports; a 74164 serial-in, parallel-out is needed to expand for display. Each individual segment cathode is connected to separate 330 ohm current limiting resistors while the common anode of each display is connected to Collector pin of a PNP transistor. Data is send from RA1 pin of MCU to A pin of 74164 ; and RA0 pin is connected to CLK pin of 74164 to send shift clock signal. The figure below shown 74164 logic diagram and truth table.
1.JPG
1.JPG (60.44 KiB) Viewed 3080 times
2.JPG
2.JPG (196.47 KiB) Viewed 3080 times
3.JPG
3.JPG (140.78 KiB) Viewed 3080 times
Press SW4 switch to on - off the timer.

Press SW3 switch to increase second from 0 - 59.

Press SW2 switch to increase minute from 0 - 99.

Press and release SW1 switch to recall time from EEPROM. Press and hold SW1 for 2- 3 second for store current time into EEPROM.

Code: Select all

#define sClock PORTA.F0
#define sData  PORTA.F1
#define OutPut PORTA.F2


char onesec = 0;
int counter = 0;
char key_press = 0;
char On_status = 0;
char Digit_map[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
char current_sec = 0;
char current_min = 0;
char first_digit, second_digit;
char third_digit, forth_digit;
char timeout = 0;
void interrupt(){

     if(INTCON.T0IF == 1) {
           counter++;
           if(counter >= 1953) {
                  onesec = 1;
                  counter = 0;
                  if(PORTB.F4 == 0) {
                         timeout ++;
                         onesec = 0;
                  }
           }
      if (onesec == 1){
                 onesec = 0;
                 if (current_sec == 0) {
                    if(current_min > 0) {
                          current_sec = 59;
                          current_min --;
                          }
                     else current_min = 0;
                     }
                 else current_sec --;

                 first_digit = current_sec % 10;
                 second_digit = current_sec/10;
                 third_digit =  current_min % 10;
                 forth_digit =  current_min / 10;
              }
           INTCON.T0IF = 0; // clear interrupt flag
     }


}
// -----  Shift Out function --------------------------
void Shift_OutMSB (char sd) {
     char i;
     char mask = 128;
     for (i=1; i<=8; i++){
         if (!(sd&mask)) sData = 0; else sData = 1;
         sClock= 1;
         delay_us (1);
         sClock = 0;
         mask = mask >> 1;
     }
}

void delay(){
     delay_ms(5);
}
void delay20ms(){
     delay_ms(20);
}
void time_display(){
     Shift_OutMSB (Digit_map[first_digit]);
     PORTB.F0 = 0;
     delay();
     PORTB.F0 = 1;
     Shift_OutMSB (Digit_map[second_digit]);
     PORTB.F1 = 0;
     delay();
     PORTB.F1 = 1;
     Shift_OutMSB (Digit_map[third_digit]);
     PORTB.F2 = 0;
     delay();
     PORTB.F2 = 1;
     Shift_OutMSB (Digit_map[forth_digit]);
     PORTB.F3 = 0;
     delay();
     PORTB.F3 = 1;
}

void key_check(){
char temp_sec, temp_min;

     if(PORTB.F7 == 0) {
            //delay_ms(10);
            if (On_status == 1) {
            On_status = 0;
            OutPut = 0;
            INTCON.T0IE = 0; // disable interrupt timer
            }
            else {
            On_status = 1;
            OutPut = 1;
            TMR0 = 0;
            INTCON.T0IE =1; // enable interrupt timer
            }
            while (PORTB.F7 == 0) { time_display(); }
     }
     
     if(PORTB.F6 ==0) {
            if (On_status == 0){
               if (current_sec < 59 ) current_sec++;
               else current_sec = 0;
               first_digit = current_sec % 10;
               second_digit = current_sec/10;
               while (PORTB.F6 == 0) { time_display(); }
            }
     }
     
     if(PORTB.F5 ==0) {
            if (On_status == 0){
               if (current_min < 99 ) current_min++;
               else current_min = 0;
               third_digit = current_min % 10;
               forth_digit = current_min/10;
               while (PORTB.F5 == 0) { time_display(); }
            }
     }
     if(PORTB.F4 == 0) {
            On_status = 0;
            OutPut = 0;
            INTCON.T0IE = 0; // disable interrupt timer
            temp_sec = Eeprom_Read(0x00);
            delay20ms();
            temp_min = Eeprom_Read(0x01);
            delay20ms();
            TMR0 = 0;
            INTCON.T0IE =1; // enable interrupt timer
            while (PORTB.F4 == 0) { time_display(); }
            INTCON.T0IE = 0; // disable interrupt timer
            if(timeout > 1) {
                     timeout = 0;
                     EEprom_Write(0x00, current_sec);
                     delay20ms();
                     EEprom_Write(0x01, current_min);
                     delay20ms();
            }
            else {
                 current_sec = temp_sec;
                 current_min = temp_min;
                 timeout = 0;
            }
            first_digit = current_sec % 10;
            second_digit = current_sec/10;
            third_digit =  current_min % 10;
            forth_digit =  current_min / 10;

     }
     
}

void main() {

     TMR0 = 0;
     INTCON.GIE = 1;  //Enable all unmasked interrupts.
     INTCON.T0IE = 0;  //disable timer0 interrupt.
     OPTION_REG = 0x00; //timer0 prescal 1:2
     INTCON.RBIF = 0;  // clear interrupt onchange flag
     PORTB = 0xFF;
     TRISB = 0xF0; //PORTB4-7 = inputs, 0-3 = output.
     TRISA = 0; // PORTA = output.
     PORTA = 0;
     first_digit = current_sec % 10;
     second_digit = current_sec/10;
     third_digit =  current_min % 10;
     forth_digit =  current_min / 10;
     while(1){
              key_check();
              time_display();
              if(current_min == 0 & current_sec == 0){
                      OutPut = 0;
                      On_status = 0;
                      INTCON.T0IE = 0; // disable interrupt timer
              }
     }

}
Post Reply

Return to “Microcontrollers”