Teach lesson
STM32 Mbed CodeIDE (3/8): buttons, pull-ups, and debounce
Students read active-low pushbuttons with Mbed DigitalIn and PullUp, test debounce behavior, and connect button evidence to LED output on a real STM32 board.
New to LabsLand? Create your teacher account
Learning Outcomes
Read a push button with Mbed
DigitalIn.Verify whether the button behaves as active-low in the current lab view.
Use a simple confirm-after-wait debounce check before accepting a press.
Student activity preview
Activity Content
Preview only. In a class session, students can fill in responses and submit their work to the teacher.
Read before reacting
10 min
Inputs turn a fixed light pattern into a controller that responds to a person, switch, or sensor. You will first prove what the button reads when it is released and pressed, then add a simple debounce check so the program reacts to one real press instead of a noisy contact.
The CodeIDE guide lists PC_5, PC_6, and PC_10 among the button/sensor pins available in the STM32 WB55RG lab. This lesson uses PC_5 first and teaches you to verify the pressed value before building logic around it.
Many pull-up button circuits are active-low, meaning the pressed electrical level is lower than the released level. The lab wiring must still be measured before you put either value into control logic.
DigitalIn button(PC_5, PullUp);
int raw = button.read();
DigitalIn is the Mbed input object for reading a pin. PullUp asks Mbed to use the microcontroller's internal pull-up resistor, so the pin has a defined value when the button is released. button.read() returns the current 0/1 value at the moment your code calls it.
The remote lab UI has round button controls. In this lesson, use B1 for PC_5.
A simple debounce check uses two readings
Which value should later become pressed_value in your sequence program?
Measure the button value
20 min
Plan for three builds and about 25 minutes of active lab time: probe, sequence, then one changed sequence delay. If queued, prepare the two observation fields and read TODOs 1-2 before the session starts.
Open the STM32 Mbed CodeIDE lab.
Open
main.cpp.Replace the file with the probe program below.
Save, compile build 1, and upload.
Watch the console panel near the bottom of the lab view. The lab manages the serial connection; use the printed lines, not a separate terminal.
Leave the button released and copy one
button_rawline.Hold
B1until at least one or two new console lines appear, then copy the changedbutton_rawline.Record the released and pressed readings before changing the code.
Only after step 8 is complete, click Mark practice as done.
#include "mbed.h"
DigitalIn button(PC_5, PullUp);
int main() {
printf("Button probe start\n");
while (true) {
int raw = button.read();
printf("button_raw=%d\n", raw);
ThisThread::sleep_for(500ms);
}
}
Record the released and pressed readings separately. Copy the exact button_raw number from the console.
Your copied serial lines should use observed values, not values supplied by the lesson:
button_raw=<released value observed>
button_raw=<pressed value observed>With the button released, write one line in this format:
Control tested: B1 | button_raw=...
Replace the dots with the exact value copied from the console.
With B1 pressed, write one line in this format:
Control: B1 | button_raw=... | held for: ... s | changed?: yes/no
Use the exact console value and the time you held the button before deciding
whether the reading had changed.
Write your result as: released=<observed value>, pressed=<observed value>. Then state whether the pressed value is lower than the released value and therefore active-low in this session.
Start a sequence from one press
22 min
Now use B1 to start a three-LED sequence. You will insert the pressed value measured in your own probe rather than copy an assumed value.
Mechanical buttons can bounce: during one press, the electrical signal may rapidly switch between 0 and 1 for a few milliseconds. Debouncing means waiting briefly and checking again so one physical press is not treated as several presses.
Three protections have different jobs:
- Debounce confirmation: wait 50 ms, sample again, and accept only if the second sample still equals the observed pressed value.
- Sequence lockout: run_sequence() is blocking, so input is not sampled while the LED sequence runs. This prevents a second start during the sequence; it is not debounce.
- Release re-arm: after the sequence, wait until the input differs from the pressed value before accepting another press. This prevents one held press from immediately starting again; it is also not debounce.
The starter has exactly two compile-blocking placeholders. TODO 1 uses your observed pressed value. TODO 2 must be a genuine second-sample rejection condition. Replace both and search for TODO before compiling.
Replace
main.cppwith the program below and complete TODOs 1-2 from your probe evidence.Search for
TODO. When none remain, save, compile build 2, and upload.Press and release
B1, and watch the full sequence.Press the button repeatedly while the sequence is running. Extra presses during the sequence are ignored. To start another sequence, wait until the sequence is complete, release the button, then press again.
Change one visible delay inside
run_sequence()from500msto1000ms. Do not change the50msdebounce delay or20msrelease/poll delay. Save, compile build 3, upload, and compare.Only after step 5 is complete, click Mark practice as done.
#include "mbed.h"
DigitalIn button(PC_5, PullUp);
DigitalOut led1(PB_13, 1);
DigitalOut led2(PB_14, 1);
DigitalOut led3(PB_15, 1);
void led_on(DigitalOut &led) {
led = 0;
}
void led_off(DigitalOut &led) {
led = 1;
}
void all_off() {
led_off(led1);
led_off(led2);
led_off(led3);
}
void run_sequence() {
led_on(led1);
ThisThread::sleep_for(500ms);
led_on(led2);
ThisThread::sleep_for(500ms);
led_on(led3);
ThisThread::sleep_for(2000ms);
all_off();
}
int main() {
// 1: replace with the exact pressed value observed in the probe.
const int pressed_value = TODO_PRESSED_VALUE;
all_off();
printf("Button sequence start\n");
while (true) {
bool pressed = (button.read() == pressed_value);
if (pressed) {
ThisThread::sleep_for(50ms);
// 2: reject the press if the second sample is not pressed.
if (TODO_CONFIRM_CONDITION) {
continue;
}
printf("press detected: running sequence\n");
run_sequence();
printf("sequence complete; release button\n");
while (button.read() == pressed_value) {
ThisThread::sleep_for(20ms);
}
printf("ready for next press\n");
}
ThisThread::sleep_for(20ms);
}
}
Record three short sequence checks. Keep prediction and evidence separate.
Normal press test:
- predicted number of sequence starts: one;
- observed LED order;
- serial line(s) proving start and completion.
Repeated press while sequence is running:
- predicted number of starts before ready for next press;
- observed number of press detected lines before ready for next press.
Changed-delay version:
- sequence delay changed, with milliseconds;
- predicted visible difference;
- observed visible difference after build 3.
Which statement correctly separates debounce from sequence lockout?
Submit your code
8 min
Attach your saved final main.cpp
Click Check saved files, confirm that main.cpp contains your observed pressed value, the second-sample condition, the tested 1000ms sequence change, and no TODO. Then attach and submit.