1
\$\begingroup\$

I'm currently working on a homework that does: the first press to the button at P1.1 opens the LED at P1.0, the second press to the same button blinks the LED and the third press closes the LED.

I wrote a code for that in Code Composer Studio but the microcontroller does not work properly. It does the opening, blinking, and closing operations but when the LED starts to blink, I have to press the button a few times to close the LED. I think that causes from bouncing (What I mean by bouncing is in the picture below) or the for loop that I wrote for blink operation. 1

I added a for loop (for (i=10000; i>0; i--)) to prevent that but that didn't work.

Here is my code:


int main(void) {
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    P1DIR |= 0x01;              // Configuring P1.0 as output
    P1DIR &= 0xFD;              // Configuring P1.1 as input

    P1REN |= 0x02;              // Enable resistor for P1.1
    P1OUT |= 0x02;              // Setting the resistor as Pull-Up and P1.0 as low
    P1OUT &= 0xFE;
    
    volatile unsigned int i;
    int j = 0;

    while(1) {

        for (i=10000; i>0; i--);                // Delay loop to avoid bouncing
        if ( (~P1IN & 0x02) && j==0 ) {         // Check if the button is pressed and j is 0 for validating it's the 1st press
            P1OUT ^= 0x01;                      // If the button is pressed, then toggle P1.0 (LED is ON)
            j = 1;                              // Change the value of "j" to "1"
        }

        for (i=10000; i>0; i--);                // Delay loop to avoid bouncing
        if ( (~P1IN & 0x02) && j==1) {          // Check if the button is pressed and j is 1 for validating it's the 2nd press
            while(1) {                          // Infinite loop to run the code below until break (3rd press)
                P1OUT ^= 0x01;                  // Toggle P1.0 (LED is blinking)
                for (i=45000; i>0; i--);        // Wait before closing or opening the LED
                if (~P1IN & 0x02) {             // If the button is pressed for the 3rd time, then break the loop
                    break;
                }
            }
            j = 2;                              // If the loop is broken, then change the value of "j" to "2"
        }

        for (i=10000; i>0; i--);                // Delay loop to avoid bouncing
        if ( (~P1IN & 0x02) && j==2) {          // Checking if the button is pressed and j is 2 for validating it's the 3rd press
            P1OUT ^= 0x01;                      // If the button is pressed, then toggle P1.0 (LED is OFF)
            j = 0;                              // Change the value of "j" to "0" for returning to the beginng of the main loop (1st press)
        }
    }
}

How can I fix this issue? My code covers all the thing that we learn until now. So I shouldn't use any codes, variables etc. apart from my code. Thanks in advance!

\$\endgroup\$
8
  • \$\begingroup\$ These busy-delay loops are always brittle - how long a delay is that for loop supposed to give? \$\endgroup\$
    – Lundin
    Apr 8, 2021 at 11:16
  • \$\begingroup\$ Rather tan thinking in terms of delays, think of ‘ticks’. Say each tick is 10ms, count ticks in order to get the time interval you require. Each tick if the button is pressed, increment a count, if not decrement it. Bound the range to 0 and 10. If the count is 0, the switch was not pressed. If the count is 10, the switch was pressed for the last 10 ticks. If it is bouncing, the count will go up/down. Toflash your led, count the required number of ticks the turn the led on. Count the required number of ticks, turn the led off. No need to sit in a delay waiting for things to happen \$\endgroup\$
    – Kartman
    Apr 8, 2021 at 12:09
  • \$\begingroup\$ Your instructor may not allow you to use it yet, but there is a Macro for loop delays, it will create loops to get the requested delay. __delay_cycles( DELAY_MCU_CLOCK_CYCLES ); \$\endgroup\$
    – Mattman944
    Apr 8, 2021 at 12:50
  • \$\begingroup\$ MSP430-specific suggestion: if you look in the MSPware examples you can use the WDT (which you are not using anyway) to poll properly the switches. It's actually somewhat designed for that \$\endgroup\$ Apr 8, 2021 at 12:51
  • \$\begingroup\$ Is it being optimized out? \$\endgroup\$
    – Passerby
    Apr 8, 2021 at 15:14

1 Answer 1

1
\$\begingroup\$

You have to use the delay after spotting the first flank, not at some random location in the code. The most crude version would be this (pseudo code):

uint8_t pin=0;
uint8_t prev=0;

while(1)
{
  pin = PORTX;
  if(pin != prev) // edge detected
    break;
  prev = pin;
}

busy_delay();  // some 5 to 20 ms usually
pin = PORTX;  // read when the switch is done bouncing
// now you can use the value of pin

The more professional version involves a circular interrupt which reads the port at even time intervals and compares with previous read and stores the result if it's the same.

\$\endgroup\$
7
  • \$\begingroup\$ In fact there is a standard procedure for the MSP430 using the WDT to do input debouncing (if you are not using it as a watchdog). It's in the TI supplied examples (and most of the evaluation board software too) \$\endgroup\$ Apr 8, 2021 at 12:53
  • \$\begingroup\$ @LorenzoMarcantonio Not using the watchdog is a very bad idea... \$\endgroup\$
    – Lundin
    Apr 8, 2021 at 12:56
  • \$\begingroup\$ Thanks for the answer but we didn't learn such things like "uint8_t" or something. So I don't know what exactly they are, and I suppose that I am not allowed to use them. And so sorry but I couldn't understand the logic behind this code. Could you explain it more clearly? \$\endgroup\$
    – Efe
    Apr 8, 2021 at 22:25
  • \$\begingroup\$ @Efe They are just 8 bit integers since I'm assuming you have 8 bit registers on this part. As for the logic there's not much else to understand that it compares one port register read with the previous, and if the value has changed, then likely someone pressed or released the button. It's a crude way to detect either raising or falling edge. When that happens is when you should start debouncing. \$\endgroup\$
    – Lundin
    Apr 9, 2021 at 6:32
  • \$\begingroup\$ Also notably in a real-world application you would have to assume that the edge could be caused by EMI. So then you'd once again read the port and compare it with the initial read. If the initial one was 1 but you get 0 after debounce, it was just an EMI spike and should be ignored. \$\endgroup\$
    – Lundin
    Apr 9, 2021 at 6:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.