![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
WDT and TIMER0 issues on 16F876A |
Posted: Fri Jul 08, 2011 2:43 pm |
|
|
I think that WDT is resetting the uC too quickly respect to my settings. To avoid the reset I should restart_wdt() at least every 2 seconds (2304 milliseconds).
In my test program there are two leds, a red one is turned ON at the beginning and OFF after a delay which I can change; then, if there is no reset, the green led is blinking every second. On the other hand, if there is a reset I see the red led stable ON.
The problem is that using a delay of just 20ms the reset is already happening! (red led is stable ON). It should not, since reset the WDT within 2000 milliseconds should be enough...
By giving 10 ms delay, the red flashes once very fast and then the green blink every second. (hence there is no watchdog reset).
Code: | #include <16F876A.h>
#fuses XT, PUT, WDT, NOLVP
#use delay(clock = 4000000)
#define green PIN_C5
#define red PIN_B0
int1 flashing;
int8 centisec;
//--------------------------------------------------------------------------
#int_RTCC
void RTCC_isr(void){ //Interrupt Service Routine every 1/100 of second
set_timer0(98);
centisec++;
if (centisec>49){
centisec=0;
flashing=!flashing;
}
}
//--------------------------------------------------------------------------
void main() {
setup_wdt(WDT_2304MS);
set_tris_a(0x3F);
set_tris_b(0xC8);
set_tris_c(0x84);
setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_64);
enable_interrupts(int_rtcc);
enable_interrupts(global);
restart_wdt();
output_bit(red,1);
delay_ms(20); //value I change to understand the WDT
output_bit(red,0);
while(1){
output_bit(green,flashing);
restart_wdt();
}
} |
Last edited by webgiorgio on Wed Jul 27, 2011 5:25 am; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Fri Jul 08, 2011 3:09 pm |
|
|
Key is in the data sheet.
On older chips (like the 16F876), the watchdog prescaler is _shared_ with the timer0 prescaler. Look at figure 5.1 in the data sheet. You can have a prescaler for the watchdog, _or_ for timer0, but not both. As soon as you select a prescaler for timer0, the prescaler is _disconnected_ from the watchdog, and the connection goes directly. Selecting a prescaler for timer0, sets the PSA bit to '0', and the watchdog drops to a nominal 18mSec timing (may be as low as 7mSec in some cases....).
Register 5-1. Bit 3.
On most latter chips there is a separate prescaler.
You need to stop using the prescaler for timer0. Better to use another timer for your interrupt (timer2 in particular, since you can program nice decimal counts with this, without trying to reload the timer).
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Wed Jul 27, 2011 4:59 am |
|
|
Hi, thank you for answare.
Can I still use timer0 without prescaler? it would be an interrupt every 255 us, isn't it too often?
It is just a curiosity, I know I can use timer1 and timer2. |
|
![](templates/subSilver/images/spacer.gif) |
webgiorgio
Joined: 02 Oct 2009 Posts: 123 Location: Denmark
|
|
Posted: Wed Jul 27, 2011 5:34 am |
|
|
I would like to use the watchdog and the interrupt from timer0.
Therefore I do not select prescaler for timer0 (setup_timer_0 (RTCC_INTERNAL); instead of setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_64); )
So the order of the instruction should not make any difference, but it does! (look at the first two rows of my code)
This works:
Code: |
setup_timer_0 (RTCC_INTERNAL);
setup_wdt(WDT_2304MS);
restart_wdt();
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );
setup_timer_2 (T2_DIV_BY_16,255, 16);
enable_interrupts(int_TIMER0);
enable_interrupts(int_TIMER1);
enable_interrupts(int_TIMER2);
enable_interrupts(global); |
while this does not work:
Code: |
setup_wdt(WDT_2304MS);
setup_timer_0 (RTCC_INTERNAL);
restart_wdt();
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );
setup_timer_2 (T2_DIV_BY_16,255, 16);
enable_interrupts(int_TIMER0);
enable_interrupts(int_TIMER1);
enable_interrupts(int_TIMER2);
enable_interrupts(global); |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19369
|
|
Posted: Wed Jul 27, 2011 6:23 am |
|
|
Yes.
Problem is that setting up a value of '0' for the prescaler, gives division by two, so the prescaler is automatically selected. You have to use:
Code: |
setup_wdt(WDT_2304MS);
setup_timer_0 (RTCC_INTERNAL | RTCC_DIV_1);
|
Which then says "don't use the prescaler".
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
|