|
|
View previous topic :: View next topic |
Author |
Message |
mharris27
Joined: 22 Apr 2005 Posts: 15
|
PIC16LF1823 TIMER1 and Sleep |
Posted: Wed May 18, 2011 7:56 am |
|
|
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: 19513
|
|
Posted: Wed May 18, 2011 8:37 am |
|
|
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
|
|
Posted: Wed May 18, 2011 9:36 am |
|
|
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
|
|
Posted: Wed May 18, 2011 2:39 pm |
|
|
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
|
|
Posted: Fri May 20, 2011 7:50 am |
|
|
Anyone? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri May 20, 2011 5:14 pm |
|
|
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
|
|
Posted: Mon May 23, 2011 6:20 am |
|
|
Thanks for the help PCM. Its much appreciated. |
|
|
|
|
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
|