I am trying to figure out how to create a timer for my C8051F020 MCU. The following code uses the value passed to init_Timer2()
with the following formula:
65535-(0.1 / (12/2000000)=48868.
I set up the timer to count every time it executes and for every 10 counts, count one second. This is based on the above formula. 48868 when passed to init_Timer2
will produce a 0.1 second delay. It would take ten of them per second. However, when I test the timer it is a little fast. At ten seconds the timer reports 11 seconds, at 20 seconds the timer reports 22 seconds. I would like to get as close to a perfect second as I can.
Here is my code:
#include <compiler_defs.h>
#include <C8051F020_defs.h>
void init_Clock(void);
void init_Watchdog(void);
void init_Ports(void);
void init_Timer2(unsigned int counts);
void start_Timer2(void);
void timer2_ISR(void);
unsigned int timer2_Count;
unsigned int seconds;
unsigned int minutes;
int main(void)
{
init_Clock();
init_Watchdog();
init_Ports();
start_Timer2();
P5 &= 0xFF;
while (1);
}
//=============================================================
//Functions
//=============================================================
void init_Clock(void)
{
OSCICN = 0x04; //2Mhz
//OSCICN = 0x07; //16Mhz
}
void init_Watchdog(void)
{
//Disable watchdog timer
WDTCN = 0xDE;
WDTCN = 0xAD;
}
void init_Ports(void)
{
XBR0 = 0x00;
XBR1 = 0x00;
XBR2 = 0x40;
P0 = 0x00;
P0MDOUT = 0x00;
P5 = 0x00; //Set P5 to 1111
P74OUT = 0x08; //Set P5 4 - 7 (LEDs) to push pull (Output)
}
void init_Timer2(unsigned int counts)
{
CKCON = 0x00; //Set all timers to system clock divided by 12
T2CON = 0x00; //Set timer 2 to timer mode
RCAP2 = counts;
T2 = 0xFFFF; //655535
IE |= 0x20; //Enable timer 2
T2CON |= 0x04; //Start timer 2
}
void start_Timer2(void)
{
EA = 0;
init_Timer2(48868);
EA = 1;
}
void timer2_ISR(void) interrupt 5
{
T2CON &= ~(0x80);
P5 ^= 0xF0;
timer2_Count++;
if(timer2_Count % 10 == 0)
{
seconds++;
}
if(seconds % 60 == 0 && seconds != 0)
{
minutes++;
}
}
Open the datasheet for this specific microcontroller and look for the timetick interrupt. Find out how to issue an interrupt every n ms. Usually the formula for calculatinng this is depended on the clock speed, and It's often described in the datasheet/programming guide for the specific microcontroller.
You are using internal oscillator. It is very inaccurate, not 2 mhz exactly.
There's likely nothing in your code that is causing the problem.
You are assuming that the internal oscillator is at exactly 2Mhz. Most likely, your micro isn't there. If you look at the datasheet's tolerances, you will see that when configured for 2Mhz, the spec'ed min is 1.5Mhz and the max is 2.4Mhz. So you could be running anywhere between 75% and 120% of your intended frequency. (This usually changes over temperature also...)
So the 10% error you are seeing in your counter could just be the hardware.
Do you have a second micro to flash your code into? It's osc may run at a different frequency and may give you a different sense of time.
Side note: I recommend changing
to
The equality check is less expensive in cycles than the modulo, and without clearing out the
seconds
your reported seconds will be incorrect after the first minute.I cannot take full credit for answering this question. Everyone contributed. I ended up using the external clock at 22.1184Mhz. The following snippets of code are the sections of the original post code that has changed to make it work:
and
From my tests this is very accurate.