View previous topic :: View next topic |
Author |
Message |
Analyzer
Joined: 07 Sep 2003 Posts: 32
|
How to make RTCC more accurate? |
Posted: Sat Dec 20, 2003 2:08 pm |
|
|
Hi,
I am a newbie about rtcc interrupt and i referenced ccs example program.This code (below) works but it is not accurate.Because 20M/(4*256*256) = 76,2939453125 and INTS_PER_SECOND is 76! So how can i make it the most accurate? How can i use it?
Thanks.
Analyzer.
#define INTS_PER_SECOND 76 // (20000000/(4*256*256))
byte seconds; // A running seconds counter
byte int_count; // Number of interrupts left before a second has elapsed
#int_rtcc // This function is called every time
void clock_isr() { // the RTCC (timer0) overflows (255->0).
// For this program this is apx 76 times
if(--int_count==0) { // per second.
++seconds;
int_count=INTS_PER_SECOND;
}
}
void main() {
byte start;
byte c;
int_count=INTS_PER_SECOND;
set_timer0(0);
setup_counters( RTCC_INTERNAL, RTCC_DIV_256 | RTCC_8_BIT);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
lcd_init();
lcd_clear();
c = 0;
do {
lcd_gotoxy(1,1);
lcd_putc((seconds-start)+48);
} while (TRUE);
} |
|
|
MGP
Joined: 11 Sep 2003 Posts: 57
|
|
|
Analyzer
Joined: 07 Sep 2003 Posts: 32
|
|
Posted: Sat Dec 20, 2003 2:52 pm |
|
|
Thank you for your great help.But i can not understand asm code and i am too lazy to get theory and write a new code
Anywayz, if somebody has an instant ccs c code, please write it here
Analyzer. |
|
|
Ttelmah Guest
|
|
Posted: Sat Dec 20, 2003 3:58 pm |
|
|
Analyzer wrote: | Thank you for your great help.But i can not understand asm code and i am too lazy to get theory and write a new code
Anywayz, if somebody has an instant ccs c code, please write it here
Analyzer. |
The simple answer, is to use a crystal that is a binary multiplier. Though you can 'tweak' things to get them closer, if you are working with a crystal frequency that does not evenly divide by the 8bit counter, times the divisor, it'll allways involve extra work. This is why crystals for clock applications, use frequencies like 32768Hz, 4.096MHz, 14.7456MHz etc.. 19.6608MHz, is readily available, and gives a nice 75 count. :-)
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Dec 20, 2003 4:35 pm |
|
|
Can you use another timer? Do you have timer1 available? Do you have a CCP still free? If so, respond back and I will show you a way using a CCP int. Another option is to drive timer1 with an external clock. One of those nice frequency values that RJ was referring to. |
|
|
Analyzer
Joined: 07 Sep 2003 Posts: 32
|
|
Posted: Sat Dec 20, 2003 6:05 pm |
|
|
Thanks for your help.It is a good idea to change xtall and get nicer values but i have many 4 mhz xtall.I need to use them.
My all timers are free now i only use that code above.I'm using 877 for this.I'm really curious on that "another way"
Analyzer |
|
|
Guest
|
What is your Crystal Frequency ? |
Posted: Sat Dec 20, 2003 8:42 pm |
|
|
Analyzer wrote: | Thanks for your help.It is a good idea to change xtall and get nicer values but i have many 4 mhz xtall.I need to use them.
My all timers are free now i only use that code above.I'm using 877 for this.I'm really curious on that "another way"
Analyzer |
You started with math showing 20MHz and now your arte using 4MHz !
What is it... ? |
|
|
Hans Wedemeyer
Joined: 15 Sep 2003 Posts: 226
|
Try this... |
Posted: Sat Dec 20, 2003 9:10 pm |
|
|
I don;t have a PIC16 setup at the moment, but form memory this should give a 1 second tick.
hansw
#include <16F877.h>
#device *=16
#device adc=8
#use delay(clock=4000000)
#fuses NOWDT,HS, PUT, NOPROTECT, BROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
int32 Seconds;
int OneSecondFlag;
int Tick;
/////////////////////////////////////////////
// Using Timer 1 to interrupt every 100mS
// Timer 1 is a 16 bit timer.
// using a 4MHz xtal and Timer1 Prescale = 8
// Timer1 counter sees 8
// for 100mS preload 15536 or 65536-(0.1/(8/4000000))
#int_TIMER1
TIMER1_isr()
{
Set_Timer1(15536);
Tick++;
if( Tick >= 10 )
{
OneSecondFlag++;
Tick=0;
}
}
////////////////////////////////////////////
//
void main()
{
Tick=0;
Seconds=0;
OneSecondFlag=0;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_counters(RTCC_INTERNAL,RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DISABLED,0,1);
enable_interrupts(INT_TIMER1);
enable_interrupts(global);
while(1)
{
if( OneSecondFlag > 0 )
{
Seconds++;
printf("%lu\r\n",Seconds);
OneSecondFlag=0;
}
}
} |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Dec 20, 2003 9:37 pm |
|
|
Lets say you are using a 20MHz crystal. The internal speed is 5MHz. This equates to timer1 incrementing every 0.2us with no prescaler assigned. Now we are going to use the CCP1 interrupt to keep track of our time. We will actually be counting 100ths of a second for this example. 100th of a second is 50,000 timer1 ticks (0.01/0.0000002=50000). This will be our CCP1 value.
Code: |
#int_ccp1
void ccp1_isr(void)
{
static count = 0;
count++;
if (count == 100)
{
count = 0;
seconds++;
}
}
|
We do not need any interrupt for timer1. We just need to set it up
Code: |
int seconds=0;
void main(void)
{
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_ccp1(CCP_COMPARE_RESET_TIMER);
// 50000 is how many timer1 ticks for 1/100th of second
CCP_1 = 50000;
enable_interrupts(INT_CCP)
enable_interrupts(GLOBAL);
while(1)
{
}
}
|
Here is a test program for the PICDEM2 PLUS board. Note that you must modify the lcd.c file according to my previous post regarding using the lcd.c file with the PICDEM board
Code: |
#include <18f452.h>
#fuses NOWDT,NOPROTECT,NOLVP,NOWRT,NOEBTR
#DEVICE ICD=TRUE
#use delay (clock=1000000)
#include "lcd.c"
short seconds_flag = FALSE;
void main(void)
{
int seconds=0;
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_ccp1(CCP_COMPARE_RESET_TIMER);
// 50000 is how many timer1 ticks for 1/100th of second
CCP_1 = 25000;
// CCP_1 = 50000;
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
lcd_init();
while(1)
{
if (seconds_flag)
{
seconds_flag = FALSE;
printf(lcd_putc,"\fElapsed secs %u",seconds++);
}
}
}
#int_ccp1
void ccp1_isr(void)
{
static int count = 0;
count++;
if (count == 100)
{
count = 0;
seconds_flag = TRUE;
}
}
|
Now the beauty of using the CCP with such a large value is that I could adjust any error due to tolerances with the crystal. At 20MHz, my resolution is 200ns. At 4MHz, I still have millisecond resolution. |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1933 Location: Norman, OK
|
RTCC Accuracy |
Posted: Sun Dec 21, 2003 8:44 am |
|
|
All this to avoid buying a 90 cent crystal.... what a waste of time......sigh...
At some point you can cut your losses and save your self a LOT of time!
I had lot of 4MHZ stuff too. But I bit the bullet and started with about 20 of the half can 18.432MHZ oscillators for $1 apiece.
The benefits:
They are very stable and reliable in all environments.
They give me exact RS232 speeds and frequency divides
No Oscillator startup/loading hassles
Less component count
Uses about the same real estate.
Oscillator does not have to be as close a possible to the PIC.
Can be socketed and the frequency changed in seconds. (I always use sockets)
etc...etc...
I have used them in all my designs ever since. The 4MHZ xtals/capacitors and resonators are still sitting in the drawer and suppose they always will be....
something to think about... |
|
|
Analyzer
Joined: 07 Sep 2003 Posts: 32
|
|
Posted: Sun Dec 21, 2003 11:54 am |
|
|
Thank you for all your replies.I especially want to thank to code senders.I will try all codes and sim in proteus.I agree to buy new xtalls, i'm totally aware of all benefits but this will be a part of production and i have MANY 4 mhz xtalls and want to spend them.
I will test all and report here.
Thank you again. |
|
|
KerryW Guest
|
Try this: |
Posted: Sun Dec 21, 2003 12:24 pm |
|
|
#define INTS_PER_SECOND 76 // (20000000/(4*256*256))
byte seconds; // A running seconds counter
byte int_count; // Number of interrupts left before a second has elapsed
int32 count;
#int_rtcc // This function is called every time
void clock_isr() { // the RTCC (timer0) overflows (255->0).
count = count + 65536;
if(count>5000000)
{
seconds++;
count = count - 5000000;
}
// For this program this is apx 76 times
//if(--int_count==0) { // per second.
//++seconds;
//int_count=INTS_PER_SECOND;
}
}
void main() {
byte start;
byte c;
int_count=INTS_PER_SECOND;
set_timer0(0);
setup_counters( RTCC_INTERNAL, RTCC_DIV_256 | RTCC_8_BIT);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
lcd_init();
lcd_clear();
c = 0;
do {
lcd_gotoxy(1,1);
lcd_putc((seconds-start)+48);
} while (TRUE);
} |
|
|
|