Timer 1, how to make a reliable Real Time Clock in 8-bit PIC

Timer 1, how to make a reliable Real Time Clock in 8-bit PIC

Measuring seconds comes really handy in many circuits. Executing tasks with demanding precision, such as a real time clock, requires an external oscillator (often called ‘crystal') of 32,768Hz. Such procedure creates an interrupt every second, which grants control to the microcontroller. Timer 1 as counter can work passively and it won't be dephased when the interrupt is attended. Fortunately, the setup is straightforward and similar to the Timer 0 tutorial. Follow this tutorial to learn how Timer 1 can be easily configured in the PIC microcontroller PIC16F684.

Background vector created by iconicbestiary – www.freepik.com

If you have been following the tutorials about timers, you may have already noticed that PIC16F628A was used previously. For Timer 1, the pins for programming (PGC and PGD) are shared with the 32KHz, thus complicating its use in a breadboard. Therefore, the PIC16F684 suits bests for this circuit.

Before reading this, you will need to know how to setup MPLAB IDE and how to connect the PICkit to the PIC microcontroller. If not, check them out first. Check out also another projects for beginners in 8-bit PIC microcontrollers.

Requirements for Timer 1

Components and Devices

In this tutorial, all the components are Through Hole.

  • PIC16F684: 1 unit.
  • LED, any color or size: 1 unit.
  • Capacitors, ceramic, 5% tolerance:
    • 15pF: 2 units.
  • 32,768Hz quartz oscillator: 1 unit.
  • Resistors, 1/2 or 1/4W, 5% tolerance:
    • 330Ω: 1 unit.
  • PIC6F684
  • 32768Hz quartz

Check out the commercial values of resistors and capacitors here.

PIC microcontroller

For this tutorial, I will use the 8-bit microcontroller PIC16F684. This one is the very first one that I learned to program. Very practical too. Be sure to select Through Hole or ‘TH' version. Surface Mounted won't fit in the breadboard.

PIC6F684
PIC6F684

Download the datasheet here. I recommend that you print in reduced A4 all the datasheet because it will serve you as quick reference.

Tools and Machinery

  • Breadboard: 1 unit.
  • AC/DC Power Adapter to 5V DC, with at least 500mA: 1 unit.
  • Jumper or UTP Wires: various.
  • Multimeter: 1 unit.

How is Timer 1 calculated?

On the tutorial about Timer 0, there is a further explanation about timers. Click here to read it first.

Timer 1 is a 16-bit counter. This means it can count from 0 to 65 535 (i.e. 2^16). Every time there is a overflow (from 65 535 to '65 536′), the Timer 1 flag will be set and a task or command will be executed.

To make a real time clock, a special crystal has to be connected to 2 pins of the microcontroller. Its value is 32 768 Hz exactly. Why such uncommon number?

Defining the Time required

The ‘unusual' oscillator of 32 768Hz and the 16-bit counter (65.536) are multiple of each other. Doing the math, it turns out that the actual time matches perfectly 1 second (or 2 seconds or 4 seconds, etc) without the need for extra calculation of compensation (as sometimes it is required in Timer 0).

Download the Spreadsheet

I highly recommend you to download the calculator of the Timer 1 for 8-bit PIC microcontrollers for free. Use the following form to complete. If you can't see it, follow this link.

The Equation

In order to know what number should go, let's use the Timer 1 Equation:

TMR1=65.536-\frac{t_{d}*f}{prescaler}

    \[ TMR1=65.536-\frac{t_{d}*f}{prescaler} \]

where td is the time desired, f is the clock frequency and the prescaler reduces the cycles to count. That being said, the desired time for any real time clock is 1 second (s) or 1000 miliseconds (ms). The clock frequency is 32 768Hz due to the oscillator and the prescaler is set to 1, so the input (clock cycle) and the output (counting up) of the oscillator remains the same.

In the spreadsheet you just downloaded, the value that the register TMR1 is displayed in the output column as decimal numbers. This value must be preloaded EVERY TIME. For 1 second, the value is 32768. But you can't just type TMR1=32768; a workaround must be done.

Timer 1 is divided into 2 8-bit registers: TMR1H and TMR1L. How do we divide the number, so it fits there? An easy way is to divide into different number systems, such as hexadecimal and binary.

If you would like to learn about number systems, check out these 2 links: Link 1 and Link 2.

Search an app on your smartphone or look for in a search engine for a converter between number systems; in other words, just type “HEX DEC BIN converter”. For example, I will use this calculator shown below. Select ‘Decimal' and type ‘32768' and click on ‘Convert'. You could either use the hexadecimal number or the binary number.

DEC HEX BIN Converter. Courtesy from Rapidtables.

If you decide to use hexadecimal, then write:

  • TMR1H=0x80;
  • TMR1L=0x00;

If you decide to use binary, then write:

  • TMR1H=0b10000000;
  • TMR1L=0b00000000;

Now that the time is defined, let's see how it's configured in this 8-bit PIC microcontroller.

Programming the Timer 1

Configuration Bits

On table 6-1, located in page 52, the registers associated with Timer 1 are displayed. Let’s start with the Option Register.

TABLE 6-1
TABLE 6-1 Registers associated with Timer1 in PIC16F684

Firstly, in the function config() the registers are configured to match the desired operation. To do so, go to page 51 in the datasheet to read about the ‘Register 6-1: T1CON – Timer1 Control Register’. The bit TMR1CS must be set in order to work with the external 32 768Hz oscillator. The bit nT1SYNC must be reset since the circuit doesn't require to be in sync with the internal 4MHz oscillator. The bits T1CKPS1 and T1CKPS0 must be reset in order to work with the prescaler on 1. Also, write the initial value for TMR1H and TMR1L, which was explain in previous section. The bits TMR1IF (flag), TMR1IE (enable) and TMR1ON (ON) must be reset, set and set respectively in order for the clock to start functioning properly.

//Timer 1 configuration
    TMR1CS = 1; //Select the external 32KHz oscillator
    T1OSCEN=1; //Enable the oscillator
    T1CKPS1=0; T1CKPS0=0; //Prescaler of Timer 1
    nT1SYNC=1; //There is no need to sync the external clock input for this circuit

    TMR1H=0x80; //TMR1 initial value for 1 second count
    TMR1L=0x00; //Needed?

    TMR1IF = 0; //Reset the interrupt flag
    TMR1IE = 1; //Set the enable flag
    TMR1ON = 1; //Turn on the counting in the Timer 1

Finally, the PEIE and GIE bits must be set, so the interrupts can work.

    PEIE=1; //Enable the peripheral interrupts
    GIE=1; //Enable all the interrupts

Now, it’s configured. But what should it do every time that the overflow occurs? Let’s deal with the interrupt.

Interrupt Function

If you haven’t read about the Interrupt Sources or how to handle Functions in C, check them out first.

Create the function called void __interrupt(void) interruptFunction(). From this place, all the interrupts are handled. Specify the enable bit and flag bit in order to enter the function. In addition, write the Routine_Tmr1() to specify where it should go next if Timer 1 requires the attention.

//Interrupt Sources
    if (TMR1IE && TMR1IF) { //If it has been enabled and if its flag has been set.
        TMR1IE = 0; //Disable Timer 1 interrupt
        Routine_Tmr1();
        TMR1IF = 0; //Once attended, erase the interrupt flag from Timer 1
        TMR1IE = 1; //Enable Timer 1 interrupt
    }

And now, let’s attend the interrupt of Timer 1 caused by the overflow. Let’s program a small LED blink, which changes between on and off every second. Furthermore, the values for TMR1H and TMR1L has to be reloaded each time.

void Routine_Tmr1() {
    PORTCbits.RC5=!PORTCbits.RC5;
    TMR1H=0x80;
    TMR1L=0x00;
}

Extra Coding

On MPLab, select ‘Production’ tab from the main menu and then clic ‘Set Configuration bits’. Select the following options:

// CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Detect (BOR enabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode is disabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

In the config() put the pin configuration (1 for everything except for RC5).

//Pin Configuration
    TRISA = 0b11111111; //RA7 to RA0.
    TRISC = 0b11011111; //RC7 to RC0.
    PORTA = 0; //Clean PORTA
    PORTC = 0; //Clean PORTC

Don’t forget to add the While(1) in the Main function to make it run forever!

while(1) {

}

Download the code of Timer 1

If you would like to see and read the whole code through, enter your name and e-mail in the form below to download the project. I promise that I won’t send you spam; just relevant content to the blog. If you don’t see any form below, please click here.

Schematic of Timer 1

For reference, here is the schematic used for the Timer 1.

Schematic of Timer 1 in PIC16F684
Schematic of Timer 1 in PIC16F684

Picture of Timer 1

This is how the Timer 1 looks like in the breadboard.

Picture of Timer 1 in a PIC6F684

Testing Timer 1

After programming the PIC microcontroller (follow this link if you don’t know how), the LED seems to turn on for one second and then it turns off for one second; afterwards, this cycle repeats itself. I checked it with a stopwatch and it certainly works as intended.

Did you notice it? The While(1) function is empty. The real time clock is working only by interruptions. There is no need to add here extra code in the Main function.

Going further

More than 1 second clock.

What if you require to execute a timer every 2 or 8 seconds? Then, an easy way will be to change the prescaler because the larger it is, the longer it will take to count. Another way would be to reduce or eliminate any values assigned to TMR1H and TMR1L.

Less than 1 second clock.

On the other hand, Timer 1 can actually count less than a second if TMR1 is filled higher. For instance, to achieve an execution every half a second, you should assign TMR1H and TMR1L to 49 152 instead of 32 768.

Conclusion

To summarize, Timer 1 was configured to execute a real time clock. The code was programmed into the PIC16F684 successfully and tested. A video and a foto is attached to demonstrate the functioning.

Timer 1 is helpful for applications and circuits that require precise timing. A real time clock is one example, however there are more circuits like alarms, monitors and sensors that could benefit from timers that executes in minutes, rather than in milliseconds. Soon I will write how to use it for such purpose.

The next tutorial will be about using the Timer 0 and Timer 1 combined in two circuits: A traffic light and 7-segment numeric display. Stay tuned for this future post.

Resources

  • PIC16F628A Datasheet. Link.
  • PIC16F628A won't program with crystal connected. Link.
  • Target Device ID (0x0) is an Invalid Device ID. Please check your connections to the Target. Link.

You have reached this far!

Thank you for reading the blog post. Your comments and suggestions are welcomed. At the bottom of this page, leave a message or just say hi! The whole team of techZorro will appreciate it. Don't forget to share it on social media as well.

techZorro’s Index of Content

Click on the following link to browse likewise content in the blog in techZorro. This index will help you see what you are looking for in a bird’s eye view.

techZorro's Newsletter!

If you enjoyed this blog post, please subscribe to techZorro’s newsletter so you don’t miss any future blog posts!

techZorro's Index of Content

Keep Reading!

2 Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.