Author Topic: Davies MSP430 Software Debounce  (Read 1697 times)

0 Members and 1 Guest are viewing this topic.

Offline MattjdTopic starter

  • Regular Contributor
  • *
  • Posts: 230
  • Country: us
Davies MSP430 Software Debounce
« on: October 13, 2017, 06:24:14 am »
Hello All,

I've been looking at Davies MSP430 Ebook, specifically the software debounce section.

The code is
Code: [Select]
// debtim1.c - press button B1 to light LED1 with debounce
// Samples input at 5 ms intervals set by Timer_A, 32KHz ACLK
// Shift reg for debounce, different thresholds for press and release
// Olimex 1121STK board, LED1 active low on P2.3,
//   button B1 active low on P2.1
// J H Davies, 2007-04-10; IAR Kickstart version 3.42A
//----------------------------------------------------------------------
#include <io430x11x1.h> // Specific device
#include <intrinsics.h> // Intrinsic functions
#include <stdint.h> // Standard integer types

union { // Debounced state of P2IN
unsigned char DebP2IN; // Complete byte
struct {
unsigned char DebP2IN_0 : 1;
unsigned char DebP2IN_1 : 1;
unsigned char DebP2IN_2 : 1;
unsigned char DebP2IN_3 : 1;
unsigned char DebP2IN_4 : 1;
unsigned char DebP2IN_5 : 1;
unsigned char DebP2IN_6 : 1;
unsigned char DebP2IN_7 : 1;
} DebP2IN_bit; // Individual bits
};
#define RAWB1 P2IN_bit.P2IN_1
#define DEBB1 DebP2IN_bit.DebP2IN_1
#define LED1 P2OUT_bit.P2OUT_3

void main (void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
P2OUT_bit.P2OUT_3 = 1; // Preload LED1 off (active low!)
P2DIR_bit.P2DIR_3 = 1; // Set pin with LED1 to output
DebP2IN = 0xFF; // Initial debounced state of port
TACCR0 = 160; // 160 counts at 32KHz = 5ms
TACCTL0 = CCIE; // Enable interrupts on Compare 0
TACTL = MC_1|TASSEL_1|TACLR; // Set up and start Timer A
// "Up to CCR0" mode, no clock division, clock from ACLK, clear timer
for (;;) { // Loop forever
__low_power_mode_3(); // Enter LPM3, only ACLK active
// Return to main function when a debounced transition has occurred
LED1 = DEBB1; // Update LED1 from debounced button
}
}
//----------------------------------------------------------------------
// Interrupt service routine for Timer A chan 0; no need to acknowledge
// Device returns to LPM3 automatically after ISR unless input changes
// PRESS_THRESHOLD = 0x3F = 0b00111111, needs 2 successive 0s (enough?)
// RELEASE_THRESHOLD = 0xFC = 0b11111100, 6 successive 1s (too many?)
//----------------------------------------------------------------------
#define PRESS_THRESHOLD 0x3F
#define RELEASE_THRESHOLD 0xFC

#pragma vector = TIMERA0_VECTOR
__interrupt void TA0_ISR (void)
{
static uint8_t P21ShiftReg = 0xFF; // Shift reg for history of P2.1

P21ShiftReg >>= 1; // Update history in shift register
if (RAWB1 == 1) { // Insert latest input from B1
P21ShiftReg |= BIT7; // Set msb if input high
}
if (DEBB1 == 0) {
// Current debounced value low, looking for input to go high (release)
if (P21ShiftReg >= RELEASE_THRESHOLD) { // button released
DEBB1 = 1; // New debounced state high
__low_power_mode_off_on_exit(); // Wake main routine
}
} else {
// Current debounced value high, looking for input to go low (press)
if (P21ShiftReg <= PRESS_THRESHOLD) { // button pressed
DEBB1 = 0; // New debounced state low
__low_power_mode_off_on_exit(); // Wake main routine
}
}
}


my code on msp430fr6989

Code: [Select]
#include <msp430.h>
#include <intrinsics.h>             // Intrinsic functions
#include <stdint.h>                 // Standard integer types

union DebP2IN{                             // Debounced state of P2IN
    unsigned char byte;         // Complete byte
    struct bit {
        unsigned char DebP2IN_0 : 1;
        unsigned char DebP2IN_1 : 1;
        unsigned char DebP2IN_2 : 1;
        unsigned char DebP2IN_3 : 1;
        unsigned char DebP2IN_4 : 1;
        unsigned char DebP2IN_5 : 1;
        unsigned char DebP2IN_6 : 1;
        unsigned char DebP2IN_7 : 1;
    } bit1;                  // Individual bits
} DebP2IN1;                 //both DebP2INx, bitx, refer to buttons.

#define BUTTON1_PRESSED() !(P1IN & BIT1)
#define DEBB1()   DebP2IN1.bit1.DebP2IN_1
#define LED1_ON()  P1OUT |= BIT0;  //P1.0 LED ON
#define LED1_OFF() P1OUT &= ~BIT0; //P1.0 LED OFF

void main (void)
{
    WDTCTL = WDTPW | WDTHOLD;               // stop watchdog timer
    PM5CTL0 &= ~LOCKLPM5;                   // Disable the GPIO power-on default high-impedance mode

    P1OUT &= ~BIT0;                     //Pre-load LED P1.0 Off
    P1DIR |= BIT0;                      //Set P1.0 LED to output

    P1DIR &= ~BIT1;                    //set P1.1 button to input
    P1REN |= BIT1;                     //Enable Resistor Button P1.1
    P1OUT |= BIT1;                     //Set as Pullup resistor Button P1.1

    DebP2IN1.byte = 0xFF;                //initialize debounce state of P1.1
    TA0CCR0 = 5000;                     // TA0 interrupt triggers every 5 ms
    TA0CCTL0 |= CCIE;                   //Enable TA0 interrupt
    TA0CTL |= (TASSEL_2 + MC_1 + TACLR);    //SMCLK (1mhz) count to CCR0, clear timer

    __enable_interrupt();

    for(;;)
    {
        if(DEBB1() == 1) //Update LED1 from debounced button
        {
            LED1_ON();
        }
        else if (DEBB1() == 0)
        {
            LED1_OFF();
        }

    }
}

#define PRESS_THRESHOLD     0x3F
#define RELEASE_THRESHOLD   0xFC

#pragma vector = TIMER0_A0_VECTOR
__interrupt void TA0_ISR (void)
{
   static uint8_t P11ShiftReg = 0xFF; // Shift Reg for history of P1.1

P11ShiftReg >>= 1;                      // Update history in shift register
if (BUTTON1_PRESSED())                         //Insert latest input from P1.1
{
    P11ShiftReg |= BIT7;                //Set MSB of Shiftreg P1.1 to 1
}

if (DEBB1() == 0)                         //when debounce value is low
{
    if(P11ShiftReg >= RELEASE_THRESHOLD)    //when button is released
    {
        DEBB1() = 1;                          //set new debounce state high
    }
}
else if(P11ShiftReg <= PRESS_THRESHOLD)     //when debounce value is high and button is pressed
    {
        DEBB1() = 0;                          //set new debounce state low
    }
}

I'm understanding it, I think. When the button is pressed, the shift register in the ISR gets filled with ones. This causes DEBB1 to go high and due to the polling in main.c it turns on the LED. Once the button is released, shiftreg will eventually shift below Press_threshold and DEBB1 goes to zero, causing the LED to turn back off.

What I am really confused about, is that if (in my code)

DEBB1 = DebP2IN1.bit1.DebP2IN_1

and

DebP2IN1.bit1.DebP2IN_1 = 1

as declared in the structure

then how does it ever get to zero for the conditional

if (DEBB1() == 0) to be true? 

Also, What is the significance of this line

Code: [Select]
    DebP2IN1.byte = 0xFF;                //initialize debounce state of P1.1
In my code, because DebP2IN1.byte gets used no where. At all.
 

Offline ez24

  • Super Contributor
  • ***
  • Posts: 3082
  • Country: us
  • L.D.A.
Re: Davies MSP430 Software Debounce
« Reply #1 on: October 14, 2017, 05:50:27 am »
watching
YouTube and Website Electronic Resources ------>  https://www.eevblog.com/forum/other-blog-specific/a/msg1341166/#msg1341166
 

Offline Fiki

  • Newbie
  • Posts: 1
  • Country: cz
Re: Davies MSP430 Software Debounce
« Reply #2 on: October 16, 2017, 08:03:17 am »
Hi,
I believe it's actually the other way around.

Initially, the shift register is filled with ones and when the button is pressed, it gets filled with zeros. The button is active at low state.

I would try to change the condition in ISR to:

Code: [Select]
if (P1IN & BIT1)                         // Button released, P1.1 at high state
{
    P11ShiftReg |= BIT7;                //Set MSB of Shiftreg P1.1 to 1
}

BIT7 of P11ShiftReg should be set if button is released.


Fiki
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf