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

PIC16F913 Sleep With LCD

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



Joined: 23 Oct 2018
Posts: 5

View user's profile Send private message

PIC16F913 Sleep With LCD
PostPosted: Mon Sep 19, 2022 12:47 pm     Reply with quote

hello. I tried to make my post as short as possible, but I couldn't do it, So here it is:

I am working on a counter project that will use a 3V coin battery and an segment LCD. It will be in sleep most of the time, and the LCD must stay ON to display the count during sleep.
I was using:
* PIC16F913
* CCS V 5.071
* 3V coin battery with a 2V regulator (Idle current for the regulator is 1uA).
* Clock is a low power 32.768kHz crystal
* LCD (2V 1/4 duty 1/3 bias) with three 1M res for LCD biasing.
* 330K Res pull up at the MCLR pin.
* PIN-B0 was pulled down to GND through a 1M Res, and will be connected
to 2V supply using a bush button to wake up from sleep.
The code is: ( to demonstrate the idea I Just use an 8bit int variable for the count value)



Code:



#include <16F913.h>

#fuses LP, NOWDT, PUT, MCLR, NOBROWNOUT, NOFCMEN, NOIESO
#use delay(clock=32768)


int count1 = 8;   // 1st digit
int count2 = 8;   // 2nd digit
int count3 = 8;   // 3rd digit
int count4 = 8;    // 4th digit
int count5 = 8;    // 5th digit

/////////////////////////////////////////////////////////////////////////////////////////
//                                 LCD Configuration                                   //
/////////////////////////////////////////////////////////////////////////////////////////
// Digit segments  A        B         C          D         E         F         G        DP
//                 b7       b6        b5         b4        b3        b2        b1       b0
#define DIGIT1  COM0+13,  COM1+13,  COM2+13,  COM3+13,  COM2+14,  COM0+14,  COM1+14,  COM3+14
#define DIGIT2  COM0+3,   COM1+3,   COM2+3,   COM3+3,   COM2+2,   COM0+2,   COM1+2,   COM3+2
#define DIGIT3  COM0+1,   COM1+1,   COM2+1,   COM3+1,   COM2+8,   COM0+8,   COM1+8,   COM3+8
#define DIGIT4  COM0+9,   COM1+9,   COM2+9,   COM3+9,   COM2+10,  COM0+10,  COM1+10,  COM3+10
#define DIGIT5  COM0+11,  COM1+11,  COM2+11,  COM3+11,  COM2+6,   COM0+6,   COM1+6,   COM3+6
//       ComX+Y is combination of Backplan0-3 and Segment0-SegmentXX
////////////////////////////////////////////////////////////////////////////////////////
//           character         0    1    2    3    4    5    6    7    8    9   Null

byte const Digit_Map_1[11] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6,0x00};

#define blank   10

//////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////////////////
//                          Segments Initilization
// Seg15 Seg14 Seg13 Seg12 Seg11 Seg10 Seg9 Seg8 Seg7 Seg6 Seg5 Seg4 Seg3 Seg2 Seg1 Seg0
//  0/1   0/1   0/1   0/1   0/1   0/1  0/1  0/1   0/1  0/1 0/1   0/1 0/1  0/1  0/1   0/1
//  if bit_SegX is 1, SegX is set as Segment Output. Otherwise
/////////////////////////////////////////////////////////////////////////////////////////

#define Segments 0x6f4e    // Initialize LCD SegmentX

////////////////////////////////////////////////////////////////////////////////////////


void Display()
{
      lcd_symbol (Digit_Map_1[count1], DIGIT1); // from left to right
      lcd_symbol (Digit_Map_1[count2], DIGIT2); // from left to right 
      lcd_symbol (Digit_Map_1[count3], DIGIT3); // from left to right                 
      lcd_symbol (Digit_Map_1[count4], DIGIT4); // from left to right
      lcd_symbol (Digit_Map_1[count5], DIGIT5); // from left to right
}

///////////////////////////////////////////////////////////////////////////////
void main()
{
   set_tris_a (0xff);  // avoid floating
   set_tris_b (0xff);  // avoid floating
   set_tris_c (0xff);  // avoid floating
   set_tris_e (0xff);  // avoid floating
   
   output_high(pin_A0);  // Make all unused pins to High
   output_high(pin_A1);
   output_high(pin_A4);
   output_high(pin_A5);
   output_high(pin_A6);
   output_high(pin_A7);
   output_high(pin_E3);
   
   setup_counters (T0_EXT_L_TO_H, T0_DIV_1); // // disable timer 0 ??????
   
   setup_timer_1 (T1_DISABLED);     // disable timer 1

   setup_timer_2 (T2_DISABLED,0,1);     // disable timer 2

   setup_vref (FALSE);              // disable Voltage reference

   setup_adc (ADC_OFF);             // disable ADC

   setup_wdt (WDT_OFF);             // disable Watch Dog Timer

   setup_ccp1 (CCP_OFF);            // disable compare/capture
   
   setup_comparator (NC_NC_NC_NC);  // disable comparators
   
   setup_spi(SPI_DISABLED);
   
   

   
   #byte VRCON = 0x009D   // VR control register
         VRCON = 0x00;    // VR is disabled
         
   #byte CMCON0 = 0x009C  // Comparator configuration register
         CMCON0 = 0x0007; // Comparator is disabled
         
   #byte ANSEL = 0x0091   // Analog select register
         ANSEL = 0x00;    // Digital I/O
         
   #byte ADCON0 = 0x001F  // A/D control register
         ADCON0 = 0x00;   // A/D is shut off
         
    ext_int_edge(L_TO_H);      // init interrupt triggering for button press
    clear_interrupt(INT_EXT);
    disable_interrupts(GLOBAL);
    enable_interrupts(INT_EXT);
   
    setup_lcd(LCD_MUX14|LCD_INTRC,7, Segments); // set segments     
   
   // initial start up
   count5 = 8;
   count4 = 8;
   count3 = 8;
   count2 = 8;
   count1 = 8;
   Display ();
   delay_ms(1000);

   count5 = 0;
   count4 = 0;
   count3 = 0;
   count2 = 0;
   count1 = 0;
   Display ();

   while (TRUE)   
   {
   
   while (!input (PIN_B0))
      {
         Display ();       
         clear_interrupt(INT_EXT);
         disable_interrupts(GLOBAL);
         enable_interrupts(INT_EXT);
         sleep();
         delay_ms(50);
      }

         
   while (input (PIN_B0))
      {
      Display ();
      count1++;
      if (count1 >=10)
         {
          count1=0;
          }
      delay_ms(1000);
      }

   }
}


Now I got a current of 9.5uA during sleep, since my regulator draw 1uA, that mean the PIC draw 8.5uA during sleep. But the data sheet says it can go below 100nA. I know that LCD will draw some current but isn't around 8.5uA too much for LCD.

I write a test code that turn OFF everything and go to sleep just to see how low can I got. I reached 1.7uA( 0.7uA for the PIC).
Here is this code.
Code:

#include <16F913.h>
#fuses LP, NOWDT, PUT, MCLR, NOBROWNOUT, NOFCMEN, NOIESO
#use delay(clock=32768)

void main()
{
   set_tris_a (0xff);  // avoid floating
   set_tris_b (0xfe);  // avoid floating
   set_tris_c (0xfc);  // avoid floating
   set_tris_e (0xff);  // avoid floating
   
   output_high(pin_A0);
   output_high(pin_A1);
   output_high(pin_A2);
   output_high(pin_A3);
   output_high(pin_A4);
   output_high(pin_A5);
   output_high(pin_A6);
   output_high(pin_A7);
   
   output_high(pin_B0);
   output_high(pin_B1);
   output_high(pin_B2);
   output_high(pin_B3);
   output_high(pin_B4);
   output_high(pin_B5);
   output_high(pin_B6);
   output_high(pin_B7);
   
   output_high(pin_C0);
   output_high(pin_C1);
   output_high(pin_C2);
   output_high(pin_C3);
   output_high(pin_C4);
   output_high(pin_C5);
   output_high(pin_C6);
   output_high(pin_C7);
   
   output_high(pin_E3);

   setup_counters (T0_EXT_L_TO_H, T0_DIV_1); // disable timer 0 ????????
   
   setup_timer_1 (T1_DISABLED);     // disable timer 1

   setup_timer_2 (T2_DISABLED,0,1);     // disable timer 2

   setup_vref (FALSE);              // disable Voltage reference

   setup_adc (ADC_OFF);             // disable ADC

   setup_wdt (WDT_OFF);             // disable Watch Dog Timer

   setup_ccp1 (CCP_OFF);            // disable compare/capture
   
   setup_comparator (NC_NC_NC_NC);  // disable comparators
   
   setup_spi(SPI_DISABLED);
   

   #byte VRCON = 0x009D   // VR control register
         VRCON = 0x00;    // VR is disabled
         
   #byte CMCON0 = 0x009C  // Comparator configuration register
         CMCON0 = 0x0007; // Comparator is disabled
         
   #byte ANSEL = 0x0091   // Analog select register
         ANSEL = 0x00;    // Digital I/O
         
   #byte ADCON0 = 0x001F  // A/D control register
         ADCON0 = 0x00;   // A/D is shut off
         
    ext_int_edge(L_TO_H);      // init interrupt triggering for button press
    enable_interrupts (INT_EXT);      // turn on interrupts
   
   setup_lcd(LCD_DISABLED);
   

   while (TRUE)   
      {

   while (!input (PIN_B0))
      {
      output_low(pin_C1);
      clear_interrupt(INT_EXT);
      disable_interrupts(GLOBAL);
      enable_interrupts(INT_EXT);
      sleep();
      delay_cycles(1);
      }

         
   while (input (PIN_B0))
      {
      output_toggle(pin_C1);   
      delay_ms(1000);
      }
      }
}


I was using:
* PIC16F913
* CCS V 5.071
* 3V coin battery with a 2V regulator (Idle current for the regulator is 1uA).
* Clock is a low power 32.768kHz crystal
* PIN-C1 is connected to LED with 47K Res connected to GND.
* 330K Res pull up at the MCLR pin.
* PIN-B0 was pulled down to GND through a 1M Res, and will be connected
to 2V supply using a push button to wake up from sleep.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Sep 19, 2022 3:03 pm     Reply with quote

I guess you want to know why the first program uses more current than
the 2nd program.

I couldn't find a spec in the 16F913 data sheet for current usage by
the LCD module when it's enabled. I think the excess current might
be used by the LCD module. To test this, turn it on in your 2nd program.
Change this:
Quote:
setup_lcd(LCD_DISABLED);

to this:
Code:
setup_lcd(LCD_MUX14|LCD_INTRC,7, Segments);

How much current does the 2nd program now use ?
samiceng



Joined: 23 Oct 2018
Posts: 5

View user's profile Send private message

PostPosted: Tue Sep 20, 2022 12:50 pm     Reply with quote

PCM programmer, I found something.

I tried what you suggest ( had to add this line too: "#define Segments 0x6f4e"). I got 2.9uA while sleep. But there is no LCD resistors attached to PIN C0 to C2. So to make it fair I add them and test two codes: one with LCD enabled and the other is not.

So using this arrangement:
* PIC16F913
* CCS V 5.071
* 3V coin battery with a 2V regulator (Idle current for the regulator is 1uA).
* Clock is a low power 32.768kHz crystal
* LCD (2V 1/4 duty 1/3 bias) with three 1M res for LCD biasing.
* 330K Res pull up at the MCLR pin.
* PIN-B0 was pulled down to GND through a 1M Res, and will be connected
to 2V supply using a bush button to wake up from sleep.
and code :

Code:

#include <16F913.h>

#fuses LP, NOWDT, PUT, MCLR, NOBROWNOUT, NOFCMEN, NOIESO
#use delay(clock=32768)


int count1 = 8;   // 1st digit
int count2 = 8;   // 2nd digit
int count3 = 8;   // 3rd digit
int count4 = 8;    // 4th digit
int count5 = 8;    // 5th digit

/////////////////////////////////////////////////////////////////////////////////////////
//                                 LCD Configuration                                   //
/////////////////////////////////////////////////////////////////////////////////////////
// Digit segments  A        B         C          D         E         F         G        DP
//                 b7       b6        b5         b4        b3        b2        b1       b0
#define DIGIT1  COM0+13,  COM1+13,  COM2+13,  COM3+13,  COM2+14,  COM0+14,  COM1+14,  COM3+14
#define DIGIT2  COM0+3,   COM1+3,   COM2+3,   COM3+3,   COM2+2,   COM0+2,   COM1+2,   COM3+2
#define DIGIT3  COM0+1,   COM1+1,   COM2+1,   COM3+1,   COM2+8,   COM0+8,   COM1+8,   COM3+8
#define DIGIT4  COM0+9,   COM1+9,   COM2+9,   COM3+9,   COM2+10,  COM0+10,  COM1+10,  COM3+10
#define DIGIT5  COM0+11,  COM1+11,  COM2+11,  COM3+11,  COM2+6,   COM0+6,   COM1+6,   COM3+6
//       ComX+Y is combination of Backplan0-3 and Segment0-SegmentXX
////////////////////////////////////////////////////////////////////////////////////////
//           character         0    1    2    3    4    5    6    7    8    9   Null

byte const Digit_Map_1[11] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6,0x00};

#define blank   10
/////////////////////////////////////////////////////////////////////////////////////////
//                          Segments Initilization
// Seg15 Seg14 Seg13 Seg12 Seg11 Seg10 Seg9 Seg8 Seg7 Seg6 Seg5 Seg4 Seg3 Seg2 Seg1 Seg0
//  0/1   0/1   0/1   0/1   0/1   0/1  0/1  0/1   0/1  0/1 0/1   0/1 0/1  0/1  0/1   0/1
//  if bit_SegX is 1, SegX is set as Segment Output. Otherwise
/////////////////////////////////////////////////////////////////////////////////////////

#define Segments 0x6f4e    // Initialize LCD SegmentX

////////////////////////////////////////////////////////////////////////////////////////


void Display()
{
      lcd_symbol (Digit_Map_1[count1], DIGIT1); // from left to right
      lcd_symbol (Digit_Map_1[count2], DIGIT2); // from left to right
      lcd_symbol (Digit_Map_1[count3], DIGIT3); // from left to right                 
      lcd_symbol (Digit_Map_1[count4], DIGIT4); // from left to right
      lcd_symbol (Digit_Map_1[count5], DIGIT5); // from left to right
}

///////////////////////////////////////////////////////////////////////////////
void main()
{
   set_tris_a (0xff);  // avoid floating
   set_tris_b (0xff);  // avoid floating
   set_tris_c (0xff);  // avoid floating
   set_tris_e (0xff);  // avoid floating
   
   output_high(pin_A0); //////////////////////////////////
   output_high(pin_A1); //
   output_high(pin_A2); //
   output_high(pin_A3); //
   output_high(pin_A4); //
   output_high(pin_A5); //
   output_high(pin_A6); //
   output_high(pin_A7); //
                        //
   output_high(pin_B1); //
   output_high(pin_B2); //
   output_high(pin_B3); //
   output_high(pin_B4); // set all the ports to high state
   output_high(pin_B5); //
   output_high(pin_B6); //
   output_high(pin_B7); //
                        //
   output_high(pin_C0); //     
   output_high(pin_C1); //
   output_high(pin_C2); //
   output_high(pin_C3); //
   output_high(pin_C4); //
   output_high(pin_C5); //
   output_high(pin_C6); //
   output_high(pin_C7); //
                        //
   output_high(pin_E3); //////////////////////////////////
   
   setup_counters (T0_EXT_L_TO_H, T0_DIV_1); // // disable timer 0 ??????
   
   setup_timer_1 (T1_DISABLED);     // disable timer 1

   setup_timer_2 (T2_DISABLED,0,1);     // disable timer 2

   setup_vref (FALSE);              // disable Voltage reference

   setup_adc (ADC_OFF);             // disable ADC

   setup_wdt (WDT_OFF);             // disable Watch Dog Timer

   setup_ccp1 (CCP_OFF);            // disable compare/capture
   
   setup_comparator (NC_NC_NC_NC);  // disable comparators
   
   setup_spi(SPI_DISABLED);         // disable SPI
   
   

   
   #byte VRCON = 0x009D   // VR control register
         VRCON = 0x00;    // VR is disabled
         
   #byte CMCON0 = 0x009C  // Comparator configuration register
         CMCON0 = 0x0007; // Comparator is disabled
         
   #byte ANSEL = 0x0091   // Analog select register
         ANSEL = 0x00;    // Digital I/O
         
   #byte ADCON0 = 0x001F  // A/D control register
         ADCON0 = 0x00;   // A/D is shut off
         
    ext_int_edge(L_TO_H);      // init interrupt triggering for button press
    clear_interrupt(INT_EXT);
    disable_interrupts(GLOBAL);
    enable_interrupts(INT_EXT);
   
//!       setup_lcd(LCD_DISABLED);              // once test with LCD disabled
   setup_lcd(LCD_MUX14|LCD_INTRC,7, Segments);  // once test with LCD enabled     

   while (TRUE)   
   {
   
   while (!input (PIN_B0))
      {     
         set_tris_a (0xff);    // avoid floating
         set_tris_b (0xff);   // avoid floating
         set_tris_c (0xff);   // avoid floating
         set_tris_e (0xff);   // avoid floating
         
         output_high(pin_A0); //////////////////////////////////
         output_high(pin_A1); //
         output_high(pin_A4); //
         output_high(pin_A5); // set all the un used ports to high state
         output_high(pin_A6); //
         output_high(pin_A7); //
         output_high(pin_E3); //////////////////////////////////
         
         clear_interrupt(INT_EXT);
         sleep();
         delay_cycles(1);
      }

         
   while (input (PIN_B0))
      {
      count1++;
      delay_ms(1000);
      }

   }
}


I got : with LCD disabled the current was 6.2uA
with LCD enabled the current was 11.2uA
Also note I just enabled the LCD and did not display anything yet.

Now I had a look at the 16F913.h file and found that I can use "LCD_BIAS_PINS" in set up the LCD. So using it
Code:

setup_lcd(LCD_MUX14|LCD_BIAS_PINS|LCD_INTRC,7, Segments); 

The current dropped to 3.7uA. ( still display nothing)
And when I turn ON all the segments before sleep the current become 4.3uA.

Note: All the current readings above are from the battery.
Ttelmah



Joined: 11 Mar 2010
Posts: 19510

View user's profile Send private message

PostPosted: Fri Sep 23, 2022 7:46 am     Reply with quote

It is one of the old 'adages' that when you want to reduce the power you
have to turn off everything. The LCD falls into this category...
Controlling the bias to reduce the current does seem to be a very good way
to go. At least you now have a good idea as to what is causing the problem.
Classic 'PCM' sensible solution. Smile
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