![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
monkeytennis
Joined: 18 Feb 2004 Posts: 16 Location: UK
|
timer1 too fast |
Posted: Wed Jul 28, 2004 4:08 am |
|
|
Hello.
I've written the program below so that a PIC can be set up to timeout and set a pin high after a user defined period (either in minutes, hours and days). I have used the recommended technique in Microchip's application note AN580 for using an external crystal source(http://ww1.microchip.com/downloads/en/AppNotes/00580c.pdf) but for some reason which I can't fathom out, it seems to be timing out roughly 3 times too fast.
Does anyone know what the problem might be?
Thanks
Simon
Code: | // Main C program
#include <16C64A.h>
#use delay(clock=4000000)
#fuses HS, NOPUT, NOWDT, NOPROTECT, NOBROWNOUT
#include <LCD3.C>
//Defitions below make it easy to change the settings without playing with the
//program. Change COUNTDOWN to 'days' or 'hours'.
#define COUNTDOWN mins
#define FIRE_PIN1 PIN_C6
#define FIRE_PIN2 PIN_C7
#define UP_PIN PIN_B7
#define SET_PIN PIN_B6
void update_lcddays(void);
long secs=0,hours=0,days=0,dayset=0,mins=0;
int1 debounce=0,newsec=0;
int1 flob=0;
#int_TIMER1
TIMER1_isr()
{
set_timer1(0x8000);
//flob++;
//if (flob==3){
newsec=TRUE;
if (flob)
{
output_low(PIN_A3);
flob=FALSE;
}
else
{
output_high(PIN_A3);
flob=TRUE;
}
//flob=0;
//}
//printf(lcd_putc,"\f%3dh %3dm %4ds",hours,mins,secs);
}
void main()
{
int1 set=0,update=1;
int a;
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
port_b_pullups(TRUE);
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT);
setup_timer_2(T2_DISABLED,0,1);
lcd_init();
enable_interrupts(INT_TIMER1);
output_float(UP_PIN);
output_float(SET_PIN);
printf(lcd_putc,"\fDays: %3ld",dayset);
do
{
if (input(UP_PIN)==0)
{
update=1;
for (a=0;a<10;a++)
if (input(UP_PIN))
update=0;
else
delay_ms(100);
if (update)
{
dayset++;
if (dayset==1000)
dayset=0;
printf(lcd_putc,"\fDays: %3ld",dayset);
}
}
if (input(SET_PIN)==0)
{
set=1;
for (a=0;a<100;a++)
if (input(SET_PIN))
set=0;
else
delay_ms(100);
}
}while(set==0);
printf(lcd_putc,"\fSet @ %3ld days",dayset);
delay_ms(2000);
printf(lcd_putc,"\f");
set_timer1(0);
secs=0;
hours=0;
days=0;
mins=0;
enable_interrupts(global);
set=TRUE;
set_timer1(0x8000);
while(set==TRUE)
{
if (newsec)
{
newsec=FALSE;
secs++;
if (secs==60)
{
mins++;
secs=0;
//printf(lcd_putc,"\f%3ld mins left",(dayset-mins));
}
if (mins==60)
{
mins=0;
hours++;
}
if (hours==24)
{
hours=0;
days++;
}
if (COUNTDOWN==dayset)
set=FALSE;
}
}
disable_interrupts(global);
printf(lcd_putc,"\fActivated");
output_high(FIRE_PIN1);
for (secs=0;secs<600;secs++)
delay_ms(100);
output_high(FIRE_PIN2);
while(true);
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Wed Jul 28, 2004 4:27 am |
|
|
You are not telling us what crystal rate you are using, or what rate the cde is actually triggering at?.
However there ae some comments which wil cause problems latter. Don't try setting the timer to a value in the ISR. The problem is that arriving in the ISR itself, will take perhaps 30 cycles of the processor clock, and the timer will allready be at a count greater than 0 at this time. Also the timer, if it is running of a crystal at a rate asynchronous to the main processor clock, may increment, between loading the high byte, and the low byte into the timer register. The result will be garbage timing...
Do a search on this forum, for some of the posts about RTC's, done by Neutone. He posted a general purpose 'counter' code system, that allows accurate timekeeping, with a timer at any rate.
Seriously consider switching to a different chip, before spending too much time writing code for this. This processor, is flagged as 'obsolete/EOL', and you should be looking at one of the more modern 'pin equivalent' chips for any work now.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
monkeytennis
Joined: 18 Feb 2004 Posts: 16 Location: UK
|
|
Posted: Wed Jul 28, 2004 4:43 am |
|
|
Thanks for the prompt reply...
Well I do normally use the PIC18 series but in this particular case I have had to try and modify an existing circuit (as per Microchip Appnote AN582) which uses an external 32.768KHz watch crystal as the asynchronous input source for timer1 (apologies for omitting that information in my previous post).
I have seen it suggested before that one can set timer1 within the ISR but I can understand how this can cause a timing problem. I would use the internal clock source but the eventual idea is that I can leave the device in sleep mode to save on power consumption and only perminantly awaken it once the device has timed out, which after that point, the fate of the chip doesn't matter.
Cheers
I am considering using the RTCC as I have had success with this in the past but I am worried about levels of current consumption as this device may potentially have to count for several hundred days before timing out and it has to run from a single PP3 battery (with a LM7805). |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Wed Jul 28, 2004 8:21 am |
|
|
monkeytennis wrote: | Thanks for the prompt reply...
Well I do normally use the PIC18 series but in this particular case I have had to try and modify an existing circuit (as per Microchip Appnote AN582) which uses an external 32.768KHz watch crystal as the asynchronous input source for timer1 (apologies for omitting that information in my previous post).
I have seen it suggested before that one can set timer1 within the ISR but I can understand how this can cause a timing problem. I would use the internal clock source but the eventual idea is that I can leave the device in sleep mode to save on power consumption and only perminantly awaken it once the device has timed out, which after that point, the fate of the chip doesn't matter.
Cheers
I am considering using the RTCC as I have had success with this in the past but I am worried about levels of current consumption as this device may potentially have to count for several hundred days before timing out and it has to run from a single PP3 battery (with a LM7805). |
So, you are seeing the output change, more than once per second?.
Though the clock rate is slow compared to the processor, the counter will probably just about be due to update the register at the point you set the clock), so there might be a problem here. Does the clock have to display a value every second?. If not, consider going to leaving the clock 'free running', and just update the time every two seconds.
The alternative, is to massively speed up the interrupt handling. The problem is that the normal handler, saves lots of registers, and this takes time. It also checks what interrupt is in use. For your application, given this will be the only interrupt source, consider something like:
Code: |
#bit flob=0x5.3
int1 newsec=0;
//This code copied from CCS's glint.c
int save_w;
#locate save_w=0x7f
int save_status;
#locate save_status=0x20
#byte status = 3
#bit t1if=0xC.0
#INT_GLOBAL
void global(void) {
#asm
//store current state of processor
MOVWF save_w
SWAPF status,W
BCF status,5
BCF status,6
MOVWF save_status
#endasm
set_timer1(0x8000);
t1if=0;
flob=!flob;
newsec=TRUE;
#asm
SWAPF save_status,W
MOVWF status
SWAPF save_w,F
SWAPF save_w,W
#endasm
}
|
You would have to use 'fast_io' for port A with this, since I map your 'flob' variable directly to the output bit, and toggle this, without changing TRIS. Hence the TRIS register would have ot be set to 0 for this bit. This will take under 10uSec, to get to the timer update, and should work (you would need to check that the compiler does not change any other registers, but it ought to be OK).
Seriously, the 7805, will waste more power than the PIC!.
I hope you are really using something significantly 'lower power' for the regulator.
I'd look carefully round the crystal. It is possible that the oscillator is running on an overtone, and the circuit is therefore running fast. A scope on the oscillator output would show this. You might well find that putting the scope probe on the input pin, makes it all start working...
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Wed Jul 28, 2004 9:06 am |
|
|
Since Timer1, on the 16C64 that is in your header, is a 16 bit timer it will overflow at 0xFFFF (65535). This is equivalent to a count of 65536 when it rolls over to zero. If you were to select a crystal that would allow for a whole number division it would work better. For instance, I use a 19.6608MHZ crystal. Now, you divide that by 4 and you have the rate at which the Timer1 circuit will be clocking at (look at the data sheet block diagram and it shows the OSC/4 input to the clock circuit). If you were to divide this by the 65536, the rate that the timer will overflow, you will get a result of 75. If you delclare Timer1 to use the internal clock like this: setup_timer_1( T1_INTERNAL | T1_DIV_BY_1);
The following code will give you a function that you can keep a running Real Time clock going to trigger whatever you want at the proper time.
Code: |
#int_TIMER1
TIMER1_isr()
{
if(++counter >= 75)// enters every second
{
counter = 0;
if(++seconds >= 60)
{
seconds = 0;
if(++minutes >= 60)
{
minutes = 0;
if(++hours >= 12)
{
hours = 0;
// etc... etc... etc...
// you get the drift
}
}
}
}
}
|
Hope this helps.
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Wed Jul 28, 2004 9:30 am |
|
|
rnielsen wrote: | Since Timer1, on the 16C64 that is in your header, is a 16 bit timer it will overflow at 0xFFFF (65535). This is equivalent to a count of 65536 when it rolls over to zero. If you were to select a crystal that would allow for a whole number division it would work better. For instance, I use a 19.6608MHZ crystal. Now, you divide that by 4 and you have the rate at which the Timer1 circuit will be clocking at (look at the data sheet block diagram and it shows the OSC/4 input to the clock circuit). If you were to divide this by the 65536, the rate that the timer will overflow, you will get a result of 75. If you delclare Timer1 to use the internal clock like this: setup_timer_1( T1_INTERNAL | T1_DIV_BY_1);
The following code will give you a function that you can keep a running Real Time clock going to trigger whatever you want at the proper time.
Code: |
#int_TIMER1
TIMER1_isr()
{
if(++counter >= 75)// enters every second
{
counter = 0;
if(++seconds >= 60)
{
seconds = 0;
if(++minutes >= 60)
{
minutes = 0;
if(++hours >= 12)
{
hours = 0;
// etc... etc... etc...
// you get the drift
}
}
}
}
}
|
Hope this helps.
Ronald |
The problem with this is that the faster an oscillator runs, the more power it needs. This is why the 32768Hz crystal is commonly used for such timing applications. By default this will roll-over at two second intervals using Timer1.
On a chip with a hardware CCP, it'd be easy to reset the counter at this point. However he is moving the clock 'forwards' to get the same effect. In principle, this is fine, provided the clock update is done in less than 30uSec from the rollover. However using the standard interrupt handler this is by no means certain.
Seperately, there is another 'issue', with the idea of letting the chip sleep, and just leaving this counter running. The problem here is the oscillator start-up time on the main processor. A crystal oscillator takes many uSec to start. Hence when using the PIC like this, it is normal to use an inaccurate RC oscillator for the main processor clock, which starts quickly...
Personally, I'd consider a completely different approach, and use a CMOS RTC clock chip, running at 32768Hz, and program this to wake the processor every second. The procesor can then happily sleep, with the total power consumption at very low levels, and wake up for a few cycles every second as needed.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|