Hello All,
I've been looking at Davies MSP430 Ebook, specifically the software debounce section.
The code is
// 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
#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
DebP2IN1.byte = 0xFF; //initialize debounce state of P1.1
In my code, because DebP2IN1.byte gets used no where. At all.