What are the features of 8bit and 16bit timers in PIC18F MCU
Solution
The program begins by Setting up TIMER0. The TIMER0 can be configured using a single register calledT0CON which stands for TIMER0 control register. The details of each bit is given below.
1
1
1
1
1
1
1
1
7
6
5
4
3
2
1
0
BIT7 – TMR0ON: Timer0 On, set this to 1 to start the timer.
BIT6 – T08BIT: =1 for 8 bit mode and =0 for 16 bit mode.
BIT5 – T0CS: Timer0 clock source. =1 for T0CLK pin input i.e. counter mode. Set to 0 for internal instruction clock.
BIT4 – T0SE: Used in counter mode only. Please see datasheet for details.
BIT3 – PSA: Prescaler Assignment. Set this to 0 to assign prescaler or 1 to by pass it.
BIT2 to BIT0 – PS2 to PS0: Prescaler Division factor select
So as per our requirement we have set the bits of T0CON register on program startup. This configures the TIMER0 as we require. Lets have a look at the code that initializes the TIMER0
As you can see in the above code, first we set up the bits of T0CON then we enable Timer Overflow interrupt, after that peripheral interrupt and finally enable interrupt globally. PEIE i.e. Peripheral Interrupt bit can enable or disable all peripheral interrupt. GIE or Global Interrupt bit is the master bit that can disable all interrupts.
Then when set PB1 i/o pins as output so that it can control a LED. The LED is connected to MCU by using series resistor to GND. Finally we enter an infinite loop that does nothing. As our timer is set up and running each times it overflows we increment counter by one. When counter becomes 76 we toggle the RB1 pin and reset the counter variable.
In HI-TECH C you can create an ISR (that is Interrupt service routine) by using the keyword interrupt. The ISR function can have any valid C function name. Its argument should be void and the return type should also be void. In our example we have named it \"ISR\".
Whenever TIMER0 overflow the CPU stops it current operation and jumps to the ISR. This is calledinterrupt(or exception) condition. As soon as it enters the ISR we check if it is the TIMER0 overflow interrupt by checking the TMR0IF (Timer0 interrupt flag). We also check if the interrupt is enabled (by checkingTMR0IE i.e. Timer0 interrupt enable bit). If both the conditions are met we execute the TIMER0 Overflow ISR Code.
The Timer Modules - Timer1
Unlike the Timer0 module, Timer1 is a 16-bit length timer/counter. It can operate as a Timer, or as a synchronous/asynchronous counter. To set-up and control the Timer1 module, there is a dedicated control register named T1CON. Accessing this register will have a result on the operation of the Timer1 module.
Setting up and accessing the Timer1 module
The Timer1 module has 2 8-bit registers to represent the 16-bit length value of the module. These registers are both located in BANK0, and are named TMR1H and TMR1L. The 16-bit value comes from the pair TMR1H:TMR1L. Every increament of the Timer1 module will increase the value of TMR1L register. Every time that this register overflows, the TMR1H is increased by 1.
To set up and control the Timer1 module, you need to access the T1CON register located in BANK0. The bits of this register are explained bellow:
T1CON register BIT <6> (T1RUN):
This bit is the \"Timer1 System Clock Status bit\", and is available only for reading. Under certain circumstances, the PIC can change the clock input to an external 32KHz crystal connected onto the PIC. This oscillator is used to reduce the power consumption even more. This kind of configuration is most usable in RTC applications (Real Time Clock). The value that the T1RUN bit can get is:
T1CON register BITS <5:4> (T1CKPS):
These two bits are the \"Timer1 Input Clock Prescaler Select bits\". Unlike the Timer0 module, this one has a dedicated prescaler. The prescaler is assigned all the time to Timer1 module and always divides the incoming counts. It can be deactivited simply by choosing a 1:1 division. The values that these two bits can get are:
T1CON register BITS <3> (T1OSCEN):
This bit is named \"Timer1 Oscillator Enable Control bit\". The PIC has a built-in inverter connected on pins T1OSO and T1OSI. This inverter is used to generate the clock pulses from the external 32 KHz crystal. This bit will turn on and off this inverter to reduce the power consumption when not in use:
T1CON register BITS <2> (T1SYNC):
This bit is named \"Timer1 External Clock Input Synchronization Control bit\". When the Timer1 module operates as a counter and the counts are delivered from the T1CKI pin, the input pulses can be synchronized with the internal clock phase. This bit controls the synchronization module, and it is ignored if the bit TMR1CS is cleared:
Some considerations needs to be taken into account when choosing the synchronizing mode. First of all, for the external pulses to be synchronizes, you need to make sure that the period of each external pulse (in case that the prescaler rate is 1:1) is equal or bigger than two periods of the internal clock. Due to the fact that the synchronization module is located after the prescaler module, this means that if the prescaler rate is not 1:1, then the minimum period of the external pulses that can be synchronized is further reduced. The reduction multiplier is the same as the rate of the prescaler. If for example the prescaler rate is 1:4, then the minimum period of the external pulses to be synchronized is:
2 x Internal_Clock_Period x Prescaler_Rate = 2 x Internal_Clock_Period x (1/4) = Internal_Clock_Period / 2
Also, you should be aware that if the PIC is in Sleep mode, the synchronization module is turned off to preserve power. Thus, although the prescaler will change value in every count, the Timer1 module will NOT increase it\'s registers!
T1CON register BITS <1> (TMR1CS):
This is the \"Timer1 Clock Source Select bit\". By changing the value of this bit, you change the clock source of the module:
T1CON register BITS <0> (TMR1ON):
This is the \"Timer1 On bit\". This bit will control the operation of the Timer1 module:
The Timer1 Interrupt
The Timer1 module has a 16-bit register for the counts, the TMR1H:TMR1L registers, both located in BANK0. This means that it can count up to 65535. If the TMR1H:TMR1L value is 65535 (0xFFFF) and it is increased once more, both registers will become 0 (0x0000) and the TMR1 interrupt shall be raised. The TMR1IE interrupt can be controlled by the PIE1 register bit 0 (TMR1IE: TMR1 Overflow Interrupt Enable bit). When the TMR1 Interrupt is raised, the PIR1 bit 0 (TMR1IF: TMR1 Overflow Interrupt Flag bit) is raised to indicate that the TMR1 interrupt is occurred. The TMR1IF must be cleared in software (BCF PIR1,TMR1IF) for the TMR1 interrupt to be re-enabled. More info about the PIC Interrupts can be found in this link.
Reading and Writing the registers of Timer1, when operating as asynchronous counter
You should take extra care when reading or writing the two register of the Timer1 module in asynchronous mode. What could happen is that when the first register is read into W and the user is ready to read the second register, an overflow may occur from TMR1L to TMR1H. Suppese for example the value of TMR1H is \'00000000\' and the value of TMR1L is \'11111111\'. You read the TMR1H register (\'00000000\') and then you are ready to read the TMR1L register, but before you do, a count increases the TMR1L register and it overflows. The TMR1H becomes \'00000001\' and the TMR1L becomes \'00000000\'. Then you read the TMR1L. The value that you get from the pair is 00000000:00000000, but you should have got 00000001:00000000 instead. The same would happen if you read first the TMR1L register.
To avoid this problem, there are two methods to follow. The first method is to shut down the Timer1 module (BCF T1CON,TMR1ON), get the reading and then re-enable the module (BSF T1CON,TMR1ON). Many times this is not possible. Especially when the pulses to be counted have high frequency, and a 4-cycles operation will have a significant change in the result. If the turn-off/on operation is not possible, then you should follow the test-method.
With the test-method, you read and save first the TMR1H register then you read and save the TMR1L register. Then, you re-read the TMR1H register and test this value with the previous-read value. If these two values are not equal, then it means that either the TMR1L has overflow, or the TMR1H AND TMR1L have overflow. Either way, you re-read and re-save the TMR1H and TMR1L register. The following code is supplied from Microchip as a fail-safe read operation for the Timer1 register:
During the writing operations, all you need to do is to turn off the Timer1 module, write the new values and then turn it on back again. Alternatively, you can clear the TMR1L register to avoid an overflow, then write the new value to TMR1H, and finally write the new value to TMR1L register. The following code is supplied from Microchip as a fail-safe write operation for the Timer1 register:
Examples with the Timer1 Module
For the sake of understanding, find below some examples on how to setup the TMR1 module.
Example 1 - TMR1 increasing on every LOW to HIGH transition on T1CKI pin synchronized
Example 2 - TMR1 measures input pulses on T1CKI pin (NOT synchronized), divided by 4
| Name | TMR0ON | T08BIT | T0CS | T0SE | PSA | PS2 | PS1 | PS0 |
| Initial Value | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| BIT | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |



