|
|
View previous topic :: View next topic |
Author |
Message |
Chubbs
Joined: 02 May 2005 Posts: 14
|
sleep() trouble |
Posted: Mon May 16, 2005 6:51 am |
|
|
Hello all, I just got a problem with the sleep function. I am using the 16F876A PIC. I am running a couple of sensors(smoke and CO) and all I want to do is get their outputs (voltages) and display them on a LCD. I can do this ok, but to save power I only want to sample the sensors once every 30 seconds say and in between put the PIC to sleep. The code that I'm using is below:
Code: |
#include <16F876A.h>
#device adc=10
#use delay(clock=4000000)
#fuses NOWDT,HS, NOPUT, NOPROTECT, NODEBUG, BROWNOUT, NOLVP, NOCPD, NOWRT
#include <LCD.C>
#include <stdlib.h>
#include <math.h>
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
void main()
{
set_tris_a(0xFF);
setup_adc_ports( AN0_AN1_AN4_VREF_VREF );
setup_adc( ADC_CLOCK_DIV_8 );
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_8|T1_CLK_OUT);
setup_timer_2(T2_DISABLED,0,1);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
lcd_init();
LCD_disp(); //haven't included it just displays a welcome message//
// Loop to constantly read the values and display to LCD //
while(TRUE)
{
get_val();
set_timer1(0);
sleep();
}
}
void get_val(void)
{
// Do the ADC for CO to check for alarm state //
set_adc_channel( 1 );
delay_us(10);
CO = Read_ADC();
CO=(5*(CO/1024));
// Check for CO alarm state //
if (CO > 1)
{
//Sound Alarm //
output_high(pin_C3);
delay_ms(500);
output_low(pin_C3);
}
// output to LCD and datalogger every xx seconds//
set_adc_channel( 0 );
delay_us(10);
smoke = Read_ADC();
smoke=(5*(smoke/1024));
smoke=(smoke*8.1)/(5.1);
lcd_gotoxy(3,1);
printf(lcd_putc,"S: %1.3fv",smoke);
lcd_gotoxy(4,2);
printf(lcd_putc,"CO: %1.3fv",CO);
printf("\n\rSmoke: %1.3f CO: %1.3f\n\r",smoke,CO);
}
|
Everthing else works ok, the sleep function only works once though. First time through it will get the values, display and send them, then go into sleep mode for around 16 seconds. It then runs the while loop over and over again without going into sleep mode. I'm trying to use timer1 to get the PIC out of sleep, with a 32KHz oscillator.
Its probably something simple, but I just can't get it.
Also I've noticed the ADC works in sleep mode, can I save any more power by disabling it before going into sleep mode and then re-initiating it before the next sample??
Any help is greatly appreciated. Thanks |
|
|
Ttelmah Guest
|
|
Posted: Mon May 16, 2005 8:37 am |
|
|
You need to clear the interrupts before entering sleep.
Interrupts are not automatically cleared, and if you read the chip data sheet about using sleep, there is the critical paragraph, which says 'if the interrupt occurs before executing sleep, the sleep instruction will complete as a NOP'. Basically once the interrupt has triggered, since you never clear the interrupt flag, the sleep instructions in future will be skipped...
Yes, turning off all unused peripherals, helps reduce power consumption.
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon May 16, 2005 7:46 pm |
|
|
You also enabled an interrupt but didn't supply a handler for it. That is a big no no. The interrupt flag will never get cleared and the interrupt will continually be triggered. |
|
|
Chubbs
Joined: 02 May 2005 Posts: 14
|
|
Posted: Mon May 16, 2005 11:58 pm |
|
|
Thanks, I was able to get it working by putting a clear_interrupt(INT_TIMER1); command before the sleep command.
I wanted to add another feature to check the threshold voltage of the detector which can be manually changed. Seeing as though the PIC is in sleep mode for 16 seconds, I decided to try to add an external button interupt. It worked ok and interrupted every time it was pressed and executed its code, problem is that the sleep timer1 no longer works it doesn't continue with the main while loop( the values are only updated once). I'm not very familiar with interrupts and it may be something simple the code is shown below:
Code: |
#include <16F876A.h>
#device adc=10
#use delay(clock=4000000)
#fuses NOWDT,HS, NOPUT, NOPROTECT, NODEBUG, BROWNOUT, NOLVP, NOCPD, NOWRT
#include <LCD2.C>
#include <stdlib.h>
#include <math.h>
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
//********************* Defined Functions and Variables **********************//
void LCD_disp(void);
void get_val(void);
void threshold(void);
float smoke;
float CO;
float thresh;
int j;
//****************************************************************************//
void main()
{
set_tris_a(0xFF);
set_tris_c(0b11101101);
setup_adc_ports( AN0_AN1_AN4_VREF_VREF );
setup_adc( ADC_CLOCK_DIV_8 );
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_8|T1_CLK_OUT);
setup_timer_2(T2_DISABLED,0,1);
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
lcd_init();
LCD_disp();
// Loop to constantly read the values and display to LCD //
while(TRUE)
{
get_val();
clear_interrupt(INT_TIMER1);
set_timer1(0);
sleep();
}
}
//****************************************************************************//
#int_ext
void ext_isr()
{
lcd_putc('\f');
lcd_gotoxy(1,1);
lcd_putc("Smoke Threshold:");
j=0;
while(TRUE)
{
// Display the smoke threshold value //
set_adc_channel( 4 );
delay_us(10);
thresh = Read_ADC();
thresh=(5*(thresh/1024));
lcd_gotoxy(7,2);
printf(lcd_putc,"%1.2f",thresh);
if (j==50000)
{
// Clear screen //
lcd_putc('\f');
break;
}
j++;
}
}
/************************* Get smoke value and display **********************//
void get_val(void)
{
// Do the ADC for CO to check for alarm state //
set_adc_channel( 1 );
delay_us(10);
CO = Read_ADC();
CO=(5*(CO/1024));
// Check for CO alarm state //
if (CO > 1)
{
//Sound Alarm //
output_high(pin_C3);
delay_ms(500);
output_low(pin_C3);
}
// output to LCD and datalogger every xx seconds//
set_adc_channel( 0 );
delay_us(10);
smoke = Read_ADC();
smoke=(5*(smoke/1024));
smoke=(smoke*8.1)/(5.1);
lcd_gotoxy(3,1);
printf(lcd_putc,"S: %1.3fv",smoke);
lcd_gotoxy(4,2);
printf(lcd_putc,"CO: %1.3fv",CO);
printf("\n\rSmoke: %1.3f CO: %1.3f\n\r",smoke,CO);
}
//****************************************************************************//
|
It may be something simple, I've been told it could be the while loop in the ext_int, but it works fine. Any help would be appreciated. Thanks |
|
|
Chubbs
Joined: 02 May 2005 Posts: 14
|
|
Posted: Mon May 16, 2005 11:59 pm |
|
|
Last edited by Chubbs on Tue May 17, 2005 8:27 am; edited 1 time in total |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue May 17, 2005 6:13 am |
|
|
Read my post. If you still don't understand then comment out this line
Code: | enable_interrupts(INT_TIMER1);
|
|
|
|
Chubbs
Joined: 02 May 2005 Posts: 14
|
|
Posted: Tue May 17, 2005 7:59 am |
|
|
Commenting out the
Code: | enable_interrupts(INT_TIMER1); |
did not give the desired result.
This is what I want to do:
1) Sample the data and send the results
2) Put the PIC in sleep mode
3) Wake up from sleep mode and repeat from step 1 when timer1 overflows. (which should be in 16seconds)
4) Simultaneously allow the user to press a button to check the status of the threshold via an external interrupt, which should work any time it is pressed regardless of the state of the PIC, then return to the main loop.
I think I understand what you are saying with the interrupt handler, but I don't want it do anything when timer1 overflows just to come out of sleep and continue with the rest of the program. It worked ok when I had the same code but with no external interrupt, it woud update the results once every 16 seconds and sleep in between. I figure that if the PIC is in sleep mode for 16 seconds and only active for a very short period, I would need an external interupt to trigger a threshold check which would then return to the program after a certain time.
Thats basically what I'm trying to do, if you could point out what I'm doing wrong and what I have to change it would be a big help cause I've been trying everthing and nothing seems to work. |
|
|
Chubbs
Joined: 02 May 2005 Posts: 14
|
|
Posted: Tue May 17, 2005 8:23 am |
|
|
I should have put in the results obtained from the code above.
The PIC samples the data once then goes into sleep mode for the 16 seconds. During this time if the external interrupt is triggered the threshold is displayed, when it finishes the ex_interrupt the screen is then updated with a new sample and the PIC goes into sleep mode. However after the 16 seconds have elapsed the PIC goes out of sleep mode but nothing else happens, the program no longer runs. The only thing that continues to work is the ex_interrupt but this time when it finishes it just leaves the LCD blank cause the rest of the program stops running. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue May 17, 2005 8:26 am |
|
|
Add
after the sleep(); instruction and see what happens.
After reading the section on SLEEP add the following:
Code: |
#INT_TIMER1
void timer1(void)
{
}
|
And add back the enable_interrupts(INT_TIMER1)
You will need to make sure that the compiler doesn't optimize out the timer1() function. It shouldn't but with this compiler who knows! |
|
|
Chubbs
Joined: 02 May 2005 Posts: 14
|
|
Posted: Tue May 17, 2005 8:44 am |
|
|
I't won't compile with a NOP(); command.
PCW Compiler
IDE version 3.212
PCB version 3.213
PCM version 3.213 |
|
|
Chubbs
Joined: 02 May 2005 Posts: 14
|
|
Posted: Tue May 17, 2005 9:07 am |
|
|
Code: | #INT_TIMER1
void timer1(void)
{
}
|
Worked perfectly, thanks.
One last thing what would be the best way to increase the amount of time in sleep mode?
Anything in the function above is run at normal power isn't it? |
|
|
|
|
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
|