Skip to content

Contributed by 邦邦, organized by Ai-Thinker

AI-WB2 Adding a Button on IO08 (Long Press, Single Click, Double Click, Release) with MultiButton

Directly porting it avoids reinventing the wheel; it's really nice and can be used in many products. <https://github.com/0x1abin/MultiButton>

Introduction MultiButton is a compact, simple, and easy-to-use event-driven button driver module that supports unlimited button expansion. The callback-based asynchronous handling of button events simplifies your program structure, removes redundant hardcoded button handling, and makes your button business logic clearer.

  1. Create a task directly in the main() function: xTaskCreate(MultiButton_poll_Task, (char*)"MultiButton_poll_Task", 512, NULL, 14, NULL);// The smaller the task priority value, the lower the priority

  2. Define a button struct Button btn1 in the task:

  3. Initialize the IO and the button module:

  4. Create a software timer that scans every 5 ms:

  5. Register events (this example uses the callback approach) (not polling):

Click to expand full code
c
void MultiButton_poll_Task(void *pvParam)
{
bl_gpio_enable_input(8, 0, 1);//

button_init(&btn1, read_button_GPIO, 1, btn1_id);
button_start(&btn1);

//make the timer invoking the button_ticks() interval 5ms.
ButtonTimers = xTimerCreate("ButtonTimers",5/portTICK_PERIOD_MS,pdTRUE,( void * ) 0,vButtonTimersCallback);//pvTimerID: 软件定时器 ID,数字形式。该 ID 典型的用法是当一个回调函数分配给一个或者多个软件定时器时,在回调函数里面根据 ID 号来处理不同的软件定时器;可以用来标记定时器,表示自己是什么定时器;可以用来保存参数,给回调函数使用
xTimerStart(ButtonTimers,portMAX_DELAY);

button_attach(&btn1, SINGLE_CLICK,     BTN1_SINGLE_CLICK_Handler);               
button_attach(&btn1, DOUBLE_CLICK,     BTN1_DOUBLE_CLICK_Handler);
button_attach(&btn1, LONG_PRESS_HOLD, BTN1_LONG_PRESS_HOLD_Handler);
button_attach(&btn1, PRESS_UP,         BTN1_PRESS_UP_Handler);

vTaskDelete(NULL);
while(1)
{

}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}

Special attention needed:

In the schematic, NC was not soldered at first; I was puzzled for a while before discovering it. bl_gpio_enable_input(8, 0, 1);//

GPIO8 acts as Bootstrap: if it is high at the moment of power-on, the module enters flashing mode; if it is low at the moment of power-on, the module boots normally.

So pull it low internally, and it goes high when the button is pressed. button_init(&btn1, read_button_GPIO, 1, btn1_id);

The button module is initialized as active-high.

The callbacks just print; no real functionality yet.

Click to expand full code
c
static TimerHandle_t ButtonTimers;

static void vButtonTimersCallback(TimerHandle_t xTimer)
{
button_ticks();
}

void BTN1_SINGLE_CLICK_Handler(void* btn)
{
blog_info_user(MultiButton,"BTN1_SINGLE_CLICK_Handler");
}

void BTN1_DOUBLE_CLICK_Handler(void* btn)
{
blog_info_user(MultiButton,"BTN1_DOUBLE_CLICK_Handler");
}

void BTN1_LONG_PRESS_HOLD_Handler(void* btn)
{
blog_info_user(MultiButton,"BTN1_LONG_PRESS_HOLD_Handler");
}

void BTN1_PRESS_UP_Handler(void* btn)
{
blog_info_user(MultiButton,"BTN1_PRESS_UP_Handler");
}

Original code

Attachments:

MultiButton.zip(242.5 KB, Downloads: 12)

Released under the MIT License. Build Time 2026-09-11 14:52:23