Teach lesson
STM32 with Arduino API (4/4): mini-controller
Students combine potentiometer input, decisions, RGB/LED output, and serial evidence to build a compact STM32 Arduino mini-controller.
New to LabsLand? Create your teacher account
Learning Outcomes
Design a mini-controller with input, decision, output, and manual mode.
Choose and justify a threshold using real readings.
Test all three branches of a decision and communicate the result.
Student activity preview
Activity Content
Preview only. In a class session, students can fill in responses and submit their work to the teacher.
Understand the challenge and design tests
10 min
Your mini-controller will have three states:
- Potentiometer below the threshold: green color.
- Potentiometer above the threshold: red color.
- Button pressed: blue color, even if the potentiometer says something else.
The challenge is not just copying the program. By the end, you should have a
tested mini-controller: it reads an input, decides a state, changes the RGB LED,
writes evidence through Serial, and keeps one small improvement that you can
defend.
Before programming, think as if you were testing a small product. A good test
should say what you will touch, what color you expect to see, and what Serial
data would confirm that the controller made the correct decision.
The starter will print lines in this exact form:
state=<green/red/manual> pot1=<ADC reading> button=<released/pressed>.
Write three separate lines, one for each case. Use this format:
Case N | Expected RGB: ... | Serial: state=... button=...
Complete one line for each situation:
1. B1 released and potentiometer below the threshold.
2. B1 released and potentiometer at or above the threshold.
3. B1 held and potentiometer at or above the threshold.
Build and check the mini-controller
27 min
The setRgb(red, green, blue) function avoids repeating three lines every time
you change color. Each argument is a PWM brightness from 0 to 255. The
initial threshold is 600 ADC counts, but you must compare it with real readings.
bool stores true or false. Because button 1 is active LOW, the Boolean
buttonPressed becomes true when the read value is LOW. if / else if / else
checks branches from top to bottom and runs only the first true branch, so the
manual condition must come first. const char* state stores a short text label
for Serial; you do not need to change that syntax.
You will copy an initial program, test it, and adjust it. The final result should be
a small but complete controller: it reads POT_1, decides with THRESHOLD,
allows manual mode with BUTTON_1, changes the RGB LED, and writes through
Serial which state it chose.
Inputs and output used by the mini-controller
The remote setup is already wired. This map contains only the two inputs and
three RGB channels used by this challenge; no wiring change is required.
Launch the STM32 Arduino lab from this block. In CodeIDE, open
main.inoand paste the starter below.Replace TODO 1 with a Boolean expression true only when manual mode is requested. Replace TODO 2 with a comparison true when the ADC reading is at or above the threshold. Search for
TODO; none may remain.Save, select Compile, and wait for success. Then select Upload and wait for the real board to receive the initial program.
Open CodeIDE's Serial console at 115200 baud. Wait for repeated
state=... pot1=... button=...lines.Test 1 - lower automatic state: release B1 and place
Pot. pot1roughly one-third of the way along its travel. Copy the ADC reading and complete thelower position, releasedrow.Test 2 - upper automatic state: keep B1 released and place
Pot. pot1roughly two-thirds of the way along its travel. Copy the ADC reading and complete theupper position, releasedrow.Test 3 - manual override: keep the potentiometer at that upper position, press and hold B1 until Serial reports the manual state, then release it and complete the
upper position, B1 heldrow. This test checks that the button has priority.Complete the first three table rows. In the question immediately below the table, calculate the rounded midpoint of the two released-button ADC readings; that midpoint is the calibrated threshold for the center of the chosen control range.
#include <Arduino.h>
const int POT_1 = PC0;
const int BUTTON_1 = PC5; // Active LOW
const int RGB_RED = PA8;
const int RGB_GREEN = PA9;
const int RGB_BLUE = PA10;
const int THRESHOLD = 600;
void setRgb(int red, int green, int blue) {
analogWrite(RGB_RED, red);
analogWrite(RGB_GREEN, green);
analogWrite(RGB_BLUE, blue);
}
void setup() {
pinMode(BUTTON_1, INPUT);
pinMode(RGB_RED, OUTPUT);
pinMode(RGB_GREEN, OUTPUT);
pinMode(RGB_BLUE, OUTPUT);
Serial.begin(115200);
}
void loop() {
int reading = analogRead(POT_1);
bool buttonPressed = digitalRead(BUTTON_1) == LOW;
const char* state;
if (TODO_MANUAL_CONDITION) { // TODO 1: true only when manual mode is requested
setRgb(0, 0, 255);
state = "manual";
} else if (TODO_HIGH_CONDITION) { // TODO 2: reading at or above threshold
setRgb(255, 0, 0);
state = "red";
} else {
setRgb(0, 180, 0);
state = "green";
}
Serial.print("state=");
Serial.print(state);
Serial.print(" pot1=");
Serial.print(reading);
Serial.print(" button=");
if (buttonPressed) {
Serial.println("pressed");
} else {
Serial.println("released");
}
delay(100);
}
Use six rows in the table. Rows 1-3 document the initial program and must be
complete before modification. Rows 4-6 repeat the same three test cases after
calibration and the diagnostic improvement. Each row must connect input, decision, and real
hardware evidence:
- Rows 1 and 4: B1 released, potentiometer at the lower calibration position.
- Rows 2 and 5: B1 released, potentiometer at the upper calibration position.
- Rows 3 and 6: B1 held at the upper calibration position.
- In Serial values seen, copy state, pot1, and button approximately.
- In improved rows also copy the new margin field. Recreate each position
within about 30 ADC counts of its initial reading.
| Version | Test | Serial values seen (pot1 in ADC counts) | Threshold ADC counts | Expected output | Observed output | Verdict |
|---|---|---|---|---|---|---|
Using the two released-button calibration rows, calculate (lower reading + upper reading) / 2 and round to an integer ADC count. State both readings, your calculation, and the final calibrated threshold. Do not edit THRESHOLD until this calculation is written.
Calibrate and add a diagnostic
15 min
Replace 600 in THRESHOLD with your rounded midpoint. Then add one Serial
diagnostic immediately after the printed pot1 value: print margin= followed
by reading - THRESHOLD. A negative margin means below the calibrated boundary;
zero or a positive margin means at or above it.
Save, compile, upload, and reopen Serial at 115200 baud. Repeat the same three
test cases and enter improved rows 4-6. The diagnostic is useful only if the
visible state, state, and sign of margin agree; manual mode must still take
priority even when the margin is positive.
State your calibrated threshold and quote the two new Serial statements. Then use improved rows 4-6 to show that negative/positive margin matched the automatic branches and that the manual override still had priority.
Present the controller
8 min
Submit your final main.ino
Save main.ino before attaching it. The snapshot must show the final
mini-controller, with the calibrated threshold, margin Serial output,
and no remaining TODO token.
Present the mini-controller in 4-6 sentences: state its purpose and input; summarize the three decisions and outputs; cite the six-row test result; explain what the margin sign showed; and name one realistic limitation.