Skip to content

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) example applications/peripherals/demo_gpio; the code can be found directly in your local SDK.

🎯Page GoalRead the button state through GPIO input, control the LED on/off, and learn the input mode configuration and level reading APIs.
🧰Prerequisites① Ai-WB2 development board, button, LED, 330Ω current-limiting resistor, jumper wires (wires with pins at both ends, used to connect board pins to peripherals) ② Environment set up per [SDK Installation](../sdk/sdk_intro) and [GPIO Output (Blink LED)](./gpio_led) completed.
🔗RelatedGPIO output: [GPIO Output (Blink LED)](./gpio_led); external interrupt: [EXTI External Interrupt](./exti_interrupt).

Hardware Wiring

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.

Enter the Example Project

Open a terminal and enter the official demo_gpio example project directory:

cd ~/Ai-Thinker-WB2/applications/peripherals/demo_gpio

Note: cd is the “change directory” command; this enters the demo_gpio example project. All subsequent make build and make flash commands must run inside this directory first.

Write the Code

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 the Project

Build in the project directory:

make -j8

Note: make is the “build” command, turning code into firmware (a program file) the board can run; -j8 builds with 8 parallel cores, faster.

On success a firmware build_out/demo_gpio.bin is generated, and you’ll see:

✓ Built target demo_gpio
Flash the Firmware

Keep the board connected via USB, confirm the serial device, and flash:

make flash p=/dev/ttyUSB0 b=921600

Note: make flash is the “flash” command, writing the compiled firmware into the board’s chip. After p= comes the serial device (change it to your computer’s actual port — check with ls /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.

Run and Verify

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 uses 8 for the button (GPIO_BUTTON_PIN)
  • pullup: enable internal pull-up, values: 1 enable / 0 disable (recommend 1 for button-to-ground wiring, reads high when floating)
  • pulldown: enable internal pull-down, values: 1 enable / 0 disable (recommend 1 for 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 uses 14 for the LED (GPIO_LED_PIN)
  • pullup: enable internal pull-up, values: 1 enable / 0 disable (push-pull output needs no pull-up, pass 0)
  • pulldown: enable internal pull-down, values: 1 enable / 0 disable

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 as bl_gpio_enable_output (0~22)
  • value: output level, values: 1 high (3.3V) / 0 low (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 via pdMS_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
c
#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.

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