Overview
This tutorial uses GPIO input to read the button state: press the button and the LED lights up, release it and the LED goes off. It pairs with the previous GPIO output tutorial, teaching you input mode configuration and level (the voltage on a pin: high ≈ 3.3V, low ≈ 0V) reading.
In plain words: GPIO input is like giving the board a pair of "eyes". When the button is pressed, pin IO8 reads a high level (about 3.3V, like a doorbell being rung); released, it reads a low level (about 0V, doorbell silent). The program acts like a doorman staring at this pin, deciding whether the LED is on or off based on the level.
This tutorial is based on the official Ai-Thinker SDK (Ai-Thinker-Open/Ai-Thinker-WB2, version
release_bl_iot_sdk_1.6.40) exampleapplications/peripherals/demo_gpio; the code can be found directly in your local SDK.
Wire per the official example (see SDK applications/peripherals/demo_gpio/README.md):
| Ai-WB2 Pin | Peripheral |
|---|---|
| IO14 | LED anode (with a 330Ω current-limiting resistor in series); LED cathode to GND |
| IO8 | One end of the button; the other end to 3V3 (IO8 reads high when pressed) |
| 3V3 / GND | Power supply |
💡 The example uses external pull-up wiring for the button (pull-up = keeping the pin at a defined level when floating; here achieved by connecting the button’s other end to 3V3;
bl_gpio_enable_input(pin, 0, 0)doesn’t enable internal pull resistors), so IO8 reads high when the button is pressed.
Open a terminal and enter the official demo_gpio example project directory:
cd ~/Ai-Thinker-WB2/applications/peripherals/demo_gpio
Note:
cdis the “change directory” command; this enters the demo_gpio example project. All subsequentmakebuild andmake flashcommands must run inside this directory first.
Open demo_gpio/main.c. The full code for this step has been moved to the end of this page:
📜 Full Code — in the “Full Code” section below, collapsed by default — click to expand, identical to the official example (
applications/peripherals/demo_gpio/demo_gpio/main.c).
Code highlights:
| Code | Purpose |
|---|---|
bl_gpio_enable_input(GPIO_BUTTON_PIN, 0, 0) |
Configure IO8 as input mode (so the pin can “see” the level); without it this pin can’t read the button state |
bl_gpio_input_get_value(GPIO_BUTTON_PIN) |
Read IO8’s level: returns 1 (high/pressed) or 0 (low/released); without it the program doesn’t know the button state |
vTaskDelay(pdMS_TO_TICKS(5)) |
Re-check the button state every 5ms; without it the polling rhythm breaks — the button either responds too fast or fails |
Build in the project directory:
make -j8
Note:
makeis the “build” command, turning code into firmware (a program file) the board can run;-j8builds with 8 parallel cores, faster.
On success a firmware build_out/demo_gpio.bin is generated, and you’ll see:
✓ Built target demo_gpio
Keep the board connected via USB, confirm the serial device, and flash:
make flash p=/dev/ttyUSB0 b=921600
Note:
make flashis the “flash” command, writing the compiled firmware into the board’s chip. Afterp=comes the serial device (change it to your computer’s actual port — check withls /dev/ttyUSB*);b=is the flash baud rate (transfer speed).
⏳ During flashing, press and hold the EN button on the board when prompted to enter download mode; wait for the progress bar to complete — that means the flash succeeded.
After flashing, the board automatically restarts; press the button and IO8 goes high, the LED lights up; release and the LED goes off.
💡 Since the program polls every 5ms (polling = the program repeatedly checks a state in a loop; the opposite is “interrupt”), the button responds without noticeable delay; this is the polling detection approach besides debouncing, suitable for low-speed scenarios.
Seeing “LED on when pressed, off when released” means success; if pressing does nothing or the light flickers erratically, check the “FAQ & Troubleshooting” section at the end.
API Summary for This Tutorial
bl_gpio_enable_input(pin, pullup, pulldown)
Configures the specified pin as digital input, capable of reading high/low levels from buttons and sensors (used here to read the button).
Parameters:
pin: pin number, values:0~22(GPIO0~GPIO22); this tutorial uses8for the button (GPIO_BUTTON_PIN)pullup: enable internal pull-up, values:1enable /0disable (recommend1for button-to-ground wiring, reads high when floating)pulldown: enable internal pull-down, values:1enable /0disable (recommend1for button-to-VCC wiring)
Return: 0 on success; negative error code on failure
bl_gpio_enable_output(pin, pullup, pulldown)
Configures the specified pin as push-pull output, capable of driving loads like LEDs and buzzers (used here to light the LED).
Parameters:
pin: pin number, values:0~22(GPIO0~GPIO22); this tutorial uses14for the LED (GPIO_LED_PIN)pullup: enable internal pull-up, values:1enable /0disable (push-pull output needs no pull-up, pass0)pulldown: enable internal pull-down, values:1enable /0disable
Return: 0 on success; negative error code on failure
bl_gpio_output_set(pin, value)
Outputs a high or low level on a pin already configured as output.
Parameters:
pin: pin number, values asbl_gpio_enable_output(0~22)value: output level, values:1high (3.3V) /0low (0V)
Return: 0 on success; negative error code on failure
bl_gpio_input_get_value(pin)
Reads the current level of the specified pin.
Parameters:
pin: pin number, values:0~22
Return: the level value: 1 high / 0 low (returns 0 on read failure)
vTaskDelay(ms)
Suspends the current task for the specified number of milliseconds, yielding the CPU to other tasks.
Parameters:
ms: delay in milliseconds, values: any non-negative integer (internally converted to system ticks viapdMS_TO_TICKS)
Return: none
Full Code
Below is the complete demo_gpio/main.c source, identical to the official example (applications/peripherals/demo_gpio/demo_gpio/main.c):
📜 Click to expand the full demo_gpio/main.c code
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <bl_gpio.h>
#define GPIO_BUTTON_PIN 8
#define GPIO_LED_PIN 14
void main(void)
{
bl_gpio_enable_input(GPIO_BUTTON_PIN, 0, 0);
bl_gpio_enable_output(GPIO_LED_PIN, 0, 0);
bl_gpio_output_set(GPIO_LED_PIN, 0);
for (;;) {
if (bl_gpio_input_get_value(GPIO_BUTTON_PIN)) {
bl_gpio_output_set(GPIO_LED_PIN, 1);
}
else {
bl_gpio_output_set(GPIO_LED_PIN, 0);
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}FAQ & Troubleshooting
⚠️ Pressing the button doesn't light the LED
Cause: the button's other end isn't connected to 3V3, the jumper wire is loose, or pin IO8 is occupied
Fix: confirm one end of the button connects to IO8 and the other to 3V3; remove other jumper wires from IO8 and retry
⚠️ The LED stays on and won't go off
Cause: LED polarity reversed, or IO14 conflicts with other peripherals on the board
Fix: confirm the LED anode (long leg) connects to IO14 through the resistor and the cathode to GND
⚠️ The button state jitters (occasional false triggers)
Cause: mechanical button contacts bounce when pressed/released
Fix: the demo example is a polling demo without debouncing; for stable detection, add a 10~20ms delay debounce in software or use interrupts — see EXTI External Interrupt
⚠️ Flashing keeps waiting, the progress bar doesn't move
Cause: download mode wasn't entered, or the cable only charges and can't transfer data
Fix: press and hold EN to enter download mode when prompted; try a Type-C cable that can transfer data and retry
⚠️ Running make reports no Makefile found
Cause: the build command ran in the wrong directory (it must run inside the example project)
Fix: first cd ~/Ai-Thinker-WB2/applications/peripherals/demo_gpio into the project directory, then run make -j8
Self-Check
The LED lights up immediately when the button is pressed and goes off immediately when released — GPIO input is verified.

