element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Personal Blogs
  • Community Hub
  • More
Personal Blogs
Legacy Personal Blogs A Button Class for detecting Press/Release events using the Mbed-OS
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: james.flynn
  • Date Created: 30 Aug 2018 12:43 AM Date Created
  • Views 1253 views
  • Likes 2 likes
  • Comments 0 comments
  • embeded
  • arm mbed
  • mbed os 5
  • avnet design
  • mbed
  • avnet_coding
Related
Recommended

A Button Class for detecting Press/Release events using the Mbed-OS

james.flynn
james.flynn
30 Aug 2018

How many times have you had to implement a button press/release routine (with de-bounce) for a project?  If you write software for embedded projects, I’ll bet it is more than once.   Because I was tired of writing this code over and over (well let’s be honest, I was copying it), I decided to write a button class that would be self-contained.  I work with the ARM Mbed-OS a lot so I utilized some of the O/S services—primarily the EventQueue.  I suppose with a little effort, it could be ported to most any other OS.

 

I use typically name files with the ‘*.hpp’ extension when they are a self-contained class, so I’ve contained all the button class in a named ‘button.hpp’  as follows:

/**
* copyright (c) 2018, James Flynn
* SPDX-License-Identifier: MIT
*/

/**
*   @file   button.hpp
*   @brief  A small BUTTON class for detecting & debouncing button presses
*
*   @author James Flynn
*
*   @date   24-Aug-2018
*/

#include "mbed.h"
#define BUTTON_DEBOUNCE           20 //specify the number of msec to debounce

class Button {
    protected:
        InterruptIn user_button;
        void (*br_cb)(int);    //button release callback
        void (*bp_cb)(void);   //button press callback

        Thread      button_thread;
        void        button_monitor_task(void);
        EventQueue  button_queue;
        uint64_t    bp_time, bp_duration;  //button press start time and button press duration
        int         button_pressed;        //counts the number of times the button has been pressed

        void button_press_handler(void) {
            if( (rtos::Kernel::get_ms_count() - bp_time) < BUTTON_DEBOUNCE)
                return;
            bp_time = rtos::Kernel::get_ms_count();
            if( bp_cb )
                bp_cb();
        }

        void button_release_handler(void) {
            uint64_t tmp = rtos::Kernel::get_ms_count() - bp_time;
            if( tmp > BUTTON_DEBOUNCE ) {
                bp_duration = tmp;
                button_pressed++;
                if( br_cb )
                  br_cb(bp_duration);
                }
        }

    public:
        enum State { ActiveHigh = 0, ActiveLow };

        Button(PinName p, State s, void (*cb)(int)=NULL) : 
            user_button(p),
            br_cb(cb),
            bp_cb(NULL),
            bp_time(0),
            bp_duration(0),
            button_pressed(0)
            {
            // The user button is setup for the edge to generate an interrupt. 
            // The release is caught an event queue callback
            button_thread.start(callback(&button_queue, &EventQueue::dispatch_forever));
            if( s == ActiveHigh ) {
                user_button.rise( Callback<void()>(this, &Button::button_press_handler) ); 
                user_button.fall( button_queue.event( Callback<void()>(this, &Button::button_release_handler)));
                }
            else{
                user_button.fall( Callback<void()>(this, &Button::button_press_handler) );
                user_button.rise(button_queue.event(Callback<void()>(this, &Button::button_release_handler)));
                }
            }

        // will return the number of times the button has been pressed (if it was pressed > 1 time before checked)
        // and returns the duration of the last button press in duration
        int chkButton_press(int *duration) {
            int bp = button_pressed;

            if( button_pressed ) {
                *duration = bp_duration;
                bp_duration = 0;
                button_pressed = 0;
                }
            return bp;
            }

        //allows the user to set a callback for a button press in
        void setButton_press_cb( void (*buttonpresscb)(void) ) {
            bp_cb = buttonpresscb;
            }
};

 

The way it works is easiest to understand by using the following small program that implements as a test driver:

 

#include "mbed.h"
#include "Button.hpp"
 
void br_callback(int dur)
{
    printf("\r\n!! button RELEASE called, press time: %d msec\r\n", dur);
}
 
void bp_callback(void)
{
    printf("\r\n!! button PRESS called\r\n"); //normally you wouldn't call printf in an interrupt context
}
 
int main() {
    int k, dur;
    Button* button_ptr;
    
    printf("Testing button class\r\n");
    printf("Test Standard polling type implementation\r\n");
    button_ptr = new Button(USER_BUTTON, Button::ActiveHigh);
    while( (k=button_ptr->chkButton_press(&dur)) == 0 )
        /* wait */;
    printf(">Button pressed %d times, last was %d msec\r\n",k,dur);
    delete button_ptr;
    
    printf("\nTest with Release callback\r\n");
    button_ptr = new Button(USER_BUTTON, Button::ActiveHigh, br_callback);
    while( (k=button_ptr->chkButton_press(&dur)) == 0 )
        /* wait */;
    printf(">Button pressed %d times, last was %d msec\r\n",k,dur);
    delete button_ptr;
        
    printf("\nTest with Press & Release callback\r\n");
    button_ptr = new Button(USER_BUTTON, Button::ActiveHigh, br_callback);
    button_ptr->setButton_press_cb(bp_callback);
    while( (k=button_ptr->chkButton_press(&dur)) == 0 )
        /* wait */;
    printf(">Button pressed %d times, last was %d msec\r\n",k,dur);
    while (1) {
        wait(.5);
    }
 
}

 

When the object is created, the user specifies the USER_BUTTON which is the binary I/O that the button is attached to, then the user specifies if the button is active in the HIGH logic level (ActiveHigh) or the LOW logic level (ActiveLow).  I dynamically the button in this test so I could delete it then recreate it using different methods for instantiation.

 

The first case simply monitors the button by calling ‘chkButton_press’ this function takes an argument that will be assigned the amount of time (msec) that the button was pressed.  The functioin ‘chkButton_press’ actually returns the number of times the button has been pressed and the duration (‘dur’ in the example) is set to the length of time of the last button press.

 

In the second test case, when the object is instantiated, I assign a callback for the button release.  This allows you to perform some action on the button release (like maybe turning off an LED). When the button is released.  When the callback is invoked it is passed the duration of the button press.

 

In the third test, the button is instantiated with a callback function and then a button press function is set via the 'setButton_press_cb' function.  This allows a function to be called when the button is pressed—like maybe lighting an LED.  The important thing to remember is that the button press function will be running in an interrupt context so you want to avoid functions that will take long times to complete--unlike I did in the above example.

 

Hopefully, this class will help others easily obtain a clean and efficient way to handle button presses when using the Mbed-OS. If you want to import this into your on-line compiler, you can get it at https://os.mbed.com/users/JMF/code/button_class_and_test/

  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube