Button Interface

Button interface [VIDEO]

Platform Test Tools SAM3U2 Firmware nRF51422 Firmware Software
MPG1
MPG2
USB RS-232 Converter Master Branch
Button Basic
AP2 Emulator TeraTerm

Prerequisite Modules

API Description

While a button is simple mechanically, there are many considerations to use them in an embedded system. This API completely abstracts the hardware so the polarity, port and pin of the buttons does not have to be known. The driver also provides debouncing and simple functions to provide typical button operations. Signal bouncing is the multiple make-and-break connections that occur in a mechanical switch before the signal is stable, as shown in the oscilloscope capture below of one of the development board buttons being released.

BouncingScopeShot

The processor would see four rising edge inputs as this button changed states even though they occur in just 300us. A debouncing algorithm starts when the processor sees the first signal edge then simply waits a period of time to look at the signal state again when it should be stable to decide if there was a legitimate state change. Note that the reset button on the development boards is not included in this driver as it is purely a hardware function on the processor’s reset line.

Type Definitions
There are no public button-specific types. However, the button names applicable to the target development board are required wherever a u32Button_ parameter is requested and are predefined below. BUTTON0 is on the left side of the PCBs.

ASCII development board: BUTTON0, BUTTON1, BUTTON2, BUTTON3
Dot matrix development board: BUTTON0, BUTTON1


Public Functions
The following functions may be used by any application in the system at any time.

  • bool IsButtonPressed(u32 u32Button_) – Returns TRUE if a particular button is currently pressed (and debounced).
  • bool WasButtonPressed(u32 u32Button_) – Returns TRUE if a particular button was pressed since last time it was checked even if it is no longer pressed. ButtonAcknowledge() is typically called immediately after WasButtonPressed() returns TRUE to clear the button pressed state.
  • void ButtonAcknowledge(u32 u32Button_) – Clears the New Press state of a button — generally always called after WasButtonPressed() returns TRUE.
  • bool IsButtonHeld(u32 u32Button_, u32 u32ButtonHeldTime_) – Returns TRUE if a button has been held for u32ButtonHeldTime_ time in milliseconds.

Only WasButtonPressed() needs to be used carefully. When a button is pressed, the driver sets a flag. Even if the button is released, the flag will remain set until it is cleared in firmware. This is called “latching” the signal. Latching ensures the signal is not missed. WasButtonPressed() checks this flag and ButtonAcknowledge() clears the flag. If it is not cleared, then the flag is still available for other tasks. This is very different than simply checking if a button is pressed or held as it ensures that a single button press can result in a single event – a very important capability that requires quite a few lines of code to implement manually, so it was included in the API.


Examples

Start with a clean version of the Master firmware from the link above. Add the following examples in user_app.c:

ASCII development board:
First, make sure all LEDs are properly initialized in UserAppInitialize():

  LedOff(WHITE);
  LedOff(PURPLE);
  LedOff(BLUE);
  LedOff(CYAN);
  LedOff(GREEN);
  LedOff(YELLOW);
  LedOff(ORANGE);
  LedOff(RED);

Turn on the WHITE LED if BUTTON0 is currently pressed:

if( IsButtonPressed(BUTTON0) )
{
  /* The button is currently pressed, so make sure the LED is on */
  LedOn(WHITE);
}
else
{
  /* The button is not pressed, so make sure the LED is off */
  LedOff(WHITE);
}

Toggle blinking on/off of the YELLOW LED when BUTTON1 has been pressed. ButtonAcknowledge() must be called after WasButtonPressed():

  if( WasButtonPressed(BUTTON1) )
  {
    /* Be sure to acknowledge the button press */
    ButtonAcknowledge(BUTTON1);

    /* If the LED is already blinking, toggle it off */
    if(bYellowBlink)
    {
      bYellowBlink = FALSE;
      LedOff(YELLOW);
    }
    else
    {
     /* start blinking the LED at the current rate */
      bYellowBlink = TRUE;
      LedBlink(YELLOW, LED_1HZ);
    }
  }

Turn on the CYAN LED after BUTTON3 has been held for 2 seconds:

  if( IsButtonHeld(BUTTON3, 2000) )
  {
    LedOn(CYAN);
  }
  else
  {
    LedOff(CYAN);
  }

Dot matrix development board:
First, make sure all LEDs are properly initialized in UserAppInitialize():

  LedOff(RED0);
  LedOff(BLUE0);
  LedOff(GREEN0);

  LedOff(RED1);
  LedOff(BLUE1);
  LedOff(GREEN1);

  LedOff(RED2);
  LedOff(BLUE2);
  LedOff(GREEN2);

  LedOff(RED3);
  LedOff(BLUE3);
  LedOff(GREEN3);

Turn on the BLUE0 LED if BUTTON0 is currently pressed:

if( IsButtonPressed(BUTTON0) )
{
  /* The button is currently pressed, so make sure the LED is on */
  LedOn(BLUE0);
}
else
{
  /* The button is not pressed, so make sure the LED is off */
  LedOff(BLUE0);
}

Toggle blinking on/off of the GREEN3 LED when BUTTON1 has been pressed. ButtonAcknowledge() must be called after WasButtonPressed():

  if( WasButtonPressed(BUTTON1) )
  {
    /* Be sure to acknowledge the button press */
    ButtonAcknowledge(BUTTON1);

    /* If the LED is already blinking, toggle it off */
    if(bYellowBlink)
    {
      bYellowBlink = FALSE;
      LedOff(GREEN3);
    }
    else
    {
     /* start blinking the LED at the current rate */
      bYellowBlink = TRUE;
      LedBlink(GREEN3, LED_1HZ);
    }
  }

Turn on the RED2 and GREEN2 LEDs after BUTTON1 has been held for 2 seconds:

  if( IsButtonHeld(BUTTON1, 2000) )
  {
    LedOn(RED2);
    LedOn(GREEN2);
  }
  else
  {
    LedOff(RED2);
    LedOff(GREEN2);
  }

Build the code and test out the functionality.

Exercise

Now add code to do the following on the ASCII board:

  • Instantly turn on/off the PURPLE and BLUE LEDs corresponding to BUTTON1 and BUTTON2.
  • Change the YELLOW blink rate to a variable value
  • If the YELLOW LED is currently on, then BUTTON2 will select the next fastest blink rate for the YELLOW LED. Use LED_1HZ, LED_2HZ, LED_4HZ, and LED_8HZ and notice that you can NOT increment these ENUM values.

For the dot matrix board:

  • Instantly turn on/off the RED1 LED corresponding to BUTTON1.
  • Change the GREEN3 blink rate to a variable value
  • If the GREEN3 LED is currently on, then BUTTON0 will select the next fastest blink rate for the GREEN3 LED. Use LED_1HZ, LED_2HZ, LED_4HZ, and LED_8HZ and notice that you can NOT increment these ENUM values.

For the variable speed blinking we will use an array to hold the blink rates and then a variable index value that will be adjusted to select different rates. A boolean variable bLedBlink will track if the LED is currently blinking and therefore if the rate can change. The solution presented is only for the ASCII board, but the solution on GitHub is complete for both boards.

  static LedRateType aeBlinkRate[] = {LED_1HZ, LED_2HZ, LED_4HZ, LED_8HZ};
  static u8 u8BlinkRateIndex = 0;
  static bool bLedBlink = FALSE;

Adjust the code to access aeBlinkRate[] for the blinking rate:

  if( WasButtonPressed(BUTTON1) )
  {
    /* Be sure to acknowledge the button press */
    ButtonAcknowledge(BUTTON1);

    /* If the LED is already blinking, toggle it off */
    if(bLedBlink)
    {
      bLedBlink = FALSE;
      LedOff(YELLOW);
    }
    /* else start blinking the LED at the current rate */
    else
    {
      bLedBlink = TRUE;
      LedBlink(YELLOW, aeBlinkRate[u8BlinkRateIndex]);
    }
  }

Check if an update should take place and select the next array value:

  if( WasButtonPressed(BUTTON2) )
  {
    /* Be sure to acknowledge the button press */
    ButtonAcknowledge(BUTTON2);

    /* Update the blink rate and handle overflow only if the LED is currently blinking */
    if(bLedBlink)
    {
      u8BlinkRateIndex++;
      if(u8BlinkRateIndex == 4)
      {
        u8BlinkRateIndex = 0;
      }
      
      /* Request the rate udpate */
      LedBlink(YELLOW, aeBlinkRate[u8BlinkRateIndex]);
    }
  }

The Button API is obviously very useful and having the input available immediately adds a new dynamic to what you can do with the development board. You should have all that you need to work sucessfully with the buttons now.

[STATUS: RELEASED. LAST UPDATE: 2016-MAR-06]

*** ENGENUICS WILL NOT BE ABLE TO SHIP PRODUCTS BETWEEN MAY 26 AND JUNE 26, 2017 ***