View previous topic :: View next topic |
Author |
Message |
rsegecin
Joined: 23 Aug 2011 Posts: 12
|
Sleep is taking imprecise life time. |
Posted: Wed Aug 24, 2011 11:35 am |
|
|
Hello, I'm trying to build a project using Pic16f688 that sleep for an 1 hour wake up using the WDT do some stuff and go back to sleep again repeating this same process endlessly. I know that the WDT can only reset it self in a maximum 268s, so I'm going have to count until it lasts for one hour, but it seems that the time of sleep is imprecise, I used the code below just to verify if the WDT is waking up and its taking around 5 min and 20 sec.
Code: |
#include "16F688.h"
#include "Timer.h"
#fuses HS, WDT, NOBROWNOUT, MCLR
#use delay(clock = 20Mhz)
void main()
{
setup_wdt(WDT_2304MS | WDT_TIMES_128);
set_tris_A(0x00);
set_tris_C(0x00);
//Timer();
output_bit(PIN_A0, 0);
delay_ms(1000);
output_bit(PIN_A0, 1);
delay_ms(1000);
output_bit(PIN_A0, 0);
//restart_wdt();
sleep();
switch (restart_cause())
{
case WDT_TIMEOUT:
{
output_bit(PIN_C0, 1);
break;
}
case NORMAL_POWER_UP:
{
//output_bit(PIN_C0, 1);
break;
}
default :
output_bit(PIN_A0, 1);
output_bit(PIN_C0, 1);
break;
}
while (true) { }
}
|
Code: |
#ifndef __TIMER_H__
#define __TIMER_H__
unsigned int segundos = 0;
unsigned int16 minutos = 0;
#int_timer0
void interruptTimer0()
{
static int counter;
counter++;
if (counter > 153)
{
if (segundos >= 60)
{
segundos = 0;
if (minutos >= 1440)
{
minutos = 0;
}
minutos++;
}
counter = 0;
segundos++;
}
}
void Timer()
{
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_128);
enable_interrupts(global | int_timer0);
}
void ResetTimer()
{
segundos = 0;
minutos = 0;
}
#endif
|
I also attempted to use timer0 together with WDT, because I didn't fully understood the pic's datasheet as it says that you can't use the same prescaler for both timer0 and WDT in chap. 5.1.3 but at 11.5.1 it says that a new prescaler was added giving to the WDT a range of 1s to 268s, may be it was refering to the same prescaler. I wonder if I use a external clock for the WDT I could use timer0 together with sleep not having the draw back of consuming more power that I'm trying to save in first place.
PS: I'm sure that the osc of 20 Mhz is working fine.
Any help will be deeply appreciated.
Thank you very much. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 24, 2011 11:48 am |
|
|
Quote: | it seems that the time of sleep is imprecise
|
Download the 16F688 data sheet and look in the Electrical Specifications
chapter in the back of the data sheet. Look at the spec for the WDT
period in the following table. It varies greatly over temperature.
Code: |
TABLE 14-4: RESET, WATCHDOG TIMER, OSCILLATOR START-UP TIMER,
POWER-UP TIMER AND BROWN-OUT RESET PARAMETERS
Param Sym Characteristic Min Typ Max Units Conditions
No.
31 TWDT Watchdog Timer 10 26 29 ms VDD = 5V,
Timeout Period -40°C to +85°C
(no prescaler)
|
If you want a more precisely timed sleep period, add a 32.768 KHz
watch crystal (and appropriate capacitors) to the Timer1 oscillator pins
and use it to wake up briefly once per second. Count the seconds in the
#int_timer1 interrupt. There is sample code on the forum for this. |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Wed Aug 24, 2011 12:26 pm |
|
|
The watchdog is designed to be ultra-reliable, but not at all precise. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
rsegecin
Joined: 23 Aug 2011 Posts: 12
|
|
Posted: Thu Aug 25, 2011 8:39 am |
|
|
At first, thank you for the replies. I still wondering if I can use both the WDT and timer 0 at same time without having to add an extra clock in the pic 16f688. Could anyone point out a code example of using the two of them together? I've been looking for it but I haven't found yet.
Thank you very much. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Aug 25, 2011 3:09 pm |
|
|
To do that, I need to know which module you want to assign the prescaler
to, the WDT or Timer0 ?
If WDT has the prescaler, the maximum WDT timeout is 268 seconds.
If it doesn't have it, the max timeout is 1 second.
If Timer0 has the prescaler, it can divide the input clock by up to 256.
If it doesn't have it, the input clock divisor is 1 (ie., not divided down at all).
So which module do you want to assign the prescaler to ? |
|
|
rsegecin
Joined: 23 Aug 2011 Posts: 12
|
Assign the prescaler to the WDT |
Posted: Fri Aug 26, 2011 12:19 pm |
|
|
Hi PCM programmer. I'd like to assign the prescaler to the WDT to wake up the pic as little as I can because I'm only interested to check up once each hour but I'm also interested to use the timer0 if possible to implement a internal real time clock. Here is the code that I wrote just to test the WDT which it's not working, can you tell me what is wrong with it? I programmed here in the chip and it seems to be stopping right after I set output_high(PIN_C2) on the delay.
Code: |
#include <16F688.h>
#fuses INTRC_IO, WDT
#use delay (clock=20Mhz)
void BlinkLedAndSleep()
{
output_high(PIN_A0);
delay_ms(1000);
output_low(PIN_A0);
restart_wdt();
sleep();
}
void main()
{
output_high(PIN_C2);
delay_ms(1000);
output_low(PIN_C2);
switch(restart_cause())
{
case WDT_FROM_SLEEP:
BlinkLedAndSleep();
break;
case NORMAL_POWER_UP:
setup_wdt(WDT_2304MS);
set_tris_a(0x00);
BlinkLedAndSleep();
break;
default:
output_high(PIN_A1);
delay_ms(1000);
output_low(PIN_A1);
break;
}
while (true)
{
}
}
|
Thank you again. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Aug 26, 2011 1:47 pm |
|
|
Quote: | #include <16F688.h>
#fuses INTRC_IO, WDT
#use delay (clock=20Mhz)
|
The 16F688 can't run at 20 MHz from its internal oscillator. The data sheet
says the maximum is 8 MHz. So, this is not a real program. Or, it's being
run on Proteus and not on real hardware. |
|
|
rsegecin
Joined: 23 Aug 2011 Posts: 12
|
I'm sorry it's HS there. The PIC has an external clock of 20 |
Posted: Fri Aug 26, 2011 3:17 pm |
|
|
ops I'm sorry it's HS there. The PIC has an external clock of 20 Mhz. But the code still not doing as I intended to do. The restart_cause() it's looping back as MCLR_FROM_RUN instead to come back as WDT_FROM_SLEEP. I think that delay_ms triggers the pic to restart as MCLR, I can't tell you that for sure because I can't debug the pic, each output there is a led, that's how I know if the code reached there or not, so if I remove the delay_ms I won't know if the code is working properly.
Thank you very much PCM programmer for your patience. =D |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Aug 26, 2011 3:22 pm |
|
|
Quote: | I think that delay_ms triggers the pic to restart as MCLR
|
If that's what you suspect, then read the manual for #use delay() and
add the restart_wdt parameter to restart the WDT inside the delay_ms()
statements:
Quote: |
#include <16F688.h>
#fuses HS, WDT
#use delay (clock=20Mhz, restart_wdt) |
|
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Aug 27, 2011 2:20 am |
|
|
WDT based sleep comes into play, if you want ultra low power consumption, e.g. for a battery powered device. If low power consumption isn't an objective, you better keep the regular (crystal or fast RC) clock running.
If you want both, low power sleep and accurate timing, a 32 kHz crystal oscillator ´can be an option. But it's not actually ultra low power compared to an external real time clock with sub µA supply current. |
|
|
rsegecin
Joined: 23 Aug 2011 Posts: 12
|
|
Posted: Tue Aug 30, 2011 12:31 pm |
|
|
Hi PCM programmer I didn't find any good documentation about the delay_ms, the help file that is installed in the MPLab with CCS doesn't provide much of a help. But anyway I managed to make the code work. The WDT is lasting a lot more than it's specified in the datasheet it's lasting around 5 sec (measured with an oscilloscope) with no prescaler set and 10min 33sec with the prescaler set to 128. FvM thank you the tip you gave, if I test with this crystal osc of 32 I'll post the results. Here is the code to anyone who are or will interested.
Code: |
#include <16F688.h>
#fuses WDT, HS, NOBROWNOUT
#use delay (clock=20Mhz, restart_wdt)
void BlinkLedAndSleep()
{
int1 a;
a = read_eeprom(0x01);
if (a == 0)
{
output_high(PIN_A0);
write_eeprom(0x01, 1);
}
else
{
output_low(PIN_A0);
write_eeprom(0x01, 0);
}
restart_wdt();
setup_wdt(WDT_2304MS | WDT_TIMES_128);
sleep();
}
void main()
{
int1 a;
a = read_eeprom(0x02);
set_tris_a(0x00);
output_a(0);
if (a == 0)
{
output_high(PIN_A1);
write_eeprom(0x02, 1);
}
else
{
output_low(PIN_A1);
write_eeprom(0x02, 0);
}
switch(restart_cause())
{
case WDT_FROM_SLEEP:
BlinkLedAndSleep();
break;
case NORMAL_POWER_UP:
BlinkLedAndSleep();
break;
default:
break;
}
while (true)
{
}
}
|
Thank you all. |
|
|
|