Problem with static variable holding a value

Discussion in 'Embedded Systems and Microcontrollers' started by hunterage2000, Jun 29, 2015.

  1. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    I am trying to create a program with a pic to:

    output a PWM signal that increments by 25% to 75% if right button is pressed.

    output a PWM signal that decrements by 25% to 0% if left button is pressed.

    I have done the inc/decrement part but a static variable that holds the present value isn't working so after a short delay the PWM% goes back to 0%.

    I don't fully understand the static class specifier and I'm not sure if the flow of the program is correct. Can someone tell me what I'm doing wrong?

    The code is below:

    Code (Text):
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <pic16f1939.h>
    4. #include <xc.h>
    5. #define _XTAL_FREQ 1000000
    6.  
    7. typedef unsigned char uint_8;
    8. typedef unsigned int uint_16;
    9. typedef unsigned short long int uint_24;
    10. typedef unsigned long int uint_32;
    11.  
    12. #define left PORTAbits.RA0
    13. #define right PORTAbits.RA1
    14. #define dl __delay_ms(100)
    15.  
    16. //dcyc_0() to set initial PWM to 0%
    17. void dcyc_0();
    18.  
    19. //dcyc_left() to decrease PWM by 25% if PWM is not 0%
    20. uint_8 dcyc_left(uint_8 dc_rtn_value);
    21.  
    22. //dcyc_right() to increase PWM by 25% if PWM is not 75%
    23. uint_8 dcyc_right(uint_8 dc_rtn_value);
    24.  
    25. //A static value is set to zero
    26.  
    27.  
    28. void main()
    29. {
    30.     //PWM (CPP1) pin is set
    31.     PORTA = 0x00;
    32.     LATA = 0x00;
    33.     ANSELA = 0x00;
    34.     TRISA = 0x03;
    35.  
    36.     while(1)
    37.     {      
    38.         while(left == 0 && right == 0)
    39.         {
    40.         /*static dc_rtn_value is zero
    41.           until right is called and dc_rtn_value
    42.           is incremented by 25 and the PWM value
    43.           for CCPR1L is 25
    44.         */
    45.         static uint_8 dc_rtn_value = 0;
    46.         TRISC = 0xFB;
    47.         CCPTMRS0bits.C1TSEL = 0b00;
    48.         PR2 = 100;
    49.         CCP1CON = 0x3C;
    50.         CCPR1L = dc_rtn_value;
    51.         PIR1bits.TMR2IF = 0;
    52.         T1CONbits.T1CKPS = 0b10;
    53.         T2CONbits.TMR2ON = 1;
    54.         while(PIR1bits.TMR2IF == 0);
    55.        
    56.         /*if left is pressed call dcyc_left()
    57.           send dc_rtn_value to it
    58.           if dc_rtn_value is zero add zero and return zero
    59.           if not decrement dc_rtn_value by 25            
    60.         */
    61.         if(left == 1)
    62.         {
    63.             dc_rtn_value = dcyc_left(dc_rtn_value);
    64.             dl;
    65.         }
    66.        
    67.         /*if right is pressed call dcyc_right()
    68.           send dc_rtn_value to it
    69.           if dc_rtn_value is 75 add zero and return 75
    70.           if not increment dc_rtn_value by 25            
    71.         */
    72.         else if(right == 1)
    73.         {
    74.             dc_rtn_value = dcyc_right(dc_rtn_value);
    75.             dl;
    76.         }
    77.         }
    78.     }
    79.  
    80. }
    81.  
    82. uint_8 dcyc_left(uint_8 dc_rtn_value)
    83. {
    84.     if(dc_rtn_value == 0)
    85.     {
    86.         dc_rtn_value = dc_rtn_value + 0;
    87.     }
    88.     else
    89.     {
    90.         dc_rtn_value = dc_rtn_value - 25;
    91.     }
    92.    
    93.     return dc_rtn_value;
    94. }
    95.  
    96. uint_8 dcyc_right(uint_8 dc_rtn_value)
    97. {
    98.     if(dc_rtn_value == 75)
    99.     {
    100.         dc_rtn_value = dc_rtn_value + 0;
    101.     }
    102.     else
    103.     {
    104.         dc_rtn_value = dc_rtn_value + 25;
    105.     }
    106.    
    107.     return dc_rtn_value;
    108. }
     
  2. RJohnson

    New Member

    May 29, 2011
    21
    3
    You need to go back and study a bit more on the C programming language. Look for global / local memory use.
     
  3. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    I've looked at some examples using static and can't figure it out. I tried something simple like:



    Code (Text):
    1.  
    2.  
    3. static int counter = 1;
    4.  
    5. void main()
    6. {
    7.  
    8. while(1)
    9.     {
    10.        
    11.         PORTD = counter;
    12.         if(button == 1)
    13.         {
    14.             ++counter;
    15.             if(counter==4)
    16.             {
    17.                 counter = 1;
    18.             }
    19.            
    20.         }
    21.     }
    22. }
    but it still hasn't worked.
     
  4. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,388
    1,605
    When you define a variable as static you are telling the compiler you want it to maintain the value between times you run some routine, so the variable is stored in some permanent place.

    Since you never leave the main() function defining a main() variable as static has no effect.
     
  5. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    A static variable defined outside of any function has it's scope limited to the file in which it is defined. It is completely unknown to any functions defined in other files or in libraries.
    A static variable defined inside a function keeps it's value between invocations of the function, and is local to that function.

    https://en.wikipedia.org/wiki/Static_variable
     
  6. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    I did try and put it just before PORTD = counter; but it didn't work.
     
  7. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
    In your simple example, it is not clear to me what doesn't work. Could you elaborate?
     
  8. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    I thought the program would:

    set a static variable initially to 1
    set PORTD = counter as 1 (binary 00000001) so an led on PORTD bit 0 is on
    if button is pressed counter is incremented to 2 (binary 00000010)
    when button is released PORTD = counter is 2 so an led on PORTD bit 1 is on
    if button is pressed again counter is incremented to 3 (binary 00000011)
    when button is released PORTD = counter is 3 so an led on PORTD bit 0 and bit 1 is on

    but once button is released counter goes back to 1.
     
  9. Papabravo

    Expert

    Feb 24, 2006
    10,144
    1,791
  10. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,388
    1,605
    Even if debounced you wrote code to continuously increment the variable as long as the button was pressed.

    You might want to think of alternatives such as "stop here and wait until the button is released."
     
  11. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    I have debounce code in now but the counter returns to 1.

    Code (Text):
    1.  while(1)
    2.     {
    3.        
    4.         PORTD = counter;
    5.         if(button == 1)
    6.         {
    7.          
    8.             ++counter;
    9.             if(counter==4)
    10.             {
    11.                 counter = 1;
    12.             }
    13.             for(int i=0; i<=10; i++)
    14.             {
    15.                 dl_1; //delay is 100ms
    16.                 if(button==0)
    17.                 {
    18.                     int i = 0;
    19.                 }
    20.             }
    21.         }
    22.     }
    23. }
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,388
    1,605
    I do not see anything in that code that will debounce either the button press or the button release, and you need both.

    I also do not see anything to stop counting over and over for a single press.

    Why do you define a variable "i" twice? Does this code actually compile?

    I strongly suggest you stop writing C and write the steps in words, in detail, then translate the words into C.
     
  13. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,809
    834
    I don't see anything in the simple code that defines what button is or that it is even testing for a button press anywhere? There must be additional code missing... Same for the debounce which you claim you are doing. Without something changing "button", your "if" statement will not get executed and counter will not get changed.

    As far as the dual definition of "i" is concerned, IMHO each declaration refers to a different object.
    "Each declaration of an identifier with no linkage denotes a unique entity."
    ...and hence changing "i" in the "if" block, does not affect the loop index. The following sample (Arduino) code illustrates this.
    Code (Text):
    1.  
    2. void setup() {
    3.   // put your setup code here, to run once:
    4.   Serial.begin(9600);
    5.   int button =0;
    6.   int j =-1;
    7.               for(int i=0; i<=10; i++)
    8.             {
    9.                  j++;
    10.                 button=1-int(i/4);
    11.  
    12.                 if(button==0)
    13.                 {
    14.                     int i = 0;
    15.                     Serial.print("i changed to ");
    16.                     Serial.println(i);
    17.                 }
    18.                 Serial.print("i,j ");
    19.                 Serial.print(i);
    20.                 Serial.print(",");
    21.                 Serial.println(j);
    22.             }
    23. }
    24.  
    25. void loop() {
    26. }
    27.  
    This program produces the following output:
    Code (Text):
    1. i,j 0,0
    2. i,j 1,1
    3. i,j 2,2
    4. i,j 3,3
    5. i changed to 0
    6. i,j 4,4
    7. i changed to 0
    8. i,j 5,5
    9. i changed to 0
    10. i,j 6,6
    11. i changed to 0
    12. i,j 7,7
    13. i,j 8,8
    14. i,j 9,9
    15. i,j 10,10
    16.  
     
  14. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    There is code missing to make the counter hold after each press but I'm not sure what.

    button is a pull down tactile switch on PORTA0 set as a digital input so when pressed button == 1.

    My thinking was:

    after static int counter was set to 1
    enter the while(1) loop
    as counter was set to 1, PORTD = counter = 1(00000001) so PORTD0 = 1 and remain at 1 until button is 1
    when button is pressed counter is incremented so now 2(00000010) so PORTD1 = 1
    a small delay occurs and button = 0 then leaves the if block so PORTD = counter = 2(00000010) so PORTD1 = 1 and remain at 1 until button is 1 again.

    In my mind I know what I want to do and think the steps are right but obviously not. I need help with thinking in steps in C and then actually programming in C.
     
  15. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,388
    1,605
    Your thinking is a curious mix of English and C. Do try to think in one or the other. Also don't mix "button pressed" with "button is one." Just use"pressed" and "unpressed" so you can use equate statements to make the thinking and logic clear and bullet proof.

    While I prefer to read and debounce my buttons in a background interrupt routine it is simpler to do it inline with direct code(or function), say something like this:
    Code (Text):
    1. unsigned char GetButton(void)
    2. {
    3.   unsigned char last = ! button;
    4.    while ( last != button)
    5.   {
    6.     last = button;
    7.     // delay here for about 25 to 50 mS
    8.   }
    9.   return last;
    10. }
    11.  
    This keeps you stuck in this loop until the button is stable.
     
  16. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    The code I've used is doing what thought it would do without holding the incremented value. So I can keep pressing it and it will continuously change and light up led1(PORTD1) then both(PORTD0,D1) then back to led2(PORTD0). But when both are turned on, after the delay the counter goes back to 1 and led2(PORTD0) is on.

    I was thinking that if the static value has been incremented from 1 to 2 in the if block statement then it is exited when button == 0 then PORTD = counter would be PORTD = 2 and remain as 2 until button == 1.
     
  17. RJohnson

    New Member

    May 29, 2011
    21
    3
    Your code is pretty confusing.
    Looks like you don't understand how and when to declare variables.
    You don't need a static variable to use.
    I have made my text a different font.

    while(1)
    {
    PORTD = counter;
    if(button == 1) // will only go inside when 1​
    {
    ++counter;
    if(counter==4)
    {
    counter = 1;​
    }
    for(int i=0; i<=10; i++) // delay 1 second
    {
    dl_1; //delay is 100ms​
    if(button==0) // button released during this second
    {
    int i = 0; // Huh?, whats this do again? Since you have a new i I think nothing.​
    }​
    }​
    }
    } // end of while(1)
     
  18. RJohnson

    New Member

    May 29, 2011
    21
    3
    OK, the system here changed the font so my comments are after the //.
     
  19. RJohnson

    New Member

    May 29, 2011
    21
    3
    Here is how I do button logic. Probably many other ways.

    In the Header file I define the bit positions for buttons:
    // MCP23S08 bits---------------------------
    // Inputs
    typedef union
    {
    UINT16 summary;
    struct __PACKED
    {
    UINT8 LB; // Addr 00
    UINT8 HB; // Addr 01
    } byte;

    struct __PACKED
    {
    unsigned :2; // b0,1
    unsigned Time :1; // b2 S5
    unsigned Set :1; // b3 S2
    unsigned Pgm :1; // b4 S13
    unsigned Fan :1; // b5 S9
    unsigned Cool :1; // b6 S6
    unsigned Heat :1; // b7 S3

    unsigned Up :1; // b8 S8
    unsigned Escape :1; // b9 S12
    unsigned Left :1; // b10 S1
    unsigned Right :1; // b11 S4
    unsigned Down :1; // b12 S7
    unsigned Enter :1; // b13 S11
    unsigned :2; // b14,15
    } bits;
    } unionDigIn;
    extern unionDigIn Button, ButtonDown;

    Back to my comments:
    Inside a function which gets called from my main loop
    I use this code to detect a button press. The actual read of the button
    bit is done in another function which reads the MCP23S08 device on SPI bus &
    this can happen fairly often.
    The buttons are de-bounced in hardware.
    This is only one button
    if( Button.bits.Fan ) // Fan button pressed - can come here lots while looping
    {
    if( ButtonDown.bits.Fan == 0 ) // This flag will prevent multiple access during one key press.
    {
    ButtonDown.bits.Fan = 1; // Set the flag preventing a second access.
    return FanKey; // FanKey will only get returned once during a single key press.
    }
    } else { ButtonDown.bits.Fan = 0; } // Now clear the flag as user
    // has released the button.
     
  20. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    so what is FanKey that is returned and where would counter be incremented?
     
Loading...