Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Timer configuration problem PIC18f4520

Status
Not open for further replies.

Raady Here

Full Member level 5
Joined
Jun 8, 2013
Messages
242
Helped
26
Reputation
52
Reaction score
26
Trophy points
28
Location
India
Activity points
1,571
PIC18F4520,
MPLAB 8.88

Hi,

I am using Timer1 and configured timer for 1 ms delay.

to check my configuration I am running a clock, for this I need to raise a flag every 1000 times it overflows to make it a second. but i need to do every 30th time.
so I am getting 33 ms instead of 1ms.
so I tried assigning TMR values to 0, even then it doesnt show any difference.
if I cant load the necessary values where should I load those else where my configuration gone wrong ?
Actually I am need of 200us delay.


calculations used for timer
Fosc = 8 Mhz internal
Fcy = 2 Mhz
Tcy = 0.5us
Tcy scalar = 0.5us x 1 (used 1:1)
T = 1ms/0.5us = 2000 = 07D0h
TMR1L = 0xD0;
TMR1H = 0x07;


Here is my timer configuration
Code:
void INIT_TIMER(void)
{
	RCONbits.IPEN		= 1;	// Enable priority levels on interrupts
	INTCONbits.GIEH		= 1;    // Enables all high priority interrupts
	INTCONbits.GIEL		= 0;    // Enables all Low priority interrupts
	PIR1bits.TMR1IF		= 0;    // TMR1 register overflow is cleared
	PIE1bits.TMR1IE		= 1;    // Enables overflow interrupt
	IPR1bits.TMR1IP		= 1;    // High priority   
	
	T1CONbits.RD16		= 1;    // Enables register Read/Write of Timer1 in one 16-bit operation  
	T1CONbits.T1RUN		= 0;	// Device clock is derived from other oscillator
	T1CONbits.T1CKPS1	= 0;
	T1CONbits.T1CKPS0	= 0;	// Prescalar 1:1
	T1CONbits.T1OSCEN	= 1;	// Timer 1 osc on.
	T1CONbits.TMR1CS	= 0;	// Internal Clock Fosc /4.
	T1CONbits.TMR1ON	= 1;	// Enables Timer1
						
	TMR1L = 0xD0;
	TMR1H = 0x07;
}

ISR used
Code:
#pragma code high_vector = 0x08
 void interrupt_at_high_vector(void)
 {
     _asm 
		goto high_isr 
	_endasm
 }

 #pragma code        // return to the default code section 
 #pragma interrupt high_isr

void high_isr(void)
{
  if(PIR1bits.TMR1IF)        // TMR1 register overflowed
    {
      PIR1bits.TMR1IF = 0;            //clear interrupt flag
	  count++;
	  if(count > 29)             // 29 approximated by trail and error 
		{
			count = 0;
			flag_clock = 1;  // flags for  every sec
			Clock();
		}
    }
}
 

should you reload the timer high and low bytes in the interrupt service routine
Code:
TMR1L = 0xD0;
	TMR1H = 0x07;
 

horace1, is correct.

If you do the math, 2^16 = 65536. 65536/2000 = 32.768 times the desired interrupt rate. Which is inline with what you are seeing. The reason for this is TMR1 is overflowing or resetting to 0. This is why setting it to 0 also did not fix it. (In affect you were doing the same thing it was.) In the initialization code you preloaded it, but since timer 1 changes TMR1 directly it cannot remember what you set it to. So it cannot reload itself after the interrupt/overflow. Therefore you must do it for it.
 

I have made modifications as said.
But I cant find any difference,

here is my code

timer.c
Code:
#include<P18F4520.h>
#include<delays.h>
#include"timer.h"

unsigned char TimerDelay_flag_200us = 0, flag_clock = 0;
unsigned int count = 0;

Time SystemTime;

// High priority interrupt vector

#pragma code high_vector = 0x08
 void interrupt_at_high_vector(void)
 {
     _asm 
		goto high_isr 
	_endasm
 }

 #pragma code        // return to the default code section 
 #pragma interrupt high_isr

void high_isr(void)
{
	if(PIR1bits.TMR1IF)
	{
  		TMR1H = 0x07;
		TMR1L = 0xD0;
		PIR1bits.TMR1IF = 0;
	  	count++;
		if(count > 29)
		{
			count = 0;
			flag_clock = 1;
			Clock();
		}
    	TimerDelay_flag_200us = 1;
	}
}

void INIT_TIMER(void)
{
	RCONbits.IPEN		= 1;	// Enable priority levels on interrupts
	INTCONbits.GIEH		= 1;    // Enables all high priority interrupts
	INTCONbits.GIEL		= 0;    // Enables all Low priority interrupts
	PIR1bits.TMR1IF		= 0;    // TMR1 register overflow is cleared
	PIE1bits.TMR1IE		= 1;    // Enables overflow interrupt
	IPR1bits.TMR1IP		= 1;    // High priority   
	
	T1CONbits.RD16		= 1;    // Enables register Read/Write of Timer1 in one 16-bit operation  
	T1CONbits.T1RUN		= 0;	// Device clock is derived from other oscillator
	T1CONbits.T1CKPS1	= 0;
	T1CONbits.T1CKPS0	= 0;	// Prescalar 1:1
	T1CONbits.T1OSCEN	= 1;	// Timer 1 osc on.
	T1CONbits.TMR1CS	= 0;	// Internal Clock Fosc /4.
	T1CONbits.TMR1ON	= 1;	// Enables Timer1			
	TMR1H = 0x07;
	TMR1L = 0xD0;
}

//----------------------------------------------------------------------------
void TimerDelay_200us(unsigned int delay)
{
	TimerDelay_flag_200us = 0;
	while(delay)
	{
		if(TimerDelay_flag_200us == 1)
		{
			TimerDelay_flag_200us = 0;
			delay--;
		}
	}
}

void Clock(void)
{
	if ( SystemTime.Seconds < 59 )          	// is cummulative seconds < 59?
	{	
		SystemTime.Seconds++;               	// yes, so increment seconds
	}
	else                         				// else seconds => 59     
	{
		SystemTime.Seconds = 0x00;          	// reset seconds
		if ( SystemTime.Minutes < 59 )      	// is cummulative minutes < 59?
		{
			SystemTime.Minutes++;           	// yes, so updates minutes  
		}
		else                     				// else minutes => 59
		{
			SystemTime.Minutes = 0x00;      	// reset minutes
			if ( SystemTime.Hours < 23 )    	// is cummulative hours < 23
			{
				SystemTime.Hours++;
			}
			else
			{
				SystemTime.Hours = 0x00;    	// Reset time
			}		  
		}
	}   	
}

timer.h
Code:
typedef union  _Time
{
	unsigned long int Value;
	struct
	{
		unsigned char Seconds;
	  	unsigned char Minutes;
	  	unsigned char Hours;
	  	unsigned char Res;								//	Reserved
	};
} Time;

void INIT_TIMER(void);
void high_isr(void);
void TimerDelay_200us(unsigned int delay);
void Clock(void);

main.c
Code:
#include<P18F4520.h>
#include<stdio.h>
#include"uart.h"
#include"timer.h"

extern Time SystemTime;
extern unsigned char flag_clock;

void main(void)
{
	ADCON0bits.ADON = 0;
	INTCON2bits.RBPU = 0;
	ADCON1 = 0b00001111;
	
	OSCCON	= 0x72;
	OSCTUNEbits.PLLEN = 0;		// PLL disabled
	TRISAbits.TRISA0 = 0;
	init_uart();
	INIT_TIMER();
	SystemTime.Value = 0;
	while(1)
	{
		if(flag_clock == 1)
		{
			LATAbits.LATA0 = ! LATAbits.LATA0;
			printf((const rom far char *) "\n\r%d.%d.%d", SystemTime.Hours, SystemTime.Minutes, SystemTime.Seconds);
			flag_clock = 0;
		}
   }
}
 

Finaly now I can my timer to the time delay that required.

I didnt understand the reason but some others in threads used the value by subtracting from FFFF

so instead of TMR1H = 0x07; and TMR1L = 0xD0;
I have loaded TMR1H = 0xF8 and TMR1L = 0x2F; (FFFF - 07D0 = F82F) // calculations for 1ms timer
and its working with some error, with respect to my project need not be considered. But...

Error:
on running a loop for 1 sec, with 1ms timer isr, producing a 1.2 sec difference for a minute on average of 30 minutes running Clcok.
On running a loop for 1 sec, with 200us timer isr, producing a 4.5 sec difference for a minute on averageof 30 minutes running Clcok.

In the link below, he explianed about counting time for overflow period( 256 time cycles) as well, but what I didnt understand is, should we add the overflow period to timer delay ?
is that the difference i get in the error.
https://extremeelectronics.co.in/mi...o-pic18s-timers-pic-microcontroller-tutorial/

ISR used for 1ms delay
Code:
#define _1ms
#ifndef _1ms
   #define _count 998
   #define _tmrh 0xF8
   #define _tmrl 0x2F
#endif
 
void high_isr(void)
{
 if(PIR1bits.TMR1IF)
 {
 TMR1H = _tmrh;
 TMR1L = _tmrl;
 PIR1bits.TMR1IF = 0;
 count++;
 if(count > _count)
 {
 count = 0;
 flag_clock = 1;
 Clock();
 }
 TimerDelay_flag_200us = 1;
 }
}
 

hello,

I suppose you used 8MHz and prescaler = 1/1 to get 1mS.

You can not get a so big difference with Timer1 at 1mS...
You compare it with Clock() ?
Check how works Clock() in details....
because this time measure is disturbed 1000 times per second !!

In Timer1 interupt , cancel Clock(); and instead change the status of a led and use a chronometer
to measure real elapsed time .. and you will see !
 

Using a timer for time keeping will cause a drift to some degree. This is why we use real time clocks. There is also a certain amount of time lost by microcontroller, processing the update. Since you do this so often that small delay can add up. This is why it increased when you increased the interrupt frequency. Optimizing this delay can be painful.

If you are making a clock, I would recommend getting an external real time clock or using a microcontroller that has one built in.

- - - Updated - - -

I didnt understand the reason but some others in threads used the value by subtracting from FFFF

so instead of TMR1H = 0x07; and TMR1L = 0xD0;
I have loaded TMR1H = 0xF8 and TMR1L = 0x2F; (FFFF - 07D0 = F82F) // calculations for 1ms timer
and its working with some error, with respect to my project need not be considered. But...

The reason is you want set the desire time to be offset from the overflow point, 0xFFFF. So you calculate the number of ticks and subtract from 0xFFFF. This will jump the timer forward or backwards to ensure that it waits for the correct amount of time before interrupting.
 
even when using external real time clocks one has to be aware of drift over time in particular with temperature, e.g. even 1 or 2 parts in a million drift may give significant errors over years

in one application we used the Microchip MCP79410 RTC
https://www.microchip.com/wwwproducts/Devices.aspx?product=MCP79410

in the 700 or 800 hundred systems built we found a number were several minutes out after six months and had to be recalibrated on site - in this case the errors were not critical

for more exacting requirements we would use a temperature compensated RTC such as the Maxim DS3231
**broken link removed**

if systems are connected to the internet the time can be synchronized online
https://tf.nist.gov/tf-cgi/servers.cgi
 

I think Timer1 with external oscillator very closed accurate than timer mode
 

Hi
In your case you are using internal osc that is what I pointed out external osc for one second count at very closed accurate
What happened last?
 

The problem with using these solutions is that they all require software. The delay from the software needs to be accounted for. If not then you will have a drift, no matter how precise the timers. Changes in software may require recalibrating the delay.

One easy fix is to move to a PIC18 with a hardware RTC built in. This is a hardware implementation that does all the counting for you. You can use a timer to trigger reading the registers and printing the result on the screen. The interval does not have to be exactly half a minute just close enough to prevent you from missing an update.

Example PIC18s are: PIC18F26J11, PIC18F26J13, PIC18F26J50, PIC18F26J53.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top