CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Sleep is taking imprecise life time.

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
rsegecin



Joined: 23 Aug 2011
Posts: 12

View user's profile Send private message

Sleep is taking imprecise life time.
PostPosted: Wed Aug 24, 2011 11:35 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Aug 24, 2011 11:48 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Aug 24, 2011 12:26 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Aug 25, 2011 8:39 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Aug 25, 2011 3:09 pm     Reply with quote

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

View user's profile Send private message

Assign the prescaler to the WDT
PostPosted: Fri Aug 26, 2011 12:19 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Aug 26, 2011 1:47 pm     Reply with quote

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

View user's profile Send private message

I'm sorry it's HS there. The PIC has an external clock of 20
PostPosted: Fri Aug 26, 2011 3:17 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Aug 26, 2011 3:22 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Aug 27, 2011 2:20 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Aug 30, 2011 12:31 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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