PIC16F877A Initial Value for Timer - Page 1
Forum section: electronics / general

author: Chris_WMS
author_rank: Newbie
timestamp: October 04, 2020, 05:01:10 pm
content: Hi guys, I would like to have some help.I am using the Timer 1 to use as a delay using the initial value method for delaying 1 sec.The FOSC used is 20MHz.Here are the ways I calculate the initial value.PIC Input frequency = 20MHz/4=5MHzPrescaler = 1:1Tick counter frequency = 1/5MHz = 0.2u secFull scale time = 0.2u sec * 65536 = 13.11 m sec10m sec is chosen as a time to count for every cycle and repeated 100 times to obtain 1 sec.Timer count = 10m sec/0.2 u sec = 50000Register value = 65536-50000 = 15535 = 3CAF (hex)Below is the attachment of the code I am using and I am using MPLAB IDE v8.92 andthe program works well.But I would like to ask 3 questions regarding the program.First, after declaring the initial value/register value in the main program (Program 1- Line 11). Should I reassign the initial value/register value after clearing the overflow flag/interrupt flag (Program 1- Line 25)? or is it not necessary to reassign the initial value/register value? (For Program 1)Second, if I'm using a interrupt sub function (Program 2). Although I had assign initial value in the main function (Program 2 - Line 26), should I reassign the initial value/register value in the interrupt sub function (Program 2- Line 18)? (For Program 2)If according to the datasheet of PIC 16F87XA 6.7 which is in the attachment (2.jpg), the statement "TMR1H and TMR1L registers are not reset to 00h on a POR" valid for the initial value inside the main program or including the interrupt function?Third, can I assign the initial value/register value as global value? If can, how should I define?Thanks.Code:Code://Program 1- without interrupt ISR function#include<htc.h>#define _XTAL_FREQ 20000000__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF);int Count = 0;void main (){TRISD=0x00; //configurate PORTD as outputT1CON=0b00000000; //disable Timer 1(bit 0),Prescaler (bit4-5)TMR1H=0x3C; //setting initial value as 15535 to count 10ms delay - Line 11TMR1L=0xAF;T1CON=0b00000001; //starting Timer 1while (1){while(TMR1IF==1){TMR1IF = 0; //clear interrupt flagCount ++; //increase count bit by 1if (Count ==100){Count = 0; //clear count bitPORTD=~PORTD; //toggle PORT D}TMR1H=0x3C; - Line 25TMR1L=0xAF;}}}Code://Program 2- with interrupt ISR function#include<htc.h>#define _XTAL_FREQ 20000000__CONFIG(FOSC_HS&WDTE_OFF&PWRTE_ON&BOREN_OFF&LVP_OFF);int Count = 0;void interrupt isr(){if (TMR1IF==1){TMR1IF = 0; //clear interrupt flagCount ++; //increase count bit by 1if (Count == 100){Count = 0; //clear count bitPORTD=~PORTD; //toggle PORT D}TMR1H=0x3C; //setting initial value as 15535 to count 10 ms - Line 18TMR1L=0xAF;}}void main (){T1CON=0x00; //initialise Timer 1, prescare=1:1, unable timer1TMR1H=0x3C; //setting initial value as 15535 to count 10ms - Line 26TMR1L=0xAF;T1CON = 0b00000001; //starting TImer 1TRISD=0x00; //configurate PORTD as outputINTCONbits.GIE=1; //enable all global interruptsINTCONbits.PEIE=1; //enable periferal intPIE1bits.TMR1IE=1; //enable timer 1 overflow interruptPIR1bits.TMR1IF=0; //timer register 1 is not overflowwhile (1){}}

author: ggchab
author_rank: Frequent Contributor
timestamp: October 04, 2020, 05:18:44 pm
content: TMR1IF is set when registers TMR1L/H reach 0. The timer then simply continues to increment to the registers, nothing else. So, you have to reload them with the initial value to keep the same delay.As the timer never stops incrementing the TMR1L/H, it is even betterto addthe initial value to the counter instead of simply loading it. So, you will take into account any processing delays.

author: ggchab
author_rank: Frequent Contributor
timestamp: October 04, 2020, 05:26:36 pm
content: You may use a#definefor the initial value. And if the first 10 ms delay is not critical, I would only load TMR1L/H in one place: in the interrupt handler function.When possible, I try to avoid doing the same thing at different places. But this could be a personal taste

author: MarkF
author_rank: Super Contributor
timestamp: October 04, 2020, 05:36:23 pm
content: Or use the compare mode with Timer 1.Set once and forget.(Set for 25KHz interrupt. Couldn't be bothered to change the time values.)Code:void main(void){// Setup CCP1 configuration for clock interruptCCPR1H=0x01; // 25KHz ticks with 20 MHz clock (PWM Freq = 100 Hz)CCPR1L=0x86;CCP1CON=0x0b; // Compare mode, trigger special event// Setup Timer1 configurationTMR1H=0;TMR1L=0;T1CON=0x01; // 1:1 Prescale | TMR1CS | TMR1ON bits// Enable CCP1 interruptPIR1bits.CCP1IF=0; // CCP1 Interrupt Flag bitPIE1bits.CCP1IE=1; // CCP1 Interrupt Enable bitINTCON=0xc0; // GIE and PEIE interruptswhile (1) {// TODO HERE:}}void __interrupt() isr(void){if (PIE1bits.CCP1IE && PIR1bits.CCP1IF) {PIR1bits.CCP1IF = 0; // Clear CCP1 Interrupt Flag// TODO HERE:}}

author: Chris_WMS
author_rank: Newbie
timestamp: October 06, 2020, 12:51:09 pm
content: Hi and thx for the reply, ggchab and MarkF. What does it meanto addthe initial value? How do I declare toaddthe initial value?Quote from: ggchab on October 04, 2020, 05:18:44 pmSo can I define the initial value as global value like this?#defineTMR1L=0xAF;#defineTMR1H=0x3C;Quote from: ggchab on October 04, 2020, 05:26:36 pmHi MarkF, may I know whats the different between Compare mode and the way I use to declare?Why do we need to set it as 25kHz?For the code if(PIE1bits.CCP1IE && PIR1bits.CCP1IF) does it means when both are trigger to 1 and it will do the function inside the if ?and using this method we do not need to declare "PIE1bits.CCP1IE ==1&& PIR1bits.CCP1IF==1" inside the condition?Quote from: MarkF on October 04, 2020, 05:36:23 pm

author: MarkF
author_rank: Super Contributor
timestamp: October 06, 2020, 01:56:45 pm
content: Quote from: Chris_WMS on October 06, 2020, 12:51:09 pmYou can use any frequency you want.I just did a quick copy-and-paste from one of my projects as an example. And 25KHz is the interrupt frequency I happened to be using.Setup the values for the Compare mode and Timer1 Prescaler for the frequency you want.The Compare Mode watches Timer1 and when it matches, Timer1 is automatically reset to zero and the interrupt called.Refresh your understanding of the Compare Mode and Timer1 from the datasheet.By using the Compare Mode, Timer1 is reset in hardware.Therefore, you don't loose the few clock cycles needed by the ISR routine before being able to reset Timer1 yourself.In most case, the timing just isn't that critical.In large projects you may be processing more than one interrupt.In which case doing it your way, you would want the have the Timer1 processing at the beginning of the ISR.Neither way is right or wrong. As a programmer, you make that decision on a per project bases.QuoteIn the interrupt service routine (ISR), you check that the Compare Interrupt is ENABLED and the Flag is SET.Then, you clear the Flag and do whatever processing you need for the Compare interrupt.You may also have other interrupts enabled and you need to check each of their enable bits and their flags.You don't want to apply your Compare Mode processing to the wrong interrupt.Note: You want to keep the processing inside the ISR routine as short as possible.

author: NorthGuy
author_rank: Super Contributor
timestamp: October 06, 2020, 02:32:09 pm
content: Of course, if the interrupt is always enabled, you don't need to check IE, only IF.<edit>And if you have only one interrupt source, you don't even need to check IF.

author: Chris_WMS
author_rank: Newbie
timestamp: October 06, 2020, 03:04:31 pm
content: Thanks MarkF, I will revise the Compare Mode and Timer1 from the datasheet. Thanks for the detail explanation.In short, can I say if using Compare mode will shorten some of the instruction set time?QuoteThanks NorthGuy for the reply. So the interrupt (TMR1IE) is always enabled by declaring once in the main program?If I did not enable IE, does it means the program will not go into the ISR ?Quote

author: ggchab
author_rank: Frequent Contributor
timestamp: October 06, 2020, 05:05:19 pm
content: Exact, if you do not set IE, the IF flag will still be set but the interrupt is not produced and the ISR is not called.

author: MarkF
author_rank: Super Contributor
timestamp: October 06, 2020, 05:08:07 pm
content: Quote from: Chris_WMS on October 06, 2020, 03:04:31 pmIf using the Compare Mode with Timer1, there is ONLY the initial setup time.There is NO ACTION required in the ISR function other that to clear the interrupt flag.All you have in the ISR is whatever you want to happen when the interrupt occurs.There is NOTHING required for Timer1 to continue. It is all done in hardware.Re-read the datasheet for using Compare with Timer1 (paragraph 8.2.4).

author: NorthGuy
author_rank: Super Contributor
timestamp: October 06, 2020, 05:45:47 pm
content: Quote from: Chris_WMS on October 06, 2020, 03:04:31 pmNo. You need to set IE. Otherwise there will be no interrupts. But if you set it once at the beginning and never clear it, it doesn't make any sense to check if it set every time you execute the interrupt. Therefore, instead ofCode:if (PIE1bits.CCP1IE && PIR1bits.CCP1IF)you can doCode:if (PIR1bits.CCP1IF)

author: Chris_WMS
author_rank: Newbie
timestamp: October 09, 2020, 07:55:44 am
content: Oh.. I see, Thanks for the information , ggchab, MarkF and NorthGuy. I will Enable the IE when I'm using ISR.So if using the CCP method, rather than using Interrupt Flag, it will choose to use GO/DONE bit and the RESET will be done in hardware but not in the processing?Chris

author: MarkF
author_rank: Super Contributor
timestamp: October 09, 2020, 02:23:00 pm
content: Quote from: Chris_WMS on October 09, 2020, 07:55:44 amUsing the CCP method, you use the Compare interrupt instead of the Timer1 interrupt.All the Timer1 processing is handled by the CCP.With CCP, the timer is counting a little differently.- Using Timer1 alone: You set the timer register and it counts up until it overflows, you get the timer interrupt and reset the value in the timer register.- Using the CCP: The timer register starts at zero, it counts up, the timer register is reset to zero when the timer count matches the CCP register and you get the CCP interrupt. All the timer processing is handled for you by the CCP.