BBC micro:bit Fun Projects: Learn Hardware Programming with MicroPython
Goal: Build a complete understanding of embedded systems programming through fun, hands-on projects using the BBC micro:bit. You will master LED displays, button input, sensors, radio communication, and real-time programming patterns. By the end, you will understand how software controls hardware, how to read sensor data, how to communicate between devices wirelessly, and how to build interactive projects that respond to the physical world. These skills transfer directly to professional embedded development while being accessible to complete beginners.
Introduction: What This Guide Covers
The BBC micro:bit is a pocket-sized programmable computer designed to make hardware programming accessible to everyone. Originally created to teach computing in UK schools, it has become a favorite platform for learners of all ages who want to understand how software interacts with the physical world.
What you will build (by the end of this guide):
- Interactive LED displays and animations
- Games that respond to tilting, shaking, and button presses
- Wireless communication between multiple micro:bits
- Fitness trackers and environmental monitors
- Musical instruments and sound generators
- Practical tools like calculators and password locks
Scope (what is included):
- MicroPython programming on the micro:bit
- All built-in sensors: accelerometer, compass, light, temperature
- Radio communication between micro:bits
- Sound and music generation
- Button and touch input handling
Out of scope (for this guide):
- Bluetooth Low Energy (requires more advanced setup)
- External hardware beyond basic components
- JavaScript/Blocks programming (we focus on MicroPython)
Why micro:bit is Perfect for Learning
Traditional Microcontroller Learning micro:bit Learning
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ Buy microcontroller │ │ Get micro:bit (one device) │
│ Buy breadboard │ │ Connect USB cable │
│ Buy LEDs, resistors │ │ Open web editor │
│ Buy sensors separately │ │ Write code │
│ Wire everything correctly │ │ Flash to device │
│ Debug wiring issues │ │ It works! │
│ Finally write code │ │ │
└─────────────────────────────────┘ └─────────────────────────────────┘
Hours of setup Minutes to first program
The micro:bit includes everything you need built-in: a 5x5 LED display, two buttons, accelerometer, compass, temperature sensor, light sensor, speaker, microphone, and radio. No wiring required to start learning.
Why micro:bit Matters
The Accessibility Revolution
Before micro:bit and similar educational boards, learning hardware programming required:
- Expensive development kits ($50-200+)
- Complex toolchains and IDEs
- Breadboards, wires, and components
- Electronics knowledge to avoid damaging parts
- Patience to debug wiring issues before writing a single line of code
The micro:bit changed this equation. For under $20, you get a complete embedded system with sensors, display, buttons, and wireless communication. You can go from zero knowledge to a working program in minutes, not hours or days.
Real-World Impact
Education Statistics:
- Deployed to millions of students across 60+ countries
- BBC initially gave one free to every Year 7 student in the UK (about 1 million devices)
- Studies show students using micro:bit report higher confidence in programming
- Teachers report increased engagement compared to screen-only programming
Industry Applications:
- Prototyping IoT concepts before production hardware
- Teaching embedded programming fundamentals that transfer to professional work
- Rapid proof-of-concept for sensor-based projects
- Gateway to ARM Cortex-M development (the same processor family used in professional embedded systems)
Skills That Transfer
The concepts you learn with micro:bit apply directly to professional embedded development:
| micro:bit Concept | Professional Equivalent |
|---|---|
| LED matrix control | Display drivers, GPIO manipulation |
| Button interrupts | Hardware interrupt handling |
| Accelerometer reading | I2C sensor interfacing |
| Radio communication | Wireless protocols (BLE, LoRa, Zigbee) |
| Event-driven programming | RTOS event systems |
| Power management | Battery-powered device design |
The Hardware at a Glance
┌─────────────────────────────────────┐
│ BBC micro:bit V2 │
│ │
│ ┌─────────────────────────┐ │
│ │ 5 x 5 LED Matrix │ │
Button A ───────────│────│ (also light sensor) │─────│─────── Button B
│ │ │ │
│ └─────────────────────────┘ │
│ │
│ ┌───┐ Touch Logo ┌───┐ │
│ │ A │ (O) │ B │ │
│ └───┘ └───┘ │
│ │
│ ──────────────────────── │
│ Edge Connector (25 pins) │
│ 0 1 2 3V GND │
└─────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Inside the micro:bit: │
│ - Nordic nRF52833 (ARM Cortex-M4, 64MHz, 128KB RAM) │
│ - 3-axis accelerometer + 3-axis magnetometer │
│ - Temperature sensor │
│ - MEMS microphone + speaker │
│ - 2.4GHz radio (micro:bit radio + BLE) │
│ - USB interface for programming │
└──────────────────────────────────────────────────────────────┘
Prerequisites & Background Knowledge
Essential Prerequisites (Must Have)
Programming Fundamentals:
- Basic understanding of variables, loops, and conditionals
- Familiarity with any programming language (not necessarily Python)
- Ability to type code and understand syntax errors
Hardware Basics:
- Understanding that electronic devices run on electricity
- Concept that sensors detect physical phenomena
- Willingness to experiment and learn from mistakes
Equipment:
- BBC micro:bit (V1 or V2 - V2 recommended for speaker/microphone)
- Micro USB cable (data cable, not charge-only)
- Computer with web browser or Mu editor installed
Recommended Reading: “Programming the BBC micro:bit” by Simon Monk - Introduction and Chapter 1
Helpful But Not Required
Python knowledge: You can learn Python as you go; micro:bit MicroPython is simplified Electronics background: Not needed for these projects; micro:bit handles the hardware Prior embedded experience: These projects assume none; you will build it up
Self-Assessment Questions
Before starting, can you answer these questions?
- Do you understand what a variable is and how to assign a value to it?
- Can you explain what a loop does in simple terms?
- Do you have a micro:bit and USB cable ready?
- Are you comfortable with making mistakes and debugging?
- Can you save files to your computer?
If you answered “no” to questions 1-2: Spend an hour with any beginner Python tutorial first.
If you answered “no” to question 3: Order a micro:bit kit before proceeding.
Development Environment Setup
Option 1: Online Editor (Easiest)
- Go to https://python.microbit.org/
- Write code in the browser
- Click “Send to micro:bit” or download the .hex file
- Drag .hex file to MICROBIT drive
Option 2: Mu Editor (Recommended)
- Download Mu from https://codewith.mu/
- Install and select “BBC micro:bit” mode
- Write code and click “Flash” to program
Testing your setup:
from microbit import *
display.scroll("Hello!")
If “Hello!” scrolls across the LED display, you’re ready to begin.
Time Investment
- Beginner projects (1-5): 1-2 hours each
- Intermediate projects (6-12): 2-4 hours each
- Advanced projects (13-17): 4-8 hours each
Total to complete all projects: 40-80 hours (spread over weeks is fine!)
Core Concepts Analysis
This section covers the fundamental concepts you will use in every project.
The LED Display: Your Visual Output
The micro:bit’s 5x5 LED display is your primary way to show information. Each LED can be turned on or off, and brightness can be controlled from 0 (off) to 9 (brightest).
LED Coordinates (x, y):
Column (x)
0 1 2 3 4
┌───┬───┬───┬───┬───┐
0 │0,0│1,0│2,0│3,0│4,0│ Row (y)
├───┼───┼───┼───┼───┤
1 │0,1│1,1│2,1│3,1│4,1│
├───┼───┼───┼───┼───┤
2 │0,2│1,2│2,2│3,2│4,2│
├───┼───┼───┼───┼───┤
3 │0,3│1,3│2,3│3,3│4,3│
├───┼───┼───┼───┼───┤
4 │0,4│1,4│2,4│3,4│4,4│
└───┴───┴───┴───┴───┘
Example: display.set_pixel(2, 2, 9)
Sets the center LED to maximum brightness
Key Display Functions:
display.show(image)- Show a built-in or custom imagedisplay.scroll(text)- Scroll text across the displaydisplay.set_pixel(x, y, brightness)- Control individual LEDsdisplay.clear()- Turn off all LEDs
Button Input: Reading User Actions
The micro:bit has two buttons (A and B) plus a touch-sensitive logo (V2 only). Buttons can be checked in two ways:
Button States:
Polling (check at a moment) Event-driven (react to changes)
┌─────────────────────────┐ ┌─────────────────────────────────┐
│ if button_a.is_pressed()│ │ if button_a.was_pressed(): │
│ # Button is DOWN now│ │ # Button was pressed since │
│ │ │ # last check (counts once) │
└─────────────────────────┘ └─────────────────────────────────┘
Key Differences:
is_pressed()returns True if button is currently held downwas_pressed()returns True once per press, then resetsget_presses()returns count of presses since last check
The Accelerometer: Detecting Motion
The accelerometer measures acceleration in three axes. When stationary, it measures gravity, which tells you orientation.
Accelerometer Axes:
Y+ (tilt forward)
▲
│
│
┌───────────┼───────────┐
│ │ │
│ LED │ LED │
X- ◄───│ Matrix │ ─│───► X+ (tilt right)
│ │ │
│ │ │
└───────────┴───────────┘
│
▼
Y- (tilt back)
Z+ points up out of the screen
Z- points down into the screen
Reading Range: -2000 to +2000 (milli-g)
At rest, flat on table: x≈0, y≈0, z≈-1000 (gravity pulls down)
Key Accelerometer Functions:
accelerometer.get_x()- Tilt left/right (-2000 to +2000)accelerometer.get_y()- Tilt forward/back (-2000 to +2000)accelerometer.get_z()- Up/down accelerationaccelerometer.current_gesture()- Detects “shake”, “face up”, etc.
The Compass: Finding North
The magnetometer measures magnetic field strength, which can determine compass heading.
Compass Heading:
North (0°/360°)
▲
│
│
West (270°) ◄─────┼─────► East (90°)
│
│
▼
South (180°)
compass.heading() returns 0-359 degrees
Important: The compass must be calibrated before first use. compass.calibrate() starts a mini-game where you tilt the micro:bit to light up all LEDs.
Radio Communication: Wireless Messaging
micro:bits can send and receive messages wirelessly using a simple radio protocol.
Radio Communication:
micro:bit A micro:bit B
┌─────────┐ ┌─────────┐
│ Channel │ ~~~~~~~~~~~~ │ Channel │
│ 7 │ ─── Message ────► │ 7 │
│ │ ~~~~~~~~~~~~ │ │
└─────────┘ └─────────┘
Both devices must be on the same channel (0-83)
Messages are strings up to 251 bytes
Multiple micro:bits can communicate on the same channel
Key Radio Functions:
radio.on()- Enable radioradio.config(channel=7)- Set channelradio.send(message)- Send a stringradio.receive()- Receive a message (or None if empty)
Event Loop Pattern: The Heart of Interactive Programs
Most micro:bit programs follow this pattern:
from microbit import *
# Setup code runs once
setup_game()
# Event loop runs forever
while True:
# 1. Read inputs
check_buttons()
read_sensors()
# 2. Update state
update_game_logic()
# 3. Update outputs
update_display()
# 4. Small delay
sleep(50) # 50ms = 20 updates per second
This pattern ensures responsive, predictable behavior.
Concept Summary Table
| Concept | What It Does | Key Function | Project Examples |
|---|---|---|---|
| LED Display | Show images, text, patterns | display.show() |
1, 2, 3, 11, 12 |
| Buttons | Detect user presses | button_a.was_pressed() |
4, 10, 11, 14 |
| Accelerometer | Measure tilt and motion | accelerometer.get_x() |
5, 6, 9, 12 |
| Compass | Find magnetic north | compass.heading() |
7 |
| Temperature | Read ambient temperature | temperature() |
8 |
| Light Level | Measure brightness | display.read_light_level() |
8, 16 |
| Speaker | Play sounds and music | music.play() |
13, 17 |
| Radio | Wireless communication | radio.send() |
3, 15 |
| Touch | Detect logo touch (V2) | pin_logo.is_touched() |
15 |
Quick Start: Your First 48 Hours
If you’re feeling overwhelmed, follow this path:
Day 1 (2-3 hours):
- Set up Mu Editor or the online editor
- Complete Project 1: LED Patterns
- Complete Project 4: Button Counter
Day 2 (2-3 hours):
- Complete Project 11: Magic 8 Ball
- Complete Project 5: Tilt Game
- Celebrate - you’ve built interactive hardware!
After this, you’ll have confidence to tackle any project in any order.
Recommended Learning Paths
Path A: Game Developer (Fun First)
Projects: 1 → 4 → 5 → 6 → 10 → 11
Path B: Scientist/Explorer
Projects: 1 → 7 → 8 → 9 → 16
Path C: Communication Expert
Projects: 1 → 3 → 12 → 15
Path D: Complete Mastery
All projects in order (1 through 17)
Projects
Project 1: LED Display Patterns and Animations
What You’ll Build
A collection of animated LED patterns including scrolling text, beating hearts, growing spirals, and custom animations. This is your first step into controlling hardware with code.
Why It Teaches the Concept
The LED display is the simplest output device. By controlling individual pixels, you learn:
- How computers represent images as numbers
- The concept of frames and animation timing
- How to translate visual ideas into code
Real World Outcome
When you complete this project, running your code will produce:
Pattern 1: Scrolling Message
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│H │→│ e │→│ l │→│ l │→...
│ │ │ │ │ │ │ │
└─────┘ └─────┘ └─────┘ └─────┘
Pattern 2: Beating Heart
Frame 1 Frame 2 Frame 1
┌─────┐ ┌─────┐ ┌─────┐
│.X.X.│ │XXXXX│ │.X.X.│
│XXXXX│ │XXXXX│ │XXXXX│
│XXXXX│ → │XXXXX│ → │XXXXX│
│.XXX.│ │XXXXX│ │.XXX.│
│..X..│ │.XXX.│ │..X..│
└─────┘ └─────┘ └─────┘
Pattern 3: Spiral Growth
Step 1 Step 2 Step 3 Step 4
X... XX.. XX.. XXX.
.... X... X... X...
.... .... X... X...
.... .... .... X...
The Core Question You’re Answering
How does software translate into visible light? How do we create the illusion of motion from static frames?
Hardware Concepts Explained
Persistence of Vision: Your eye retains an image for about 1/25th of a second. By showing frames faster than this, separate images blend into smooth animation.
Pixel Coordinates: The display uses a coordinate system where (0,0) is the top-left corner. X increases rightward, Y increases downward.
Brightness Levels: Each LED can be set from 0 (off) to 9 (maximum brightness), allowing for effects like fading.
Code Snippet: Creating Custom Images
from microbit import *
# Define a custom image using strings
# Each character represents brightness (0-9)
my_arrow = Image("00900:"
"09990:"
"90909:"
"00900:"
"00900")
display.show(my_arrow)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 3: LED Display
- micro:bit MicroPython documentation: Images section
Hints in Layers
Hint 1 - Starting Point:
Begin with built-in images like Image.HEART and Image.HAPPY. Use display.show() to display them, then add sleep() to control timing.
Hint 2 - Next Level: Create a list of images and loop through them. Each iteration shows one frame, then sleeps.
Hint 3 - Technical Details:
For smooth animation, use 100-200ms between frames. For a beating heart, alternate between Image.HEART and Image.HEART_SMALL.
Hint 4 - Debugging:
If animation seems stuck, check your sleep() values. If too fast, you won’t see individual frames. If too slow, it looks choppy.
Interview Questions
- How would you create a smooth fade effect on the LED display?
- What frame rate is needed for animation to appear smooth?
- How does the coordinate system of the display relate to how you’d define a custom image?
- What’s the memory cost of storing a 5x5 image with 10 brightness levels?
Common Pitfalls
| Problem | Cause | Fix |
|---|---|---|
| Nothing displays | Forgot to import microbit | Add from microbit import * |
| Animation too fast | No sleep between frames | Add sleep(100) |
| Image looks wrong | Coordinates confused | Remember (0,0) is top-left |
| Display flickering | Updating too frequently | Reduce update rate |
Project 2: Advanced LED Animations
What You’ll Build
More sophisticated animations: a bouncing ball, a snake that grows, Conway’s Game of Life, and a starfield effect. These patterns require tracking state and updating multiple pixels per frame.
Why It Teaches the Concept
Moving beyond static patterns, you learn:
- State management (tracking position over time)
- Boundary detection (what happens at edges)
- Algorithmic thinking (rules that generate patterns)
Real World Outcome
Bouncing Ball:
The ball starts at top-left, moves diagonally, bounces off walls
Frame 1 Frame 5 Frame 9 Frame 13
X.... ....X ....X X....
..... ..... ..... .....
..... ..... ..... .....
..... ..... ..... .....
..... ..... X.... ....X
Snake Growth:
Turn 1 Turn 5 Turn 10 Turn 15
X.... XXXXX XXXXX XXXXX
..... ....X XXXXX XXXXX
..... ..... ...XX XXXXX
..... ..... ..... XXXXX
..... ..... ..... ...XX
The Core Question You’re Answering
How do you create complex emergent behavior from simple rules applied repeatedly?
Hardware Concepts Explained
Frame Buffer Concept: Games often draw to a “buffer” before displaying. This prevents partial updates being visible. On micro:bit, you can build an image, then display.show() it all at once.
Update Loop Timing: The speed of your animation depends on how often you update. Too fast and things become a blur. Too slow and it’s not engaging.
Code Snippet: Bouncing Ball Logic
from microbit import *
x, y = 0, 0
dx, dy = 1, 1 # Direction of movement
while True:
display.clear()
display.set_pixel(x, y, 9)
# Move
x += dx
y += dy
# Bounce off walls
if x <= 0 or x >= 4:
dx = -dx
if y <= 0 or y >= 4:
dy = -dy
sleep(200)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 3: LED Display
- Wikipedia: Conway’s Game of Life (for algorithm rules)
Hints in Layers
Hint 1: Start with a single moving dot. Track its x, y position and direction (dx, dy).
Hint 2: Add boundary checking. When x reaches 0 or 4, reverse dx. Same for y and dy.
Hint 3: For Game of Life, create a 5x5 list of lists. Count neighbors, apply rules, update grid.
Hint 4: Use Image() to create each frame from your data structure before displaying.
Interview Questions
- How would you implement collision detection between two moving objects?
- What data structure is best for representing a 2D grid?
- How does double buffering prevent visual glitches?
- What’s the time complexity of updating Conway’s Game of Life grid?
Project 3: Radio Messenger
What You’ll Build
A two-way radio messenger that sends and receives text between two micro:bits. You’ll create a simple chat system with message acknowledgment.
Why It Teaches the Concept
Wireless communication is fundamental to IoT and embedded systems. You’ll learn:
- Setting up radio channels
- Sending and receiving data
- Handling the case when no message is available
- Basic protocol design (acknowledgments)
Real World Outcome
micro:bit A micro:bit B
┌─────────┐ ┌─────────┐
│ Press A │ ──── "Hello" ────► │ Display │
│ to send │ │ "Hello" │
│ │ │ │
│ Display │ ◄──── "Got it" ─── │ Auto- │
│ ":)" │ │ reply │
└─────────┘ └─────────┘
Usage:
- Button A sends a greeting
- Button B sends a response
- Messages scroll on display
- Both devices on channel 7
The Core Question You’re Answering
How do wireless devices coordinate communication without wires?
Hardware Concepts Explained
Radio Channels: The micro:bit radio operates on channels 0-83. All devices on the same channel can hear each other. Think of it like walkie-talkie frequencies.
Message Buffering: Received messages are stored in a buffer. radio.receive() returns one message or None if the buffer is empty.
Radio Communication Flow:
Sender Receiver
┌────────┐ ┌────────┐
│ radio │ │ radio │
│.send() │ │.recv() │
└───┬────┘ └───┬────┘
│ │
│ ┌─────────────────┐ │
└───►│ Radio Waves │───────┘
│ (2.4 GHz) │
└─────────────────┘
~1 Mbit/s, range ~50m indoors
Code Snippet: Basic Send and Receive
from microbit import *
import radio
radio.on()
radio.config(channel=7)
while True:
# Send message on button press
if button_a.was_pressed():
radio.send("Hello!")
display.show(Image.ARROW_N)
# Check for incoming messages
message = radio.receive()
if message:
display.scroll(message)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 11: Radio
- micro:bit MicroPython documentation: Radio module
Hints in Layers
Hint 1: Start with one micro:bit sending and one receiving. Don’t worry about two-way yet.
Hint 2: Add button handling to trigger sends. Use was_pressed() to avoid repeat sends.
Hint 3: For acknowledgment, have receiver send back a confirmation string.
Hint 4: Handle the None case from radio.receive() - it means no message is waiting.
Interview Questions
- What happens if multiple micro:bits send at the exact same time?
- How would you implement a reliable message delivery protocol?
- Why do we need to check if
radio.receive()returns None? - What’s the difference between broadcast and point-to-point communication?
Project 4: Button Counter and Clicker Game
What You’ll Build
A multi-function counter with:
- Button A increments the count
- Button B decrements
- Shake to reset
- Long press for different action
Then extend it into a clicking speed game.
Why It Teaches the Concept
Buttons are the most basic input. This project teaches:
- Difference between
is_pressed()andwas_pressed() - Debouncing (handling button bounce)
- State management
- User interface design on limited display
Real World Outcome
Counter Mode:
Press A Press A Press A Press B Shake
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ 1 │ → │ 2 │ → │ 3 │ → │ 2 │ → │ 0 │
└─────┘ └─────┘ └─────┘ └─────┘ └─────┘
Clicker Game:
Start 5 sec Time up Show Score
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│READY│ → │ 23 │ → │STOP!│ → │23CPS│
└─────┘ └─────┘ └─────┘ └─────┘
"CPS" = Clicks Per Second
The Core Question You’re Answering
How do we reliably detect discrete user actions from continuous electrical signals?
Hardware Concepts Explained
Button Debouncing: Mechanical buttons don’t produce clean signals. When pressed, they “bounce” between on and off for a few milliseconds.
Physical Button Press:
Ideal Signal: Actual Signal:
┌─────── ┌─┬─┬─────
│ │ │ │
────┘ ────┴─┴─┘
↑
Bounce (1-10ms)
The micro:bit handles this in hardware, but
you still need to handle it in software with
was_pressed() vs is_pressed()
Code Snippet: Counter with Reset
from microbit import *
count = 0
while True:
if button_a.was_pressed():
count += 1
display.show(count)
if button_b.was_pressed():
count -= 1
if count < 0:
count = 0
display.show(count)
if accelerometer.was_gesture("shake"):
count = 0
display.show(count)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 4: Buttons
- “Programming the BBC micro:bit” by Simon Monk - Chapter 7: Accelerometer
Hints in Layers
Hint 1: Use was_pressed() for counting - it only returns True once per press.
Hint 2: For numbers > 9, use display.scroll() or show digits sequentially.
Hint 3: For the clicker game, use running_time() to measure elapsed milliseconds.
Hint 4: Store the high score in a variable and compare after each round.
Interview Questions
- What’s the difference between polling and interrupt-driven button handling?
- How would you detect a “long press” vs a “short press”?
- Why might
was_pressed()miss a button press? - How would you implement a combo system (press A then B within 500ms)?
Project 5: Tilt Maze Game
What You’ll Build
A maze game where you tilt the micro:bit to guide a dot through a maze to reach the goal. The accelerometer controls movement, and the maze is displayed on the LEDs.
Why It Teaches the Concept
Accelerometer games teach:
- Reading analog sensor values
- Converting sensor data to game actions
- Collision detection
- Level design on a constrained display
Real World Outcome
Game Display:
X = Player (bright)
# = Wall (dim)
O = Goal (blinking)
Level 1 Level 2 Level 3
X.... X#... X.#..
.###. .#.#. .#.#.
...#. .#.#. .#.#.
.#... ...#. .###.
....O ....O ....O
Tilt micro:bit right → Player moves right
Tilt forward → Player moves up
Reach goal → Victory animation + next level
The Core Question You’re Answering
How do we translate physical orientation into game controls?
Hardware Concepts Explained
Accelerometer Values: The accelerometer returns values from -2000 to +2000 (milli-g). These represent acceleration, but when still, they measure gravity’s pull.
Interpreting Accelerometer for Tilt:
Flat (level): Tilted Right: Tilted Forward:
┌─────┐ ┌─────┐ ┌─────┐
│ │ │ │╲ │ │
│ │ │ │ ╲ │ │
└─────┘ └─────┘ ╲ └─────┘─
x ≈ 0 x ≈ +500 y ≈ -500
y ≈ 0 (tilted (tilted
z ≈ -1000 toward right) toward you)
Thresholds:
|x| > 300: Horizontal tilt detected
|y| > 300: Forward/back tilt detected
Code Snippet: Tilt-Based Movement
from microbit import *
player_x, player_y = 0, 0
while True:
x_tilt = accelerometer.get_x()
y_tilt = accelerometer.get_y()
# Move based on tilt (with threshold)
if x_tilt > 300 and player_x < 4:
player_x += 1
elif x_tilt < -300 and player_x > 0:
player_x -= 1
if y_tilt > 300 and player_y < 4:
player_y += 1
elif y_tilt < -300 and player_y > 0:
player_y -= 1
# Draw player
display.clear()
display.set_pixel(player_x, player_y, 9)
sleep(200)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 7: Accelerometer
- micro:bit MicroPython documentation: Accelerometer
Hints in Layers
Hint 1: Start with just the player dot moving on an empty screen. Get tilt controls working first.
Hint 2: Define maze walls as a list of (x, y) coordinates. Check before moving if destination is a wall.
Hint 3: Use different brightness levels: player=9, walls=3, goal=5 (or blink the goal).
Hint 4: Store multiple levels as separate wall lists. Increment level when goal is reached.
Interview Questions
- How would you implement a “dead zone” to prevent accidental movement?
- What data structure would you use to represent a larger maze?
- How could you add a timer or move counter?
- What calibration might be needed for different users?
Project 6: Spirit Level Tool
What You’ll Build
A practical spirit level (bubble level) that shows when a surface is flat. The LED display shows the direction of tilt, with the center lit when level.
Why It Teaches the Concept
This project teaches:
- Mapping continuous sensor values to discrete display states
- Creating useful tools from sensors
- Understanding gravity and orientation
Real World Outcome
Display States:
Perfectly Level: Tilted Left: Tilted Forward:
..... ..... ..X..
..... ..... .....
..X.. X.... .....
..... ..... .....
..... ..... .....
Tilted Far Right: Tilted Back-Right:
..... .....
..... .....
....X .....
..... .....
..... ....X
The dot moves like a bubble in a traditional level.
Sensitivity can be adjusted for precision work.
The Core Question You’re Answering
How can we transform orientation data into an intuitive visual representation?
Code Snippet: Basic Spirit Level
from microbit import *
while True:
x = accelerometer.get_x()
y = accelerometer.get_y()
# Map accelerometer values to display coordinates
# Divide by 400 to reduce sensitivity
display_x = 2 + (x // 400)
display_y = 2 + (y // 400)
# Clamp to valid range
display_x = max(0, min(4, display_x))
display_y = max(0, min(4, display_y))
display.clear()
display.set_pixel(display_x, display_y, 9)
sleep(50)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 7: Accelerometer
Hints in Layers
Hint 1: The accelerometer measures gravity. When tilted, gravity has a horizontal component.
Hint 2: Divide accelerometer values to reduce sensitivity. Values of 400-500 per LED work well.
Hint 3: Add a “level” indication - light up the center brighter when within a tolerance.
Hint 4: For a professional look, add a trail or smoothing to prevent jitter.
Project 7: Digital Compass
What You’ll Build
A compass that points north using the magnetometer. The display shows an arrow pointing toward magnetic north regardless of how you orient the micro:bit.
Why It Teaches the Concept
The magnetometer introduces:
- Calibration requirements for sensors
- Converting heading to visual representation
- Understanding magnetic vs true north
Real World Outcome
Compass Display:
Facing North: Facing East: Facing South: Facing NW:
..X.. ..... ..... X....
..X.. ...XX ..X.. .X...
..X.. ...X. ..X.. ..X..
..... ..... ..X.. .....
..... ..... ..X.. .....
The arrow always points toward magnetic north,
rotating as you turn the micro:bit.
Calibration screen (tilt to fill all LEDs):
XX... XXXXX XXXXX
X.... → XXXX. → XXXXX
..... XX... XXXXX
The Core Question You’re Answering
How do we measure Earth’s magnetic field and convert it to a direction?
Hardware Concepts Explained
Magnetometer Calibration: The magnetometer is affected by nearby magnetic objects (phones, computers, metal). Calibration maps the actual sensor range to 0-360 degrees.
Compass Heading:
0° (North)
▲
│
315° ┌─────────┼─────────┐ 45°
│ │ │
270° ─────│──── micro:bit ───│───── 90°
(West) │ │ (East)
225° └─────────┼─────────┘ 135°
│
▼
180° (South)
compass.heading() returns current heading
relative to magnetic north
Code Snippet: Arrow That Points North
from microbit import *
# Define arrow images for 8 directions
arrows = {
'N': Image("00900:00900:00900:00000:00000"),
'NE': Image("00099:00090:00900:00000:00000"),
'E': Image("00000:00090:00999:00090:00000"),
'SE': Image("00000:00000:00900:00090:00099"),
# ... define all 8 directions
}
compass.calibrate()
while True:
heading = compass.heading()
# Convert heading to direction
if heading < 23 or heading >= 338:
direction = 'N'
elif heading < 68:
direction = 'NE'
# ... handle all directions
display.show(arrows[direction])
sleep(100)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 8: Compass
- micro:bit MicroPython documentation: Compass
Hints in Layers
Hint 1: Start with compass.calibrate() - you must calibrate before readings are useful.
Hint 2: Divide the 360-degree range into 8 sectors of 45 degrees each.
Hint 3: Create 8 arrow images, each rotated 45 degrees from the previous.
Hint 4: Keep the micro:bit away from metal and magnets for accurate readings.
Interview Questions
- Why does a compass need calibration?
- How would you convert magnetic heading to true north?
- What environmental factors affect magnetometer accuracy?
- How would you smooth out jumpy compass readings?
Project 8: Temperature and Light Monitor
What You’ll Build
An environmental monitor that displays temperature and ambient light level. Add logging capability to track changes over time.
Why It Teaches the Concept
Environmental sensing teaches:
- Reading different types of sensors
- Unit conversion (the temperature sensor reads in Celsius)
- Data logging and trends
- Threshold-based alerts
Real World Outcome
Display Modes:
Temperature Mode (Button A):
Shows current temp in °C
┌─────┐
│ 23 │ (scrolls "23C")
└─────┘
Light Level Mode (Button B):
Shows light level 0-255
┌─────┐
│ 156 │ (scrolls "156")
└─────┘
Alert Mode:
If temp > 30°C or light < 10:
┌─────┐
│ !!! │ (warning animation)
└─────┘
Trend Display (optional):
Shows last 5 readings as bar graph
┌─────┐
│ █ │
│ █ █│
│█ █ █│
│█ ███│
│█████│
└─────┘
The Core Question You’re Answering
How do we turn physical environmental conditions into actionable digital data?
Hardware Concepts Explained
Temperature Sensor: The micro:bit’s temperature sensor is actually on the processor. It reads a few degrees higher than ambient due to processor heat.
Light Sensor: The LED display doubles as a light sensor. When not displaying, it measures light falling on the LEDs. Values range from 0 (dark) to 255 (bright).
Sensor Locations:
┌─────────────────────┐
│ LED Matrix │
│ (Light Sensor) │
│ │
│ ┌─────────────┐ │
│ │ Processor │ │
│ │ (Temp │ │
│ │ Sensor) │ │
│ └─────────────┘ │
└─────────────────────┘
Code Snippet: Environment Monitor
from microbit import *
mode = "temp"
while True:
if button_a.was_pressed():
mode = "temp"
if button_b.was_pressed():
mode = "light"
if mode == "temp":
t = temperature()
display.scroll(str(t) + "C")
else:
l = display.read_light_level()
display.scroll(str(l))
sleep(2000) # Wait 2 seconds between readings
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 6: Sensors
- micro:bit MicroPython documentation: Temperature, Display
Hints in Layers
Hint 1: temperature() returns an integer in Celsius. display.read_light_level() returns 0-255.
Hint 2: Store readings in a list to show trends. Keep only the last 5-10 readings.
Hint 3: Create a bar graph by setting pixel brightness proportional to values.
Hint 4: Add sound alerts (V2) when thresholds are crossed.
Project 9: Step Counter / Fitness Tracker
What You’ll Build
A pedometer that counts steps using the accelerometer. It detects the walking motion pattern and keeps a running total.
Why It Teaches the Concept
Motion pattern detection teaches:
- Signal processing basics (detecting patterns in noisy data)
- Threshold-based event detection
- Preventing false positives
- Displaying accumulated data
Real World Outcome
Step Detection Algorithm:
Peak (step detected)
▲
Accelerometer ┌────┴────┐
Value │ │ ┌────┐
│ │ │ │
Threshold ─│─ ─ ─ ─ ─│─ ─ ─ ─ ─│─ ─ ─│─ ─
│ │ │ │
────┘ └─────────┘ └────
Step 1 Step 2
Display:
Walking: Idle: Goal reached:
┌─────┐ ┌─────┐ ┌─────┐
│1,234│ │1,234│ │GOAL!│ + happy face
└─────┘ └─────┘ └─────┘
The Core Question You’re Answering
How do we detect repetitive human motion patterns from raw acceleration data?
Hardware Concepts Explained
Step Detection: Walking produces a characteristic acceleration pattern. Each step causes a spike in Z-axis acceleration (up-down motion). We detect when acceleration crosses a threshold after being below it.
Walking Motion:
Step 1 Step 2 Step 3
┌─┐ ┌─┐ ┌─┐
│ │ │ │ │ │
────┘ └─────────┘ └─────────┘ └────
Each peak represents foot impact.
Typical step frequency: 1-2 Hz (1-2 steps per second)
We need debouncing to prevent double-counting.
Code Snippet: Basic Step Counter
from microbit import *
steps = 0
was_above = False
threshold = 1500
while True:
z = abs(accelerometer.get_z())
# Detect threshold crossing
if z > threshold and not was_above:
steps += 1
was_above = True
elif z < threshold - 200: # Hysteresis
was_above = False
# Show steps on button press
if button_a.was_pressed():
display.scroll(str(steps))
sleep(20)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 7: Accelerometer
Hints in Layers
Hint 1: Walking creates peaks in acceleration. Use accelerometer.get_z() or total magnitude.
Hint 2: Use hysteresis - require the value to drop significantly before counting another step.
Hint 3: Add a minimum time between steps (300-500ms) to prevent false counts.
Hint 4: Test by walking with the micro:bit and calibrating your threshold.
Interview Questions
- What is hysteresis and why is it important for step counting?
- How would you differentiate walking from running?
- What filtering techniques could reduce noise?
- How do commercial fitness trackers achieve better accuracy?
Project 10: Reaction Time Game
What You’ll Build
A game that measures reaction time. The display shows a countdown, then a signal. The player must press a button as fast as possible, and their reaction time is displayed.
Why It Teaches the Concept
Timing and measurement teaches:
- Precise timing with
running_time() - Random number generation
- User interface for games
- Handling edge cases (pressing too early)
Real World Outcome
Game Sequence:
Ready... Wait... GO! Result
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│ 3 │ → │ │ → │XXXXX│ → │ 234 │
│ │ │ ... │ │XXXXX│ │ │
│ │ │ │ │XXXXX│ │ ms │
└─────┘ └─────┘ └─────┘ └─────┘
If pressed during "Wait...": "TOO SOON!"
Record tracking: Best time saved and displayed
Typical Reaction Times:
Excellent: < 200ms
Good: 200-300ms
Average: 300-400ms
Slow: > 400ms
The Core Question You’re Answering
How do we precisely measure time intervals in an embedded system?
Hardware Concepts Explained
running_time(): Returns milliseconds since the micro:bit started. Use two readings to measure elapsed time.
Timing Measurement:
time1 = running_time() # e.g., 5234
↓
[ Event occurs ]
↓
time2 = running_time() # e.g., 5498
↓
elapsed = time2 - time1 # = 264 ms
Code Snippet: Reaction Time Core
from microbit import *
import random
display.scroll("Ready")
sleep(1000)
# Random wait before signal
wait_time = random.randint(1000, 3000)
display.clear()
sleep(wait_time)
# Check if button pressed too early
if button_a.was_pressed():
display.scroll("TOO SOON!")
else:
# Show signal
display.show(Image.YES)
start = running_time()
# Wait for button press
while not button_a.was_pressed():
pass
reaction = running_time() - start
display.scroll(str(reaction) + "ms")
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 4: Buttons
- micro:bit MicroPython documentation: running_time
Hints in Layers
Hint 1: Use random.randint() for variable wait times to prevent anticipation.
Hint 2: Check for early presses using was_pressed() before showing the signal.
Hint 3: Store the best reaction time and compare each round.
Hint 4: Add sound feedback (V2) for start and result.
Project 11: Rock Paper Scissors Game
What You’ll Build
A Rock Paper Scissors game where shaking the micro:bit selects a random choice, and two players can compare using radio.
Why It Teaches the Concept
This combines multiple concepts:
- Gesture detection (shake)
- Random selection
- Radio for multiplayer
- Game logic and state
Real World Outcome
Single Player:
Shake! Result
┌─────┐ ┌─────┐
│ ??? │ → │ ✂ │ (Scissors selected)
└─────┘ └─────┘
Two Player (radio):
Player 1 Player 2
┌─────┐ ┌─────┐
│ ✊ │ ──────► │ ✂ │
│ ROCK │ │SCIS │
│ │ │ │
│ WIN! │ ◄─── │LOSE!│
└─────┘ └─────┘
Symbols:
✊ Rock (solid square)
✋ Paper (full display)
✂ Scissors (X pattern)
The Core Question You’re Answering
How do we combine random selection, gesture input, and wireless communication into a complete game?
Code Snippet: Basic Shake Selection
from microbit import *
import random
rock = Image("09990:09990:09990:00000:00000")
paper = Image("99999:99999:99999:99999:99999")
scissors = Image("90009:09090:00900:09090:90009")
choices = [rock, paper, scissors]
while True:
if accelerometer.was_gesture("shake"):
display.clear()
sleep(200)
choice = random.choice(choices)
display.show(choice)
sleep(50)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 7: Accelerometer
- “Programming the BBC micro:bit” by Simon Monk - Chapter 11: Radio
Hints in Layers
Hint 1: Use was_gesture("shake") to detect shake. Map choices to images.
Hint 2: For two-player, send your choice via radio after selection.
Hint 3: Compare choices: rock beats scissors, scissors beats paper, paper beats rock.
Hint 4: Add a countdown before reveal for dramatic effect.
Project 12: Magic 8 Ball
What You’ll Build
A fortune-telling Magic 8 Ball. Shake the micro:bit to receive a random answer from a pool of mystical responses.
Why It Teaches the Concept
This fun project reinforces:
- Gesture detection
- Random selection from a list
- String display
- Creating engaging user experiences
Real World Outcome
Usage:
1. Ask a question out loud
2. Shake the micro:bit
3. Wait for dramatic pause
4. Read your answer
Answers (examples):
"YES" "NO"
"MAYBE" "ASK AGAIN"
"CERTAINLY" "DOUBTFUL"
"DEFINITELY" "NO WAY"
Display Sequence:
Shake! Thinking... Answer
┌─────┐ ┌─────┐ ┌─────┐
│ ??? │ → │ ... │ → │YES! │
│ │ │ ... │ │ │
└─────┘ └─────┘ └─────┘
The Core Question You’re Answering
How do we create an engaging, randomized experience using simple hardware?
Code Snippet: Magic 8 Ball
from microbit import *
import random
answers = [
"Yes", "No", "Maybe",
"Ask again", "Definitely",
"Doubtful", "Certainly", "No way"
]
while True:
if accelerometer.was_gesture("shake"):
display.show(Image("09090:00000:09090:00000:09090")) # ?
sleep(500)
display.clear()
sleep(500)
answer = random.choice(answers)
display.scroll(answer)
sleep(50)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 7: Accelerometer
Hints in Layers
Hint 1: Create a list of answer strings. Use random.choice() to select one.
Hint 2: Add dramatic pauses with sleep() and mysterious images.
Hint 3: Expand your answer pool for variety - aim for 10-20 responses.
Hint 4: Add categories of answers: positive, negative, neutral.
Project 13: Morse Code Transmitter
What You’ll Build
A Morse code transmitter and receiver using the LED display and buttons, plus radio for communicating with another micro:bit.
Why It Teaches the Concept
Encoding and protocols teach:
- Translating between representations (letters to dots/dashes)
- Timing protocols (dot length, dash length, gaps)
- Building simple communication protocols
- Historical context of digital communication
Real World Outcome
Morse Code Basics:
Dot (.) = short press = short flash
Dash (-) = long press = long flash
Letter gap = pause between letters
Word gap = longer pause between words
Example: "SOS"
S = ... (dot dot dot)
O = --- (dash dash dash)
S = ... (dot dot dot)
Visual:
┌─┐ ┌─┐ ┌─┐ ┌───┐ ┌───┐ ┌───┐ ┌─┐ ┌─┐ ┌─┐
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
└─┘ └─┘ └─┘ └───┘ └───┘ └───┘ └─┘ └─┘ └─┘
S O S
Transmission:
micro:bit A micro:bit B
┌─────────┐ ┌─────────┐
│ Type │ ~~~~~~~ │ Display │
│ message │ ───► │ message │
└─────────┘ └─────────┘
The Core Question You’re Answering
How did early electrical communication encode information, and how does timing convey meaning?
Hardware Concepts Explained
Timing as Data: Morse code uses timing to distinguish dots from dashes. This is a fundamental concept in digital communication - data is encoded in the duration of signals.
Morse Timing Standards:
Dot duration: 1 unit
Dash duration: 3 units
Symbol gap: 1 unit
Letter gap: 3 units
Word gap: 7 units
If 1 unit = 100ms:
Dot = 100ms on
Dash = 300ms on
Gap between symbols = 100ms off
Gap between letters = 300ms off
Gap between words = 700ms off
Code Snippet: Button to Morse
from microbit import *
MORSE = {
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..',
'E': '.', 'F': '..-.', 'G': '--.', 'H': '....',
# ... complete alphabet
'S': '...', 'O': '---'
}
def flash_morse(code):
for symbol in code:
if symbol == '.':
display.show(Image.SQUARE_SMALL)
sleep(100)
else: # dash
display.show(Image.SQUARE)
sleep(300)
display.clear()
sleep(100) # symbol gap
# Example: Flash "SOS"
for letter in "SOS":
flash_morse(MORSE[letter])
sleep(200) # letter gap
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 11: Radio
- Wikipedia: Morse code
Hints in Layers
Hint 1: Create a dictionary mapping letters to Morse strings (dots and dashes).
Hint 2: Measure button press duration: short press = dot, long press = dash.
Hint 3: For radio transmission, send the Morse string and flash on receive.
Hint 4: Add a decoder that translates received Morse back to letters.
Project 14: Simple Calculator
What You’ll Build
A calculator using buttons for number selection and operations. One button cycles through digits, the other confirms selection.
Why It Teaches the Concept
User interface on constrained hardware teaches:
- State machines for multi-step input
- Displaying intermediate results
- Handling multi-digit numbers
- Arithmetic operations
Real World Outcome
Input Method:
Button A: Cycle through 0-9, then +, -, *, /
Button B: Confirm selection
Shake: Calculate result
Example: 5 + 3 = 8
Step 1 Step 2 Step 3
Cycle to 5 Confirm Cycle to +
┌─────┐ ┌─────┐ ┌─────┐
│ 5 │ → │ 5_ │ → │ + │
└─────┘ └─────┘ └─────┘
Press A Press B Press A (cycle)
Step 4 Step 5 Step 6
Confirm + Cycle to 3 Shake!
┌─────┐ ┌─────┐ ┌─────┐
│ 5+_ │ → │ 3 │ → │ 8 │
└─────┘ └─────┘ └─────┘
The Core Question You’re Answering
How do we build complex input interfaces with minimal hardware?
Code Snippet: Digit Selection
from microbit import *
digits = "0123456789+-*/"
current = 0
expression = ""
while True:
if button_a.was_pressed():
current = (current + 1) % len(digits)
display.show(digits[current])
if button_b.was_pressed():
expression += digits[current]
display.scroll("_")
if accelerometer.was_gesture("shake"):
try:
result = eval(expression)
display.scroll(str(result))
expression = ""
except:
display.scroll("ERR")
sleep(50)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 4: Buttons
Hints in Layers
Hint 1: Use a list of characters and an index. Button A increments the index.
Hint 2: Build up an expression string as the user confirms selections.
Hint 3: Use Python’s eval() for calculation (careful: it executes any code!).
Hint 4: Add error handling for invalid expressions.
Project 15: Password Door Lock Simulator
What You’ll Build
A password lock where the correct sequence of button presses unlocks it. Add radio to simulate a door opening signal.
Why It Teaches the Concept
Security and sequences teach:
- State tracking (password progress)
- Comparing sequences
- Timeout handling
- Visual feedback for security interfaces
Real World Outcome
Password Entry:
Password: A-A-B-A (4 presses)
Attempt: Correct Wrong
┌─────┐ ┌─────┐ ┌─────┐
│ * │ │ YES │ │ X │
│ * │ → │ :) │ or │ :( │
│* │ │OPEN │ │LOCK │
└─────┘ └─────┘ └─────┘
Shows * for each button press
Lockout after 3 wrong attempts:
┌─────┐
│WAIT │ (30 second cooldown)
│ 30 │
└─────┘
With Radio:
When unlocked, send "OPEN" signal
Receiving micro:bit shows unlocked icon
The Core Question You’re Answering
How do we implement sequence-based authentication on embedded devices?
Code Snippet: Password Check
from microbit import *
PASSWORD = ["A", "A", "B", "A"]
attempt = []
wrong_count = 0
while True:
if button_a.was_pressed():
attempt.append("A")
display.show("*")
sleep(200)
if button_b.was_pressed():
attempt.append("B")
display.show("*")
sleep(200)
# Check when attempt matches password length
if len(attempt) == len(PASSWORD):
if attempt == PASSWORD:
display.show(Image.YES)
attempt = []
wrong_count = 0
else:
display.show(Image.NO)
attempt = []
wrong_count += 1
if wrong_count >= 3:
display.scroll("LOCKED")
sleep(30000)
wrong_count = 0
sleep(1000)
display.clear()
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 4: Buttons
- “Programming the BBC micro:bit” by Simon Monk - Chapter 11: Radio
Hints in Layers
Hint 1: Store the password as a list. Build up the attempt list with each button press.
Hint 2: Compare lists when the attempt length matches password length.
Hint 3: Add a timeout - reset the attempt if no button pressed for 5 seconds.
Hint 4: Use radio to send unlock signal to a second micro:bit.
Project 16: Plant Watering Monitor
What You’ll Build
A soil moisture monitor using the light sensor as a basic moisture indicator (or external sensor), with alerts when plants need water.
Why It Teaches the Concept
Environmental monitoring teaches:
- Threshold-based alerts
- Data logging over time
- Creating practical IoT devices
- Sensor calibration
Real World Outcome
Monitoring Display:
Moist (good): Dry (needs water): Very dry:
┌─────┐ ┌─────┐ ┌─────┐
│ :) │ │ :/ │ │ :( │
│ │ │WATER│ │ !!!│
└─────┘ └─────┘ └─────┘
With Bar Graph (moisture level):
Full: Med: Low: Empty:
█████ ███ █
█████ ███ █
█████ ███ █
█████ ███
█████
Data Logging:
Press A to see trend:
"Last 5: 90 85 70 60 55"
The Core Question You’re Answering
How do we create automated monitoring systems that alert us to changing conditions?
Hardware Concepts Explained
Moisture Sensing Options:
- Light sensor method: Cover with dark material; wet soil reflects less light
- Resistance method: Use two pins stuck in soil (with external components)
- External sensor: Connect a proper moisture sensor to edge connector
Simple Setup (light sensor based):
┌─────────────┐
│ micro:bit │
│ ┌───────┐ │
│ │ LEDs │◄─┼──── Cover with dark cap
│ │(sensor)│ │ pointing at soil
│ └───────┘ │
└─────┬───────┘
│
▼ Light from soil
┌─────────────┐
│ Soil │
└─────────────┘
Wet soil = darker = lower reading
Dry soil = lighter = higher reading
Code Snippet: Moisture Monitor
from microbit import *
DRY_THRESHOLD = 100
VERY_DRY = 50
while True:
moisture = display.read_light_level()
if moisture > DRY_THRESHOLD:
display.show(Image.HAPPY)
elif moisture > VERY_DRY:
display.show(Image.MEH)
else:
display.show(Image.SAD)
# Flash warning
for _ in range(3):
display.show(Image.SAD)
sleep(200)
display.clear()
sleep(200)
sleep(5000) # Check every 5 seconds
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 6: Sensors
Hints in Layers
Hint 1: Use display.read_light_level() as a simple proxy for moisture.
Hint 2: Calibrate by taking readings from wet and dry soil.
Hint 3: Store readings in a list and calculate averages or trends.
Hint 4: Add radio alerts to a second micro:bit when watering is needed.
Project 17: Mini Piano / Musical Instrument
What You’ll Build
A musical instrument using buttons and touch pins (V2) to play notes. Create melodies, add different octaves, and experiment with sound generation.
Why It Teaches the Concept
Sound generation teaches:
- Audio fundamentals (frequency = pitch)
- User interface for musical expression
- Using edge connector pins
- Combining multiple inputs
Real World Outcome
Piano Layout (using edge pins):
Edge Pins: 0 1 2
│ │ │
▼ ▼ ▼
Notes: Do Re Mi
Buttons:
A = Lower octave
B = Higher octave
Touch pins + buttons = 6 notes
Playing a tune:
┌────────────────────────────────┐
│ Touch pins in sequence: │
│ 0-0-1-2-2-1-0 = "Mary had..." │
└────────────────────────────────┘
Visual Feedback:
When playing note:
┌─────┐
│ ♪ │ + Note name scrolls
└─────┘
The Core Question You’re Answering
How do we generate and control sound using a microcontroller?
Hardware Concepts Explained
Sound Frequency: Musical notes are specific frequencies. Middle C is 262 Hz, meaning the speaker vibrates 262 times per second.
Musical Notes and Frequencies:
Note Freq(Hz) MicroPython
──────────────────────────────
C4 262 music.pitch(262)
D4 294
E4 330
F4 349
G4 392
A4 440 (Tuning standard)
B4 494
C5 523 (Octave higher)
Octave = doubling frequency
A4 (440 Hz) → A5 (880 Hz)
Code Snippet: Touch Piano (V2)
from microbit import *
import music
NOTES = [262, 294, 330, 349, 392, 440, 494] # C D E F G A B
NOTE_NAMES = "CDEFGAB"
while True:
if pin0.is_touched():
music.pitch(NOTES[0], 200)
display.show(NOTE_NAMES[0])
elif pin1.is_touched():
music.pitch(NOTES[1], 200)
display.show(NOTE_NAMES[1])
elif pin2.is_touched():
music.pitch(NOTES[2], 200)
display.show(NOTE_NAMES[2])
elif button_a.is_pressed():
music.pitch(NOTES[3], 200)
display.show(NOTE_NAMES[3])
elif button_b.is_pressed():
music.pitch(NOTES[4], 200)
display.show(NOTE_NAMES[4])
else:
display.clear()
sleep(50)
References
- “Programming the BBC micro:bit” by Simon Monk - Chapter 9: Sound
- micro:bit MicroPython documentation: Music
Hints in Layers
Hint 1: Use music.pitch(frequency, duration) to play a tone.
Hint 2: Touch pins work by detecting capacitance - touch with fingertip.
Hint 3: Pre-define note frequencies in a list for easy selection.
Hint 4: Add recording: store touched pins in a list, then play back the sequence.
Bonus Projects
Project 18: Dice Roller
Create a dice that shows 1-6 when shaken. Add multiple dice modes and custom dice (D20 for games).
Project 19: Tamagotchi Pet
A virtual pet that gets hungry, sleepy, and wants to play. Use buttons to feed, put to sleep, and play. Track happiness over time.
Project 20: Countdown Timer
An egg timer with adjustable duration. Button A adds time, Button B starts countdown, shake to cancel.
Project Comparison Table
| # | Project | Difficulty | Time | Key Concepts | Fun Factor |
|---|---|---|---|---|---|
| 1 | LED Patterns | Easy | 1hr | Display, Images | High |
| 2 | Advanced Animations | Medium | 2hr | State, Algorithms | High |
| 3 | Radio Messenger | Medium | 2hr | Radio, Protocol | High |
| 4 | Button Counter | Easy | 1hr | Input, State | Medium |
| 5 | Tilt Maze | Medium | 3hr | Accelerometer, Game | High |
| 6 | Spirit Level | Easy | 1hr | Accelerometer, Tool | Medium |
| 7 | Digital Compass | Medium | 2hr | Magnetometer, Calibration | Medium |
| 8 | Temp/Light Monitor | Easy | 1hr | Sensors, Display | Medium |
| 9 | Step Counter | Hard | 3hr | Signal Processing | High |
| 10 | Reaction Game | Easy | 1hr | Timing, Random | High |
| 11 | Rock Paper Scissors | Medium | 2hr | Gesture, Radio | High |
| 12 | Magic 8 Ball | Easy | 1hr | Random, Fun | High |
| 13 | Morse Code | Hard | 4hr | Encoding, Protocol | Medium |
| 14 | Calculator | Hard | 3hr | UI, State Machine | Medium |
| 15 | Password Lock | Medium | 2hr | Security, Sequence | Medium |
| 16 | Plant Monitor | Medium | 2hr | Sensing, Alerts | High |
| 17 | Mini Piano | Medium | 2hr | Sound, Touch | High |
Recommended Reading
Primary Text
“Programming the BBC micro:bit” by Simon Monk
- The definitive guide to micro:bit programming
- Covers MicroPython and MakeCode
- Excellent for beginners with clear explanations
| Chapter | Relevance to Projects |
|---|---|
| Ch 1: Introduction | Setup and basics |
| Ch 3: LED Display | Projects 1, 2, 12 |
| Ch 4: Buttons | Projects 4, 10, 14, 15 |
| Ch 6: Sensors | Projects 8, 16 |
| Ch 7: Accelerometer | Projects 5, 6, 9, 11 |
| Ch 8: Compass | Project 7 |
| Ch 9: Sound | Projects 13, 17 |
| Ch 11: Radio | Projects 3, 11, 15 |
Additional Resources
Online Documentation:
- micro:bit MicroPython: https://microbit-micropython.readthedocs.io/
- micro:bit Foundation: https://microbit.org/
Video Courses:
- YouTube: “micro:bit for beginners” (official channel)
- Coursera: “Programming micro:bit” (various)
Common Questions (FAQ)
Q: Which micro:bit version should I get? A: V2 is recommended. It has a speaker, microphone, touch logo, and more memory. V1 works for most projects but lacks sound output without external components.
Q: Can I use these projects with Blocks/JavaScript instead of Python? A: Yes! All concepts transfer. The block editor is great for beginners, then transition to Python for more power.
Q: My micro:bit isn’t detected by my computer. A: Check that you have a data USB cable (not charge-only). Try different USB ports. On Windows, it should appear as a drive called “MICROBIT”.
Q: How do I save programs permanently? A: Programs are stored in flash memory and persist after power off. To run, just power on the micro:bit.
Q: Can I connect external components? A: Yes! Use the edge connector with crocodile clips or an edge connector breakout board. Be careful with voltage levels (3.3V).
What’s Next After micro:bit?
Once you’ve completed these projects, you have solid foundations for:
More Advanced Boards:
- Raspberry Pi Pico (more power, same accessibility)
- Arduino (huge ecosystem, more C-like)
- ESP32 (Wi-Fi built in, more complex)
Professional Skills:
- Embedded C programming
- RTOS concepts
- PCB design
- Sensor interfacing
Career Paths:
- IoT Developer
- Embedded Systems Engineer
- Product Designer (prototyping)
- Educational Technology
Summary
The BBC micro:bit is a remarkable learning platform that packs sensors, display, buttons, and wireless communication into a pocket-sized package. Through these 17+ projects, you’ve learned:
- Display Control - Turning code into visible output
- Input Handling - Reading buttons, touch, and gestures
- Sensor Integration - Measuring the physical world
- Wireless Communication - Connecting devices without wires
- Sound Generation - Creating audio output
- Game Development - Building interactive experiences
- Practical Tools - Creating useful devices
Most importantly, you’ve learned that hardware programming is accessible, fun, and deeply rewarding. The skills you’ve developed here form the foundation for professional embedded development, IoT engineering, and physical computing.
Now go build something amazing!
Last updated: January 2025 Total projects: 20 | Estimated completion: 40-80 hours | Difficulty: Beginner to Intermediate