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

PIC16LF1823 TIMER1 and Sleep

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



Joined: 22 Apr 2005
Posts: 15

View user's profile Send private message

PIC16LF1823 TIMER1 and Sleep
PostPosted: Wed May 18, 2011 7:56 am     Reply with quote

Hello all,

I am trying to setup timer1 to wake up the pic from sleep using a 32khz xtal on the OSC1 and OSC2 pins. I can see the oscillator running while the pic is sleeping so I believe I am successful in that regard. My problem is in the TIMER1 isr I think. My main question at this point is this, how does one keep track of the "ints_per_second" of the 32khz xtal in the isr? I have looked thru several examples but they all seem to use the internal oscillator for timer1.

Do I use ((32768/4)/1))/(65535)) or would it be what ever the ext xtal freq is (32768 per sec)?

If I put a break point in the isr it will stop just prior to the if statement but nowhere else.

Thanks,
Mike

Code:
#include <16LF1823.h>
   #fuses INTRC_IO,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOFCMEN,NOCPD,NOWDT,PLL_SW
   #use delay(clock = 4000000)

[color=red]#define INTS_PER_SECOND 19         // (20000000/(4*4*65536))[/color]

int8 seconds;      // A running seconds counter
int8 int_count;    // Number of interrupts left before a second has elapsed


#INT_TIMER1                        // This function is called every time
void clock_isr() {                 // timer 1 overflows (65535->0), which is
                                   // approximately 19 times per second for
    if(--int_count==0) {           // this program.
      ++seconds;
      int_count = INTS_PER_SECOND;
    }
}


void main() {
   int_count = INTS_PER_SECOND;//((32768/4)/1))/(65535))
   setup_timer_1(T1_ENABLE_T1OSC | T1_DIV_BY_1 | T1_EXTERNAL);
   set_timer1(0);
   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);

   while(TRUE) {
   sleep();
   }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19255

View user's profile Send private message

PostPosted: Wed May 18, 2011 8:37 am     Reply with quote

Your interrupt will be called _once every two seconds_.
Timer1 is running off 32768Hz, and counts to 65536. So overflows once every two seconds. The 'ints_per_second' counter, is used when you are interrupting multipl times per second. You are not. Just increment your seconds by two, and trigger whatever you want to do in the main code.

Best Wishes
mharris27



Joined: 22 Apr 2005
Posts: 15

View user's profile Send private message

PostPosted: Wed May 18, 2011 9:36 am     Reply with quote

Thanks for the quick reply Ttelmah!

I have updated the code and its working better but there still seems to be a timing issue.

Code:
#include <16lf1823.H>

#device ICD=TRUE

   #fuses INTRC_IO,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOFCMEN,NOCPD,NOWDT,PLL_SW
   #use delay(clock = 4000000)

 
   #define Power_up       PIN_C5   //LED control (low is on)

   //Variable Declarations -- Globals
   int x,a;
   int seconds;     // A running seconds counter  ==> Timer 1
   int time;

   
void main()
{
   setup_adc_ports(NO_ANALOGS|VSS_VDD);

   time = 10;

//////////////Timer1 Setup
      setup_timer_1(T1_ENABLE_T1OSC | T1_EXTERNAL |T1_DIV_BY_2);
      enable_interrupts(INT_TIMER1);
      enable_interrupts(GLOBAL);
      set_timer1(0);
   seconds = 0;

   while(1){

      if (seconds >= time) {
         x = 1;
         output_low(Power_up);   //LED on
         delay_ms(250);
         output_high(Power_up);   //LED off
         delay_ms(250);
      }
   sleep();
   } //end while loop
} //End of main


#INT_TIMER1                     // This function is called every time
void clock_isr() {

   for (seconds=0; seconds<=time; ++seconds){
   x = 1;
   }   
}



It appears that no matter what I specify the time value the while loop is ran about ever 5 seconds or so. Why must the easiest things be so difficult...lol


ETA: If I step thru the program in the debugger I see no problems. The seconds counter does increase to what ever is define as "time" and then the while loop is ran. The seconds variable resets to 0 and starts over. My problem is "real time" at this point. Any ideas?
mharris27



Joined: 22 Apr 2005
Posts: 15

View user's profile Send private message

PostPosted: Wed May 18, 2011 2:39 pm     Reply with quote

okay... I have reworked the code a bit but I still cant get it to work right. Can anyone tell me where I have went astray?

MPLAB Ver 8.63
CCS Compiler Ver 4.121

The theory behind the code...

What I am trying to accomplish is this....I want the PIC to wake up AFTER an x number of seconds. In this case 10. The main oscillator is set to internal 4mhz allowing the use of the OSC I/O pins for an external 32khz xtal for timer1. It runs at 4mhz while awake but when its sleeping the external xtal is running timer1. So far I have confirmed that all of this works.
From the beginning of the While loop, the first thing I do is make sure that timer1 is disabled so I can write to the timer registers as recommended by Microchip. I preload the timer1 register to 32768. I am looking for a 1 second interrupt. The debugger does show that the registers are loaded with this value. At this point the external oscillator is now setup and enabled. Per scope all is well as I can see 32khz. I then clear the timer1 interrupt and enable both the timer1 and global interrupts. I set the seconds to 0 and then put it to sleep.

As it was pointed out to me earlier, the isr is serviced every 2 seconds so by setting the timer1 register to 32768 I am thinking that the isr will now be serviced once per second. Now every second the timer1 interrupt should now increment seconds up to the value of time and then wake up. If I step thru the debugger I can see second value increment, to 10, and then leave the isr and wake up the pic. However if I run it without breakpoints the while loop is run once a second.

I have a feeling this is something simple and I am just over looking it but for the life of me I cant see it. Please tell me what I am missing here.

Thanks,
Mike



Code:
#include <16lf1823.H>

#device ICD=TRUE

   #fuses INTRC_IO,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOFCMEN,NOCPD,NOWDT,PLL_SW
   #use delay(clock = 4000000)

   #define Power_up       PIN_C5   //LED control (low is on)

   int x;         // Debug
   int seconds;    // A running seconds counter  ==> Timer 1
   int time;      // Amount of time to continue interrupts before re-entering the while loop

void main()
{

   time = 10;

   while(1){

    setup_timer_1(T1_DISABLED);                              // Disable TIMER1   
   set_timer1(32768);                                    // Preload TMR1H:TMR1L register pair for 1 second counter.
      setup_timer_1(T1_ENABLE_T1OSC | T1_EXTERNAL | T1_DIV_BY_1);      // Setup and Enable TIMER1 for 32khz XTAL (32768hz)
   clear_interrupt(int_timer1);                           // Clear TIMER1 Interrupt.
    enable_interrupts(INT_TIMER1);                           // Enable TIMER1 Interrupt.
      enable_interrupts(GLOBAL);                              // Enable Global Interrupts.
   seconds = 0;                                       // A running seconds counter  ==> Timer 1 reset to 0.

   sleep();                                          // Put PIC to sleep.

//// Once PIC wakes up ///////

    setup_timer_1(T1_DISABLED);                              // Disable TIMER1

   if (seconds >= time) {                                 // If seconds is less than or equal to time
      output_low(Power_up);                              // LED on
      delay_ms(50);                                    // 50ms delay
      output_high(Power_up);                              // LED off
       delay_ms(50);                                    // 50ms delay
      x = 1;                                          // Debug spot
      } // End of If
   } // End while loop
} // End of main

#INT_TIMER1                                                // TIMER1 ISR
void clock_isr() {
   for (seconds=0; seconds<=time; ++seconds){                  // Stay in ISR until seconds = time
   } // End for loop
} // End ISR   
mharris27



Joined: 22 Apr 2005
Posts: 15

View user's profile Send private message

PostPosted: Fri May 20, 2011 7:50 am     Reply with quote

Anyone?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri May 20, 2011 5:14 pm     Reply with quote

Here's a demo program that I just wrote. It seems to work. A stopwatch
shows that it sleeps for 10 seconds. It wakes up once per second to check
the time. I tested this with a 16F1824 (that's in the same PIC family as
your PIC), and compiler version 4.121. I used a Microchip "low pin count"
board for the test, and added a 32.768 KHz crystal across pins 2 and 3,
with a 22 pf capacitor to ground, on each pin. I only tested it with delay
times of 1, 2, 3, 5, 10 seconds.
Code:

#include <16F1824.H>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)

#define LED1  PIN_C1
#define LED2  PIN_C2

int8 sleep_timer = 0;

#define interrupt_enabled(x)  !!(*make8(x,1) & make8(x,0))

//-------------------------------------------
#byte T1CON = getenv("SFR:T1CON")
#bit  TMR1ON = T1CON.0
#byte TMR1H = getenv("SFR:TMR1H")
#byte TMR1L = getenv("SFR:TMR1L")

#define timer1_start() TMR1ON = 1;
#define timer1_stop() TMR1ON = 0;


// When Timer1 rolls over from 0xFFFF to 0x0000,
// this interrupt routine will be executed.
#int_timer1
void timer1_isr(void)
{
if(sleep_timer)
  {
   sleep_timer--;
   
   timer1_stop();
   bit_set(TMR1H, 7);  // Set Timer1 MSB to 0x80   
   timer1_start();
  }

}

//-------------------------------------------
// Sleep for the specified time of 1 to 255 seconds,
// Note: The PIC will actually wake-up once per second
// briefly, and check the remaining time.

void sleep_for_x_seconds(int8 seconds)
{
int8 global_interrupts_enabled;

sleep_timer = seconds;  // Load sleep count into global variable

// Preset Timer1 so it will roll over in 1 second.
timer1_stop();
set_timer1(32768);   
timer1_start();

if(interrupt_enabled(GLOBAL))
   global_interrupts_enabled = TRUE;

clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);

// Wait in this loop until the desired delay in seconds is done.
while(sleep_timer)
  {
   sleep();
  }

// We're done, so disable Timer1 interrupts.
disable_interrupts(INT_TIMER1);

// If global interrupts were disabled outside of
// of this routine, then disable them before we exit.
if(global_interrupts_enabled == FALSE)
   disable_interrupts(GLOBAL);

}


//==========================================
void main()
{
// Start the Timer1 oscillator.   
// Allow 5 seconds for it to start.
setup_timer_1(T1_EXTERNAL | T1_ENABLE_T1OSC   | T1_DIV_BY_1);
delay_ms(5000);


output_high(LED1);  // Turn on LED1 to show start of sleep.

sleep_for_x_seconds(10);

output_high(LED2);   // Turn on LED 2 to show end of sleep.

while(1);
}
mharris27



Joined: 22 Apr 2005
Posts: 15

View user's profile Send private message

PostPosted: Mon May 23, 2011 6:20 am     Reply with quote

Thanks for the help PCM. Its much appreciated.
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