This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Toggle LED1 to LED2 by using Swicth2 - MSP430 Launchpad

Hi,

I'd like to write a code that does toggling on the LED1 (P1.0) to LED2 (P1.6) when the S2 (P1.3) is pressed.

My code is the following;

----------

WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

P1DIR |= 0x41; // LED1 and LED2 are output

P1OUT |= BIT0; // LED1 is on - initial

P1OUT |= BIT3; // Code for switch (S2)to be used
P1REN |= BIT3; // Code for switch (S2) to be used

P1OUT &= ~BIT6; // LED2 is off - initial

while(1)
{

if (!(BIT3 & P1IN)) //when S2 is pressed
{
P1OUT ^= 0x41; //do xor to LED1 and LED2
}
}

--------------

When I use this, MSP40 does sometimes turns on LED1 and turns off LED2, but sometimes LED2 stays stills and LED1 toggles.

What am I doing wrong?

I have checked a lot about this in forums and web but couldn't find a solution.

Thanks.

Basar

  • Hi Basar,

    Your code works as you've described, it's just hard to tell because of the rate of toggling.  Add

    __delay_cycles(50000);

    immediately after the port toggle instruction and it will make the toggle much easier to see.

  • Michael is right. Your code doesn’t toggle the LED when the button is pressed, but as long as the button is pressed. And it does so about 80.000 times per second then.
    After all, it gives you a random generator, as you press the button and when you release it, one of the two LEDs will light, depending on how many microseconds you pressed the button.

  • Hi Basar,

    Michael and JMG have bried you about the senario and they were right.  Usually programmers use interrupts to word arouch such examles , any way if I were u, I would do some thing like this.

    uint8_t button_pressed_flag = 0;
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    
    P1DIR |= 0x41; // LED1 and LED2 are output
    
    P1OUT |= BIT0; // LED1 is on - initial
    
    P1OUT |= BIT3; // Code for switch (S2)to be used
    P1REN |= BIT3; // Code for switch (S2) to be used
    
    P1OUT &= ~BIT6; // LED2 is off - initial
    
    while(1)
    {
         if (!(BIT3 & P1IN)) //when S2 is pressed
          {
             button_pressed_flag = 1;          
          }//close if
         if(button_pressed_flag)
          {
             button_pressed_flag = 0// clear flag 
             P1OUT ^= 0x41; //xor to LED1 and LED2                       
          }//if
    }//while()

  • I forgot to add a note about button bouncing. If one presses a mechanical button (except for special bounce-free buttons), then the contact bounces several times. For up to several milliseconds, the button appears to be pressed, released, pressed, released… When releasing the button, situation is similar (but usually shorter)

    To avoid this, one the first state change, an delay should be added to wait until a typical bounce time is over. Then the state of the button is checked again. When working with interrupts, a timer delay can be used. Else a __delay_cycles(x) in the code flow does the trick.

  • Hi, 

    First of all, I'd like to thank you all for your replies. Now I understand one should always give a delay after a bounced button since it's giving to many singnals in a one press. 

    By the way, it should be like __delay_cycles(200000);

    Yet still, is there a way to use a bounced button to give only one shot? I believe it's the subject of interrupt.

    Thank you very much again!

    Basar

  • As you are using the Launchpad, you can not make to many changes of the circuit,
    if you did your own pcb, you could add hardware debounce

    http://www.ganssle.com/images/debouncerrc.jpg
    Problems is that you may make the slopes to long and mcu don't like that, that is why they are using a 
    schmitt trigger inverter in the pic, but as long you keep the Resistors at 10k and Cap at 0.1uf it should be OK without it.

    Software debounce:
    set up port IRQ as normal, in the IRQ you turn off its own IRQ for ever happening again,
    but you restart the watchdog timer with: WDT_MDLY_8     /* 8ms     " */
    and the watchdogs IRQ only job is to always resetting the-allowing-of-PortPin-IRQ.
    clear the port irq flag too before exiting if it notice port IRQ was turned off,
    and you could tell itself to turn off as you really only needed a one-shoot-timer.

    Problem solved.

  • To add to Tony's post;

    MSP430 inputs are schmitt trigger inputs, and so the external schmitt trigger would not be necessary.  Need for R2 is questionable since it's primary contribution is to limit the discharge rate (it does affect charge rate but that can be handled by R1 alone).  R1 could also, technically, be omitted and the internal active pullups could be used but these are a bit weak so the choice is up to the designer.

  • In addition to Tony’s suggestion of using the WDT for debouncing, I want to suggest making the ‘press detected’ decision not immediately in the port ISR but later in the WTD ISR, after the delay. This way, spikes are ignored. Only if the button is still pressed after 8ms (check the pin manually there), it is counted. And the delay is negligible.
    It is also possible, to ‘arm’ the port pin interrupt for the opposite edge in the WDT ISR. This allows detecting the release too.

**Attention** This is a public forum