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 CCS Technical Support

sleep() trouble

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



Joined: 02 May 2005
Posts: 14

View user's profile Send private message

sleep() trouble
PostPosted: Mon May 16, 2005 6:51 am     Reply with quote

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







PostPosted: Mon May 16, 2005 8:37 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon May 16, 2005 7:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 16, 2005 11:58 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 16, 2005 11:59 pm     Reply with quote



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

View user's profile Send private message Send e-mail

PostPosted: Tue May 17, 2005 6:13 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue May 17, 2005 7:59 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue May 17, 2005 8:23 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Tue May 17, 2005 8:26 am     Reply with quote

Add
Code:
NOP();

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

View user's profile Send private message

PostPosted: Tue May 17, 2005 8:44 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue May 17, 2005 9:07 am     Reply with quote

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?
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