Contents
Intro
The Tangible Interfaces Class introduces interaction design using the BBC Microbit device and common sensors (see hardware). These code samples are meant to demonstrate functionality to help you get started exploring hardware interaction.
We code in JavaScript as it is a very common programming language. The Blocks style of coding has, in my experience, been more confusing than helpful. JavaScript programs are text, so it is easy to add // comments to explain the code. AI tools are very familiar with JavaScript, and can help to fix bugs or suggest features.
The Microbit is easy to program, no software needs to be installed. Connect the board to your computer with a USB cable and go to https://makecode.microbit.org for tutorials. You will be able to connect the board and program it from the webpage. It is possible to program the Microbit from the phone or tablet app, but it is harder.
Built-in Code Examples
These programs work with the microbit alone, no wiring or components needed.
Microbit Button
The simplest Microbit program: The LEDs show a number. Button B increases the number, Button A reduces the number.
// @ts-nocheck
// The simplest Microbit program: shows a number on the 25 LEDs.
// Button B increases the value, Button A decreases the value.
// No external wiring needed — just the micro:bit itself.
// --- Setup ---
let value = 0;
basic.showNumber(value);
// --- Button Handlers ---
input.onButtonPressed(Button.B, function () {
value += 1;
basic.showNumber(value);
});
input.onButtonPressed(Button.A, function () {
value -= 1;
basic.showNumber(value);
});Compass
Reads the micro:bit’s built-in compass and displays an arrow on the LED screen pointing in the compass direction.
// @ts-nocheck
// Reads the micro:bit's built-in compass and displays an arrow on the LED screen
// pointing in the compass direction (N, NE, E, SE, S, SW, W, NW).
// --- Setup ---
let angle = 0;
basic.showIcon(IconNames.Triangle);
input.calibrateCompass();
// --- Main Loop ---
basic.forever(function () {
angle = input.compassHeading();
if ((angle >= 0 && angle < 45) || angle >= 360) {
basic.showArrow(ArrowNames.North);
} else if (angle >= 45 && angle < 90) {
basic.showArrow(ArrowNames.NorthWest);
} else if (angle >= 90 && angle < 135) {
basic.showArrow(ArrowNames.West);
} else if (angle >= 135 && angle < 180) {
basic.showArrow(ArrowNames.SouthWest);
} else if (angle >= 180 && angle < 225) {
basic.showArrow(ArrowNames.South);
} else if (angle >= 225 && angle < 270) {
basic.showArrow(ArrowNames.SouthEast);
} else if (angle >= 270 && angle < 315) {
basic.showArrow(ArrowNames.East);
} else if (angle >= 315 && angle < 360) {
basic.showArrow(ArrowNames.NorthEast);
} else {
}
serial.writeValue("x", angle);
basic.pause(100);
});Accelerometer Tilt Game
Tilt-to-navigate game: tilt the micro:bit to move a bright dot toward a dimmer target dot on the 5x5 LED grid. Press button A when you reach it to check.
// @ts-nocheck
// Tilt-to-navigate game: tilt the micro:bit to move a bright dot toward a dimmer
// target dot on the 5x5 LED grid. Press button A when you reach it to check.
// --- Setup ---
let goal: game.LedSprite = null;
let player: game.LedSprite = null;
serial.redirectToUSB();
music.play(music.tonePlayable(262, music.beat(BeatFraction.Sixteenth)), music.PlaybackMode.UntilDone);
player = game.createSprite(0, 0);
goal = game.createSprite(2, 2);
// --- Main Loop ---
basic.forever(function () {
basic.clearScreen();
if (input.acceleration(Dimension.X) > 500) {
player.change(LedSpriteProperty.X, 1);
} else if (input.acceleration(Dimension.X) < -500) {
player.change(LedSpriteProperty.X, -1);
}
if (input.acceleration(Dimension.Y) > 500) {
player.change(LedSpriteProperty.Y, 1);
} else if (input.acceleration(Dimension.Y) < -500) {
player.change(LedSpriteProperty.Y, -1);
}
led.plotBrightness(player.get(LedSpriteProperty.X), player.get(LedSpriteProperty.Y), 255);
led.plotBrightness(goal.get(LedSpriteProperty.X), goal.get(LedSpriteProperty.Y), 119);
serial.writeLine("X" + input.acceleration(Dimension.X) + " " + "Y" + input.acceleration(Dimension.Y) + " " + "Z" + input.acceleration(Dimension.Z));
basic.pause(100);
});
// --- Event Handlers ---
// Runs when button A is pressed to check if player reached the goal
input.onButtonPressed(Button.A, function () {
if (player.get(LedSpriteProperty.X) == goal.get(LedSpriteProperty.X) && player.get(LedSpriteProperty.Y) == goal.get(LedSpriteProperty.Y)) {
serial.writeString("WON");
music.play(music.stringPlayable("C5 B A G F E D C ", 120), music.PlaybackMode.UntilDone);
basic.pause(1000);
} else {
music.play(music.tonePlayable(131, music.beat(BeatFraction.Sixteenth)), music.PlaybackMode.UntilDone);
basic.clearScreen();
basic.pause(1000);
}
});Simple Digital Input
Digital input is a yes/no or on/off measurement.
Simple External Button
Reads an external push button — the simplest possible digital sensor, just on or off. Use this pattern any time you want a physical button separate from the micro:bit’s built-in A and B buttons.
// @ts-nocheck
// Reads an external push button and shows its state on the LED screen.
// This is the simplest possible digital sensor — just on or off.
// Use this pattern any time you want a physical button that is separate
// from the micro:bit's built-in A and B buttons.
//
// Digital read: 1 = button pressed, 0 = button released.
//
// Physical setup:
// Button module has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// --- Setup ---
let buttonState = 0;
basic.showIcon(IconNames.SmallDiamond);
// --- Main Loop ---
basic.forever(function () {
buttonState = pins.digitalReadPin(DigitalPin.P0);
if (buttonState == 1) {
basic.showIcon(IconNames.Diamond);
serial.writeLine("Button pressed");
} else {
basic.showIcon(IconNames.SmallDiamond);
serial.writeLine("Button released");
}
basic.pause(100);
});Motion Sensor
Detects human movement using a PIR (passive infrared) sensor — it senses body heat moving in front of it. When motion is detected, the LED screen shows an eye icon and plays a tone. Wiring: signal → P0, VCC → 3V, GND → GND.
// @ts-nocheck
// Detects human movement using a PIR (passive infrared) motion sensor.
// When motion is detected, the LED screen shows an eye icon and plays a sound.
//
// How it works: the sensor detects body heat moving in front of it.
// Digital read: 1 = motion detected, 0 = no motion.
// The sensor has a ~2 second warm-up time when first powered on.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// --- Setup ---
let motionDetected = 0;
basic.showIcon(IconNames.Asleep);
// --- Main Loop ---
basic.forever(function () {
motionDetected = pins.digitalReadPin(DigitalPin.P0);
if (motionDetected == 1) {
basic.showIcon(IconNames.Happy);
music.play(music.tonePlayable(988, music.beat(BeatFraction.Quarter)), music.PlaybackMode.InBackground);
serial.writeLine("Motion detected!");
} else {
basic.showIcon(IconNames.Asleep);
serial.writeLine("No motion");
}
basic.pause(200);
});Capacitive Touch
Detects touch using a capacitive sensor — no mechanical button needed. Any conductive surface (metal, fruit, foil, water) can become a touch input. Wiring: signal → P0, VCC → 3V, GND → GND.
// @ts-nocheck
// Detects touch using a capacitive touch sensor — no mechanical button needed.
// Any conductive surface (metal, fruit, foil, water, skin) can become a touch input.
// Touching the sensor pad lights up the LED screen and plays a tone.
//
// Digital read: 1 = touched, 0 = not touched.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// You can attach a wire to the sensor pad to extend the touch area.
// --- Setup ---
let isTouched = 0;
basic.showIcon(IconNames.Heart);
// --- Main Loop ---
basic.forever(function () {
isTouched = pins.digitalReadPin(DigitalPin.P0);
if (isTouched == 1) {
basic.showIcon(IconNames.Diamond);
music.play(
music.tonePlayable(523, music.beat(BeatFraction.Eighth)),
music.PlaybackMode.InBackground,
);
serial.writeLine("Touched!");
} else {
basic.showIcon(IconNames.SmallDiamond);
serial.writeLine("Not touched");
}
basic.pause(100);
});Hall Magnetic Sensor
Detects a nearby magnet using a Hall effect sensor. Magnets can be hidden inside objects, behind walls, or under surfaces to create invisible triggers — this simple sensor is used everywhere in devices, cars, and homes. Wiring: signal → P0, VCC → 3V, GND → GND.
// @ts-nocheck
// Detects a nearby magnet using a Hall effect magnetic sensor.
// Magnets can be hidden inside objects, behind walls, or under surfaces
// to create invisible triggers — no visible button or switch needed.
//
// Digital read: 1 = magnet detected (within ~3cm), 0 = no magnet.
// Try taping a small magnet to a game piece, box lid, or sliding panel.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Hold a magnet close to the sensor face to trigger it.
// --- Setup ---
let magnetDetected = 0;
basic.showIcon(IconNames.No);
// --- Main Loop ---
basic.forever(function () {
magnetDetected = pins.digitalReadPin(DigitalPin.P0);
if (magnetDetected == 1) {
basic.showIcon(IconNames.Yes);
music.play(
music.tonePlayable(784, music.beat(BeatFraction.Eighth)),
music.PlaybackMode.InBackground,
);
serial.writeLine("Magnet detected!");
} else {
basic.showIcon(IconNames.No);
serial.writeLine("No magnet");
}
basic.pause(100);
});Simple Output
Servo simple
Sweeps a servo motor back and forth from 0 to 180 degrees continuously.
// @ts-nocheck
// Sweeps a servo motor back and forth from 0 to 180 degrees continuously.
// A basic demo of servo movement on pin P0.
// --- Setup ---
servos.P0.setRange(0, 180);
basic.showIcon(IconNames.Heart);
let direction = 1;
let angle = 0;
// --- Main Loop ---
basic.forever(function () {
if (angle > 180 || angle < 0) {
direction = direction * -1;
}
angle += direction;
servos.P0.setAngle(angle);
serial.writeValue("angle", angle);
});Fan Module
Controls an L9110 fan module for physical, tactile output — you can feel the wind on your skin. Button A turns the fan on, Button B turns it off. Wiring: INA → P0, INB → P1, VCC → 5V (use battery pack), GND → GND.
// @ts-nocheck
// Controls an L9110 fan module — a small motor with a propeller that blows air.
// Most outputs are visual (LEDs) or audible (buzzer). A fan gives physical,
// tactile feedback — you can FEEL the output on your skin.
//
// Button A turns the fan on, Button B turns it off.
//
// Physical setup:
// Fan module has 4 pins: INA, INB, VCC, GND.
// Connect INA → micro:bit pin 0
// Connect INB → micro:bit pin 1
// Connect VCC → battery pack positive (5V recommended, 3V may be too weak)
// Connect GND → micro:bit GND (and battery pack negative)
// Important: use the 6xAA battery pack for enough power to spin the fan.
// --- Setup ---
let fanOn = false;
basic.showIcon(IconNames.Target);
// Make sure fan starts off
pins.digitalWritePin(DigitalPin.P0, 0);
pins.digitalWritePin(DigitalPin.P1, 0);
// --- Event Handlers ---
// Button A: turn fan on
input.onButtonPressed(Button.A, function () {
fanOn = true;
pins.digitalWritePin(DigitalPin.P0, 1);
pins.digitalWritePin(DigitalPin.P1, 0);
basic.showIcon(IconNames.SmallSquare);
serial.writeLine("Fan ON");
});
// Button B: turn fan off
input.onButtonPressed(Button.B, function () {
fanOn = false;
pins.digitalWritePin(DigitalPin.P0, 0);
pins.digitalWritePin(DigitalPin.P1, 0);
basic.showIcon(IconNames.Target);
serial.writeLine("Fan OFF");
});Relay Module
Controls a relay — an electrically operated switch that lets your micro:bit turn real-world devices on and off (lamps, fans, motors). You’ll hear a satisfying “click” when it switches. Button A = on, Button B = off.
// @ts-nocheck
// Controls a relay module — an electrically operated switch that can turn
// real-world devices on and off. You'll hear a satisfying "click" when it switches.
// A relay lets your micro:bit control things like lamps, fans, or motors
// that need more power than the micro:bit can provide directly.
//
// Button A turns the relay on (click!), Button B turns it off.
// Digital write: 1 = relay ON (closed circuit), 0 = relay OFF (open circuit).
//
// Physical setup:
// Relay module has 3 low-voltage pins: S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
//
// The relay also has screw terminals for the high-voltage side:
// COM (common), NO (normally open), NC (normally closed).
// For basic testing, just listen for the click — no need to wire the screw terminals.
// To control a device: wire it through COM and NO so it turns on when the relay activates.
// --- Setup ---
let relayOn = false;
basic.showIcon(IconNames.Target);
pins.digitalWritePin(DigitalPin.P0, 0);
// --- Event Handlers ---
// Button A: turn relay on
input.onButtonPressed(Button.A, function () {
relayOn = true;
pins.digitalWritePin(DigitalPin.P0, 1);
basic.showIcon(IconNames.Yes);
serial.writeLine("Relay ON");
});
// Button B: turn relay off
input.onButtonPressed(Button.B, function () {
relayOn = false;
pins.digitalWritePin(DigitalPin.P0, 0);
basic.showIcon(IconNames.No);
serial.writeLine("Relay OFF");
});Analog Sensors
Basic Analog sensor
Reads an analog sensor on pin P0 and displays the value as a bar graph on the LED screen. An example sensor is the “potentiometer” (a rotating variable resistor) that changes the voltage that the microbit sees.
// @ts-nocheck
// Reads an analog sensor on pin P0 and displays the value as a bar graph
// on the LED screen. Logs the raw value and percentage over serial.
// --- Setup ---
let AnalogReading = 0;
basic.showIcon(IconNames.Yes);
// --- Main Loop ---
basic.forever(function () {
AnalogReading = pins.analogReadPin(AnalogPin.P0);
led.plotBarGraph(AnalogReading, 1023);
serial.writeLine("Analog Reading" + AnalogReading + "|" + Math.map(AnalogReading, 0, 1023, 0, 99) + "%");
});Pressure/Force Sensor
Reads a thin-film pressure sensor and shows how hard you’re pressing as a bar graph. Unlike a button (on/off), this sensor gives an analog value — it knows HOW MUCH force is applied. Wiring: signal → P0, VCC → 3V, GND → GND.
// @ts-nocheck
// Reads a thin-film pressure (force) sensor and displays how hard you're pressing.
// Unlike a button (on/off), this sensor gives an analog value — it knows HOW MUCH
// force is applied. Squeeze harder = higher reading.
//
// Use cases: squeeze toys, sit-on sensors, footstep detection, grip strength.
// Analog read: 0 = no pressure, up to 1023 = maximum force.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Press the round film area with your finger to see values change.
// --- Setup ---
let forceReading = 0;
basic.showIcon(IconNames.SmallHeart);
// --- Main Loop ---
basic.forever(function () {
forceReading = pins.analogReadPin(AnalogPin.P0);
led.plotBarGraph(forceReading, 1023);
serial.writeValue("force", forceReading);
serial.writeValue("percent", Math.round(Math.map(forceReading, 0, 1023, 0, 100)));
basic.pause(100);
});Joystick Input
Reads an analog joystick and displays position as a dot on the LED screen. Pressing the joystick button plays a sound.
The joystick is actually simply 2 rotating variable resistors
// @ts-nocheck
// Reads an analog joystick and displays position as a dot on the LED screen.
// Pressing the joystick button plays a sound. Uses a KEYESTUDIO analog joystick.
//
// Wiring: Y direction → pin 0, X direction → pin 1, Switch → pin 2
// MAP scales the 0-1023 input to 0-4 (pixel positions on the LED grid)
// ROUND converts to whole numbers for LED coordinates
// Digital read pin 2: 1 = button clicked
// --- Setup ---
let Y = 0;
let X = 0;
serial.redirectToUSB();
basic.showIcon(IconNames.Chessboard);
music.play(music.tonePlayable(262, music.beat(BeatFraction.Sixteenth)), music.PlaybackMode.UntilDone);
// --- Main Loop ---
basic.forever(function () {
basic.clearScreen();
X = Math.round(Math.map(pins.analogReadPin(AnalogReadWritePin.P1), 0, 1023, 4, 0));
Y = Math.round(Math.map(pins.analogReadPin(AnalogReadWritePin.P0), 0, 1023, 0, 4));
if (pins.digitalReadPin(DigitalPin.P2) == 1) {
music.play(
music.createSoundExpression(WaveShape.Sine, 5000, 0, 255, 0, 500, SoundExpressionEffect.None, InterpolationCurve.Linear),
music.PlaybackMode.InBackground,
);
basic.showIcon(IconNames.SmallDiamond);
} else {
led.plotBrightness(X, Y, 255);
}
basic.pause(100);
serial.writeNumbers([X, Y, 0]);
});Ultraviolet Sensor
Reads a GUVA-S12SD UV sensor and estimates the UV index (0-11). When should you reapply sunscreen? Great for wearable or outdoor projects.
// @ts-nocheck
// Reads a GUVA-S12SD ultraviolet (UV) sensor and estimates the UV index.
// UV index 0-2 is low, 3-5 moderate, 6-7 high, 8-10 very high, 11+ extreme.
// Great for wearable projects: when should you reapply sunscreen?
//
// Analog read: the sensor outputs a voltage proportional to UV intensity.
// We map the 0-1023 reading to an approximate UV index of 0-11.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Point the sensor window toward the sky or a UV light source.
// --- Setup ---
let uvReading = 0;
let uvIndex = 0;
basic.showString("UV");
// --- Main Loop ---
basic.forever(function () {
uvReading = pins.analogReadPin(AnalogPin.P0);
// Map sensor range to approximate UV index (0-11)
uvIndex = Math.round(Math.map(uvReading, 0, 1023, 0, 11));
// Show the UV index number on the LED screen
basic.showNumber(uvIndex);
serial.writeValue("raw", uvReading);
serial.writeValue("uvIndex", uvIndex);
basic.pause(1000);
});Analog Gas Sensor
Reads an MQ-2 gas sensor that detects flammable gases and smoke. The bar graph gets taller as gas concentration increases. The sensor needs 5V and about 20 seconds to warm up.
// @ts-nocheck
// Reads an analog gas sensor (MQ-2) that detects flammable gases and smoke.
// The bar graph gets taller as gas concentration increases.
// Useful for safety projects or environmental monitoring.
//
// Analog read: 0 = clean air, higher values = more gas detected.
// The sensor needs about 20 seconds to warm up before readings stabilize.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 5V (use battery pack — this sensor needs 5V)
// Connect G → micro:bit GND
// Important: the sensor has a small heater inside and gets warm. This is normal.
// --- Setup ---
let gasReading = 0;
basic.showString("GAS");
// Give sensor time to warm up
basic.pause(3000);
basic.showIcon(IconNames.SmallHeart);
// --- Main Loop ---
basic.forever(function () {
gasReading = pins.analogReadPin(AnalogPin.P0);
led.plotBarGraph(gasReading, 1023);
serial.writeValue("gas", gasReading);
basic.pause(500);
});Analog Alcohol Sensor
Reads an MQ-3 alcohol sensor that detects alcohol vapor in the air. Try holding hand sanitizer near the sensor. Needs 5V and about 20 seconds to warm up.
// @ts-nocheck
// Reads an analog alcohol sensor (MQ-3) that detects alcohol vapor in the air.
// The bar graph gets taller as alcohol concentration increases.
// Try holding hand sanitizer or rubbing alcohol near the sensor.
//
// Analog read: 0 = clean air, higher values = more alcohol vapor detected.
// The sensor needs about 20 seconds to warm up before readings stabilize.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 5V (use battery pack — this sensor needs 5V)
// Connect G → micro:bit GND
// Important: the sensor has a small heater inside and gets warm. This is normal.
// --- Setup ---
let alcoholReading = 0;
basic.showString("ALC");
// Give sensor time to warm up
basic.pause(3000);
basic.showIcon(IconNames.SmallHeart);
// --- Main Loop ---
basic.forever(function () {
alcoholReading = pins.analogReadPin(AnalogPin.P0);
led.plotBarGraph(alcoholReading, 1023);
serial.writeValue("alcohol", alcoholReading);
basic.pause(500);
});Sensors and Displays Requiring Extensions
Ultrasonic Distance Sensor
Reads an ultrasonic distance sensor (HC-SR04) and displays the distance as a bar graph on the LED screen. In the microbit code editor, open “extensions”, search for ‘Sonar’ and add. Example project Example video
// @ts-nocheck
// Reads an ultrasonic distance sensor (HC-SR04) and displays the distance
// as a bar graph on the LED screen. Also logs distance values over serial.
// --- Setup ---
let DistanceInCM = 0;
led.enable(true);
// --- Main Loop ---
basic.forever(function () {
DistanceInCM = sonar.ping(DigitalPin.P0, DigitalPin.P1, PingUnit.Centimeters);
led.plotBarGraph(DistanceInCM, 40);
serial.writeLine("DistanceInCM=" + DistanceInCM);
});Temperature And Humidity Sensor
Reads temperature and humidity from a DHT11 sensor — one sensor, two readings. The core of every smart thermostat or weather station. Requires the “DHT11_DHT22” MakeCode extension (search “DHT11” in Extensions).
// @ts-nocheck
// Reads temperature and humidity from a DHT11 sensor and shows them on the LED screen.
// One sensor gives you two readings — the core of every smart thermostat or weather station.
// Alternates between showing temperature (C) and humidity (%).
//
// Note: this program requires a MakeCode extension.
// In the MakeCode editor, click "Extensions" and search for "DHT11".
// Add the "DHT11_DHT22" extension by Alan Krantas.
//
// Physical setup:
// Sensor has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Important: wait at least 1 second between readings (the sensor is slow).
// --- Setup ---
let temperature = 0;
let humidity = 0;
basic.showString("DHT");
// --- Main Loop ---
basic.forever(function () {
// Read the sensor (must call this before reading temperature or humidity)
dht11_dht22.queryData(DHTtype.DHT11, DigitalPin.P0, true, false, true);
// Get the readings
temperature = dht11_dht22.readData(dataType.temperature);
humidity = dht11_dht22.readData(dataType.humidity);
// Show temperature
basic.showString("T");
basic.showNumber(temperature);
basic.pause(1000);
// Show humidity
basic.showString("H");
basic.showNumber(humidity);
basic.pause(1000);
// Log to serial
serial.writeValue("tempC", temperature);
serial.writeValue("humidity", humidity);
});Rotary encoder
Demonstrates a KY-040 rotary encoder: twist to change a value shown as a bar graph, press the button to reset. Requires the RotaryEncoder extension.
// @ts-nocheck
// Demonstrates a KY-040 rotary encoder: twist to change a value shown as a bar
// graph on the LED screen, press the button to reset. Requires the RotaryEncoder extension.
// --- Setup ---
let count = 0;
count = 50;
basic.showIcon(IconNames.SmallHeart);
RotaryEncoder.init(DigitalPin.P2, DigitalPin.P1, DigitalPin.P0);
led.plotBarGraph(50, 100);
// --- Event Handlers ---
// Runs when encoder is rotated left (counter-clockwise)
RotaryEncoder.onRotateEvent(RotationDirection.Left, function () {
count += 5;
serial.writeValue("count", count);
led.plotBarGraph(count, 100);
});
// Runs when encoder is rotated right (clockwise)
RotaryEncoder.onRotateEvent(RotationDirection.Right, function () {
count += -5;
serial.writeValue("count", count);
led.plotBarGraph(count, 100);
});
// Runs when encoder button is pressed
RotaryEncoder.onPressEvent(function () {
basic.showIcon(IconNames.Yes);
count = 50;
basic.pause(1000);
led.plotBarGraph(count, 100);
});IR Remote Reader
Reads button presses from the included IR remote (or any IR remote — try your TV remote). Point a remote at the IR receiver and the micro:bit shows which button code was received. Requires the “MakerBit IR Receiver” MakeCode extension (search “makerbit-ir” in Extensions).
// @ts-nocheck
// Reads button presses from the included IR remote control (or any IR remote).
// Point any remote at the IR receiver and press buttons — the micro:bit shows
// which button was pressed. Use this to decode your TV or AC remote's signals.
//
// MakeCode extension required:
// In the MakeCode editor, click "Extensions" and search for "makerbit-ir".
// Add the "MakerBit IR Receiver" extension by 1010Technologies.
//
// Physical setup:
// IR receiver module has 3 pins labeled S (signal), V (power), G (ground).
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Point the IR remote directly at the receiver module (line of sight).
// --- Setup ---
// Connect IR receiver on pin 0 using Keyestudio protocol
makerbit.connectIrReceiver(DigitalPin.P0, IrProtocol.Keyestudio);
basic.showIcon(IconNames.SmallDiamond);
// --- Event Handlers ---
// This runs every time any IR button is pressed.
// The IR remote sends a 32-bit datagram (address + command + error-check bytes).
// irDatagram() returns the full 32-bit hex code as a string like "0x00FF02FD".
// Copy the hex value from the serial monitor and paste it into ir_control_devices.ts
// (remove the "0x" prefix, e.g. "0x00FF02FD" becomes "00FF02FD").
//
// Common codes for the included Keyestudio remote:
// Power=0xFF02FD, Vol+=0xFF18E7, Vol-=0xFF4AB5
makerbit.onIrDatagram(function () {
let hex = makerbit.irDatagram();
basic.showString("IR");
serial.writeLine("IR hex: " + hex);
});IR Remote Transmit To Control Your Devices
Record-and-replay: capture an IR signal from any remote, then replay it to control real devices like your TV or AC. Uses both an IR receiver and IR transmitter LED. Requires the “MakerBit IR Receiver” and “MakerBit IR Transmitter” MakeCode extensions (search “makerbit-ir” in Extensions).
// @ts-nocheck
// Send IR commands to control a TV using the micro:bit buttons.
// Button A = Volume Down
// Button B = Volume Up
// A+B together = Power On/Off
//
// NOTE: The IR codes below are common NEC protocol values for generic TVs.
// Your TV may use different codes! To find the right hex codes:
// 1. Load ir_remote_reader.ts, point your TV remote at the IR receiver,
// and press buttons — the hex codes appear in the serial monitor.
// 2. Or google your TV brand + "IR codes NEC hex".
// Then update the values in the Setup section below.
//
// MakeCode extensions required:
// In the MakeCode editor, click "Extensions" and search for "makerbit-ir".
// Add the "MakerBit IR Transmitter" extension.
//
// Physical setup — IR transmitter LED:
// Connect signal → micro:bit pin 1
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Point the IR transmitter LED at your TV when sending commands.
// --- Setup ---
// Connect IR transmitter on pin 1
makerbit.connectIrSenderLed(AnalogPin.P1);
// IR codes — update these for your specific TV!
// These are common NEC protocol codes; google "[your TV brand] IR hex codes"
let IR_POWER = "00FF02FD";
let IR_VOL_UP = "00FF18E7";
let IR_VOL_DOWN = "00FF4AB5";
basic.showIcon(IconNames.Target);
// --- Event Handlers ---
// Button A: Volume Down
input.onButtonPressed(Button.A, function () {
makerbit.sendIrDatagram(IR_VOL_DOWN);
basic.showString("-");
serial.writeLine("Sent: Volume Down");
basic.pause(300);
basic.showIcon(IconNames.Target);
});
// Button B: Volume Up
input.onButtonPressed(Button.B, function () {
makerbit.sendIrDatagram(IR_VOL_UP);
basic.showString("+");
serial.writeLine("Sent: Volume Up");
basic.pause(300);
basic.showIcon(IconNames.Target);
});
// A+B together: Power On/Off
input.onButtonPressed(Button.AB, function () {
makerbit.sendIrDatagram(IR_POWER);
basic.showIcon(IconNames.Square);
serial.writeLine("Sent: Power Toggle");
basic.pause(500);
basic.showIcon(IconNames.Target);
});OLED Display
Displays text and numbers on a 0.96” OLED screen (128x64 pixels) — real visual output beyond the 5x5 LED grid. Shows a counter, light level, and temperature. Requires the “OLED_SSD1306” MakeCode extension (search “OLED” in Extensions). Uses I2C: plug into the sensor shield’s I2C port.
// @ts-nocheck
// Displays text and numbers on a 0.96" OLED screen (128x64 pixels).
// This tiny screen gives you real visual output beyond the 5x5 LED grid —
// show sensor readings, messages, or simple graphics.
//
// MakeCode extension required:
// In the MakeCode editor, click "Extensions" and search for "OLED".
// Add the "OLED_SSD1306" extension by Tinkertanker.
//
// Physical setup:
// The OLED module has 4 pins. It uses I2C, so it must go on specific pins:
// Connect GND → micro:bit GND
// Connect VCC → micro:bit 3V
// Connect SCL → micro:bit pin 19 (I2C clock)
// Connect SDA → micro:bit pin 20 (I2C data)
// Note: on the sensor shield, just plug into one of the I2C ports.
// --- Setup ---
OLED.init(128, 64);
OLED.writeStringNewLine("Hello!");
OLED.writeStringNewLine("micro:bit OLED");
basic.pause(2000);
// --- Main Loop ---
// Show a counter that updates every second
let count = 0;
basic.forever(function () {
OLED.clear();
OLED.writeStringNewLine("Count: " + count);
OLED.writeStringNewLine("Light: " + input.lightLevel());
OLED.writeStringNewLine("Temp: " + input.temperature() + "C");
count += 1;
serial.writeValue("count", count);
basic.pause(1000);
});LCD Display
Displays text on a 1602 LCD screen (2 rows of 16 characters) — the classic display found on microwaves, thermostats, and vending machines. Requires the “i2cLCD1602” MakeCode extension (search “LCD1602” in Extensions). Uses I2C: plug into the sensor shield’s I2C port. Tip: if the screen looks blank, adjust the blue potentiometer on the back.
// @ts-nocheck
// Displays text and numbers on a 1602 LCD screen (2 rows of 16 characters).
// This classic display is on microwaves, thermostats, and vending machines.
// Great for showing sensor readings or status messages.
//
// MakeCode extension required:
// In the MakeCode editor, click "Extensions" and search for "LCD1602".
// Add the "i2cLCD1602" extension.
//
// Physical setup:
// The LCD module has 4 pins. It uses I2C, so it must go on specific pins:
// Connect GND → micro:bit GND
// Connect VCC → micro:bit 5V (use battery pack — LCD needs 5V for backlight)
// Connect SCL → micro:bit pin 19 (I2C clock)
// Connect SDA → micro:bit pin 20 (I2C data)
// Note: on the sensor shield, just plug into one of the I2C ports.
// Tip: if the screen looks blank, adjust the blue potentiometer on the back.
// --- Setup ---
// Address 0 means auto-detect. Try 39 or 63 if auto doesn't work.
I2C_LCD1602.LcdInit(0);
I2C_LCD1602.ShowString("Hello!", 0, 0);
I2C_LCD1602.ShowString("micro:bit LCD", 0, 1);
basic.pause(2000);
// --- Main Loop ---
// Show a counter and temperature that update every second
let count2 = 0;
basic.forever(function () {
I2C_LCD1602.ShowString("Count: " + count2 + " ", 0, 0);
I2C_LCD1602.ShowString("Temp: " + input.temperature() + "C ", 0, 1);
count2 += 1;
serial.writeValue("count", count2);
basic.pause(1000);
});Medium complexity examples
Analog data smoothing
Demonstrates smoothing noisy analog sensor data using a rolling average and dynamic min/max tracking. More advanced concept to be aware of.
// @ts-nocheck
// Demonstrates smoothing noisy analog sensor data using a rolling average
// and dynamic min/max tracking to produce a stable percentage output.
// --- Setup ---
let ValueAsPercentage = 0;
let SmoothedValue = 0;
let maxValue = 0;
let minValue = 0;
let SensorMax = 0;
let SensorMin = 0;
// What the sensor reads in - will vary for each sensor
let RawSensorValue = 0;
// Min for the sensor (you need to update this with values from using the sensor the way you want)
SensorMin = 0;
// Max for the sensor (you need to update this with values from using the sensor the way you want)
SensorMax = 256;
// This gets reset by this program every run
minValue = 1023;
// This gets reset by this program every run
maxValue = 0;
SmoothedValue = 511;
ValueAsPercentage = 50;
// --- Main Loop ---
basic.forever(function () {
basic.pause(100);
RawSensorValue = input.lightLevel();
CleanAnalogData(RawSensorValue);
led.plotBarGraph(ValueAsPercentage, 100);
serial.writeValue("RawSensor", RawSensorValue);
serial.writeValue("Smoothed", SmoothedValue);
serial.writeValue("%", ValueAsPercentage);
serial.writeValue("Max", maxValue);
serial.writeValue("Min", minValue);
});
// --- Functions ---
function CleanAnalogData(input2: number) {
// Ignore values outside the normal range. Differs for each sensor
if (input2 >= SensorMin && input2 <= SensorMax) {
// Set new Max Value as new readings come in
if (input2 > maxValue) {
maxValue = input2;
}
// Set new Min Value as new readings come in
if (input2 < minValue) {
minValue = input2;
}
SmoothedValue = Math.round(SmoothedValue + (input2 - SmoothedValue) / 5);
ValueAsPercentage = Math.round(Math.map(SmoothedValue, minValue, maxValue, 0, 100));
}
}Rotary encoder with RGB Color Picker
RGB rotary encoder color picker: twist to cycle through colors, press the button to send the selected hex color value over serial.
// @ts-nocheck
//
// RGB rotary encoder color picker: twist to cycle through colors on the built-in
// RGB LED, press the button to send the selected hex color value over serial.
//
// The RGB Encoder has 2 sides with pins
// Facing the 3 pin side, left to right
// 1) Encoder A connect to Pin 9
// 2) Ground
// 3) Encoder B connect to Pin 8
// Facing the 5 pin side, left to right
// 4) Voltage. 3.3v seems to work
// 5) Blue connect to Pin 2
// 6) Switch connect to Pin 16
// 7) Green connect to Pin 1
// 8) Red connect to Pin 0
// Note the device is wired different than other simple components, which can cause confusion
// You set LED pins down to light them.
// You can use analog out to control brightness,
// pins.analog_write_pin(AnalogPin.P0, 0) is fully on
// pins.analog_write_pin(AnalogPin.P0, 1023) is fully off
// Rotary Encoder can NOT use the standard microbit KY-040 rotary encoder extension
// very helpful guide https://qbalsdon.github.io/circuitpython/rotary-encoder/python/led/2021/02/27/rgb-rotary-encoder.html
// --- Setup ---
let current_time: number;
let encoder_a: number;
let encoder_b: number;
led.enable(false);
serial.redirectToUSB();
pins.setPull(DigitalPin.P8, PinPullMode.PullUp);
pins.setPull(DigitalPin.P9, PinPullMode.PullUp);
pins.setPull(DigitalPin.P16, PinPullMode.PullDown);
let red = 255;
let green = 0;
let blue = 0;
let color_position = 0;
let encoder_a_prev = 1;
let loop_time = input.runningTime();
// --- Functions ---
function to_hex(value: number) {
let hex_digits = "0123456789abcdef";
return hex_digits[Math.idiv(value, 16)] + hex_digits[value % 16];
}
function set_color_from_position(pos: number) {
if (pos < 85) {
red = 255 - pos * 3;
green = pos * 3;
blue = 0;
} else if (pos < 170) {
pos -= 85;
red = 0;
green = 255 - pos * 3;
blue = pos * 3;
} else {
pos -= 170;
red = pos * 3;
green = 0;
blue = 255 - pos * 3;
}
}
// --- Main Loop ---
while (true) {
set_color_from_position(color_position);
pins.analogWritePin(AnalogPin.P0, 1023 - red * 4);
pins.analogWritePin(AnalogPin.P1, 1023 - green * 4);
pins.analogWritePin(AnalogPin.P2, 1023 - blue * 4);
// Button - flash white and send hex color
if (pins.digitalReadPin(DigitalPin.P16) == 1) {
serial.writeLine("#" + to_hex(red) + to_hex(green) + to_hex(blue));
// Flash white
pins.analogWritePin(AnalogPin.P0, 0);
pins.analogWritePin(AnalogPin.P1, 0);
pins.analogWritePin(AnalogPin.P2, 0);
basic.pause(200);
}
// Check encoder
current_time = input.runningTime();
if (current_time >= loop_time + 5) {
encoder_a = pins.digitalReadPin(DigitalPin.P8);
encoder_b = pins.digitalReadPin(DigitalPin.P9);
if (encoder_a == 0 && encoder_a_prev == 1) {
if (encoder_b == 1) {
color_position += 5;
// Clockwise - step forward
if (color_position > 255) {
color_position = 0;
}
} else {
color_position -= 5;
// Counter-clockwise - step back
if (color_position < 0) {
color_position = 255;
}
}
}
encoder_a_prev = encoder_a;
loop_time = current_time;
}
basic.pause(10);
}Control Servo with analog sensor
Controls a servo motor position using an analog sensor input. The sensor reading on P1 is mapped to a servo angle on P0.
// @ts-nocheck
// Controls a servo motor position using an analog sensor input.
// The sensor reading on P1 is mapped to a servo angle on P0.
// --- Setup ---
let servo = 0;
basic.showIcon(IconNames.SmallHeart);
serial.redirectToUSB();
// --- Main Loop ---
basic.forever(function () {
servo = Math.map(pins.analogReadPin(AnalogReadWritePin.P1), 0, 2, 0, 10);
led.plotBarGraph(servo, 180);
pins.servoWritePin(AnalogPin.P0, servo);
serial.writeLine("" + servo);
});Servo sonar with smoothing
Controls a servo motor based on an ultrasonic distance sensor reading, with data smoothing applied to prevent jittery movement.
// @ts-nocheck
// Controls a servo motor based on an ultrasonic distance sensor reading,
// with data smoothing applied to prevent jittery movement.
// --- Setup ---
let newAngle = 0;
let SonarReading = 0;
let ServoAngle = 180;
servos.P2.setRange(0, 180);
basic.showIcon(IconNames.Chessboard);
// --- Main Loop ---
basic.forever(function () {
SonarReading = sonar.ping(DigitalPin.P0, DigitalPin.P1, PingUnit.Centimeters);
if (SonarReading > 1 && SonarReading < 40) {
newAngle = Math.map(SonarReading, 1, 40, 0, 180);
ServoAngle = Math.round(ServoAngle + (newAngle - ServoAngle) / 5);
serial.writeLine("sonarCM:" + SonarReading + " angle:" + ServoAngle + " Angle Difference:" + (newAngle - ServoAngle));
servos.P2.setAngle(ServoAngle);
led.plotBarGraph(ServoAngle, 180);
}
basic.pause(100);
});More Advanced programs
Flappy pixel
A minimal version of Flappy Bird on the micro:bit 5x5 LED screen. Press button A to flap upward; avoid the walls scrolling toward you.
// @ts-nocheck
// A minimal version of Flappy Bird on the micro:bit 5x5 LED screen.
// Press button A to flap upward; avoid the walls scrolling toward you.
// --- Event Handlers ---
// Runs when button A is pressed - flap the bird upward
input.onButtonPressed(Button.A, function () {
birdY += -1;
if (birdY < 0) {
birdY = 0;
}
});
// --- Setup ---
let birdY = 0;
basic.clearScreen();
let score = 0;
birdY = 0;
let wallX = 5;
let WallHoleY = 2;
// --- Main Loop ---
basic.forever(function () {
basic.clearScreen();
if (wallX < 0) {
wallX = 4;
WallHoleY = randint(0, 4);
}
for (let index = 0; index <= 4; index++) {
led.plotBrightness(wallX, index, 28);
}
led.unplot(wallX, WallHoleY);
if (birdY > 4) {
birdY = 4;
}
led.plot(0, birdY);
if (wallX == 0) {
if (birdY == WallHoleY) {
music.play(music.tonePlayable(523, music.beat(BeatFraction.Quarter)), music.PlaybackMode.UntilDone);
} else {
music.play(music.tonePlayable(131, music.beat(BeatFraction.Quarter)), music.PlaybackMode.UntilDone);
}
}
wallX += -1;
birdY += 1;
basic.pause(1000);
});Flappy Servo
Steers a servo motor up and down using buttons A and B. A simple demo of using buttons to control physical output.
// @ts-nocheck
// Steers a servo motor up and down using buttons A and B.
// A simple demo of using buttons to control physical output.
// --- Event Handlers ---
// Button A moves the servo up
input.onButtonPressed(Button.A, function () {
if (birdY < maxY) {
birdY += 10;
}
});
// Button B moves the servo down
input.onButtonPressed(Button.B, function () {
if (birdY > minY) {
birdY += -10;
}
});
// --- Setup ---
let minY = 0;
let maxY = 0;
let birdY = 0;
birdY = 100;
maxY = 180;
minY = 0;
servos.P0.setRange(minY, maxY);
// --- Main Loop ---
basic.forever(function () {
servos.P0.setAngle(birdY);
basic.pause(200);
});Smart Thermostat Demo
A thermostat in miniature: reads temperature from a DHT11 sensor, displays it on an OLED screen, and automatically turns on a fan when it gets too hot. Buttons A/B adjust the threshold. Components: DHT11 + OLED + Fan Module. Requires “OLED_SSD1306” and “DHT11_DHT22” MakeCode extensions.
// @ts-nocheck
// A mini smart thermostat: reads temperature, shows it on the OLED screen,
// and automatically turns on a fan when it gets too hot. This is how a Nest
// thermostat works at its core: sense → display → actuate.
//
// MakeCode extensions required:
// Click "Extensions" and search for "OLED". Add "OLED_SSD1306" by Tinkertanker.
// Click "Extensions" and search for "DHT11". Add "DHT11_DHT22" by Alan Krantas.
//
// Physical setup:
// DHT11 temperature sensor:
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// OLED display (I2C):
// Connect GND → micro:bit GND
// Connect VCC → micro:bit 3V
// Connect SCL → micro:bit pin 19
// Connect SDA → micro:bit pin 20
// Fan module:
// Connect INA → micro:bit pin 1
// Connect INB → micro:bit pin 2
// Connect VCC → battery pack 5V
// Connect GND → micro:bit GND
//
// Adjust the threshold temperature to suit your environment.
// --- Setup ---
let temp = 0;
let hum = 0;
let fanRunning = false;
let threshold = 26; // Fan turns on above this temperature (Celsius)
OLED.init(128, 64);
OLED.writeStringNewLine("Thermostat");
OLED.writeStringNewLine("Starting...");
pins.digitalWritePin(DigitalPin.P1, 0);
pins.digitalWritePin(DigitalPin.P2, 0);
basic.pause(2000);
// --- Main Loop ---
basic.forever(function () {
// Read temperature and humidity
dht11_dht22.queryData(DHTtype.DHT11, DigitalPin.P0, true, false, true);
temp = dht11_dht22.readData(dataType.temperature);
hum = dht11_dht22.readData(dataType.humidity);
// Update OLED display
OLED.clear();
OLED.writeStringNewLine("Temp: " + temp + " C");
OLED.writeStringNewLine("Humidity: " + hum + " %");
OLED.writeStringNewLine("Threshold: " + threshold + " C");
// Turn fan on or off based on temperature
if (temp > threshold) {
pins.digitalWritePin(DigitalPin.P1, 1);
pins.digitalWritePin(DigitalPin.P2, 0);
OLED.writeStringNewLine("Fan: ON");
fanRunning = true;
} else {
pins.digitalWritePin(DigitalPin.P1, 0);
pins.digitalWritePin(DigitalPin.P2, 0);
OLED.writeStringNewLine("Fan: OFF");
fanRunning = false;
}
serial.writeValue("temp", temp);
serial.writeValue("humidity", hum);
serial.writeValue("fan", fanRunning ? 1 : 0);
basic.pause(2000);
});
// --- Event Handlers ---
// Button A: lower threshold
input.onButtonPressed(Button.A, function () {
threshold -= 1;
});
// Button B: raise threshold
input.onButtonPressed(Button.B, function () {
threshold += 1;
});Proximity-Reactive Object
An object that reacts as you approach: OLED display shows different messages at different distances, and a servo arm points toward you. Think: interactive museum exhibit, responsive furniture, robot personality. Components: Ultrasonic + OLED + Servo. Requires “OLED_SSD1306” and “Sonar” MakeCode extensions.
// @ts-nocheck
// An object that reacts as you approach: the OLED display changes its message
// and a servo arm points toward you based on distance. Think: interactive museum
// exhibit, responsive furniture, or a robot with personality.
//
// MakeCode extensions required:
// Click "Extensions" and search for "OLED". Add "OLED_SSD1306" by Tinkertanker.
// Click "Extensions" and search for "Sonar". Add the Sonar extension.
//
// Physical setup:
// Ultrasonic sensor (HC-SR04):
// Connect Trig → micro:bit pin 0
// Connect Echo → micro:bit pin 1
// Connect VCC → micro:bit 5V (use battery pack)
// Connect GND → micro:bit GND
// OLED display (I2C):
// Connect GND → micro:bit GND
// Connect VCC → micro:bit 3V
// Connect SCL → micro:bit pin 19
// Connect SDA → micro:bit pin 20
// Servo motor:
// Connect signal → micro:bit pin 2
// Connect VCC → battery pack positive
// Connect GND → micro:bit GND
// --- Setup ---
let distance = 0;
let servoAngle = 90;
OLED.init(128, 64);
OLED.writeStringNewLine("Waiting...");
servos.P2.setRange(0, 180);
// --- Main Loop ---
basic.forever(function () {
distance = sonar.ping(DigitalPin.P0, DigitalPin.P1, PingUnit.Centimeters);
// Map distance to servo angle: closer = more servo movement
// At 40cm+ the servo centers, at 5cm it swings fully
servoAngle = Math.round(Math.map(distance, 5, 40, 180, 90));
servoAngle = Math.constrain(servoAngle, 0, 180);
servos.P2.setAngle(servoAngle);
// Change OLED message based on distance zones
OLED.clear();
OLED.writeStringNewLine("Distance: " + distance + "cm");
if (distance < 10) {
OLED.writeStringNewLine("TOO CLOSE!");
basic.showIcon(IconNames.Surprised);
} else if (distance < 25) {
OLED.writeStringNewLine("Hello there!");
basic.showIcon(IconNames.Happy);
} else if (distance < 50) {
OLED.writeStringNewLine("Come closer...");
basic.showIcon(IconNames.Asleep);
} else {
OLED.writeStringNewLine("Waiting...");
basic.clearScreen();
}
serial.writeValue("distance", distance);
serial.writeValue("servo", servoAngle);
basic.pause(200);
});Security / Alert System
A simple security system with three states: DISARMED, ARMED, and TRIGGERED. PIR motion sensor detects intruders, buzzer sounds the alarm, OLED shows status. Press A to arm (with countdown), B to disarm. Demonstrates state machines — how every real product manages modes. Components: PIR + Buzzer + OLED. Requires “OLED_SSD1306” MakeCode extension.
// @ts-nocheck
// A simple security system: PIR motion sensor triggers an alarm with buzzer
// and OLED display. Press button A to arm, button B to disarm.
// Demonstrates a state machine — the system is always in one of three states:
// DISARMED → ARMED → TRIGGERED.
//
// MakeCode extension required:
// Click "Extensions" and search for "OLED". Add "OLED_SSD1306" by Tinkertanker.
//
// Physical setup:
// PIR motion sensor:
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Passive buzzer:
// Connect S → micro:bit pin 1
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// OLED display (I2C):
// Connect GND → micro:bit GND
// Connect VCC → micro:bit 3V
// Connect SCL → micro:bit pin 19
// Connect SDA → micro:bit pin 20
// --- Setup ---
// States: 0 = DISARMED, 1 = ARMED, 2 = TRIGGERED
let state = 0;
let motion = 0;
OLED.init(128, 64);
OLED.writeStringNewLine("Security System");
OLED.writeStringNewLine("Press A to arm");
// --- Event Handlers ---
// Button A: arm the system
input.onButtonPressed(Button.A, function () {
if (state == 0) {
state = 1;
OLED.clear();
OLED.writeStringNewLine("ARMING...");
// 5 second countdown before armed
for (let i = 5; i > 0; i--) {
basic.showNumber(i);
basic.pause(1000);
}
OLED.clear();
OLED.writeStringNewLine("ARMED");
OLED.writeStringNewLine("Press B to disarm");
basic.showIcon(IconNames.SmallDiamond);
serial.writeLine("System armed");
}
});
// Button B: disarm the system
input.onButtonPressed(Button.B, function () {
state = 0;
music.stopAllSounds();
OLED.clear();
OLED.writeStringNewLine("DISARMED");
OLED.writeStringNewLine("Press A to arm");
basic.showIcon(IconNames.Heart);
serial.writeLine("System disarmed");
});
// --- Main Loop ---
basic.forever(function () {
if (state == 1) {
// ARMED: check for motion
motion = pins.digitalReadPin(DigitalPin.P0);
if (motion == 1) {
state = 2;
serial.writeLine("MOTION DETECTED!");
}
}
if (state == 2) {
// TRIGGERED: alarm!
OLED.clear();
OLED.writeStringNewLine("!! ALERT !!");
OLED.writeStringNewLine("Motion detected!");
OLED.writeStringNewLine("Press B to disarm");
basic.showIcon(IconNames.Skull);
music.play(
music.tonePlayable(988, music.beat(BeatFraction.Quarter)),
music.PlaybackMode.InBackground,
);
basic.pause(200);
basic.showIcon(IconNames.No);
basic.pause(200);
}
basic.pause(100);
});Environmental Dashboard
A mini weather station: reads temperature, humidity, UV level, and light on one OLED display. Multiple sensors feeding one screen — teaches data visualization on physical displays. Components: DHT11 + UV sensor + OLED. Requires “OLED_SSD1306” and “DHT11_DHT22” MakeCode extensions.
// @ts-nocheck
// A mini weather station: reads temperature, humidity, and UV level,
// then displays all readings on an OLED screen. A tiny environmental
// dashboard you can carry around or mount in a room.
//
// MakeCode extensions required:
// Click "Extensions" and search for "OLED". Add "OLED_SSD1306" by Tinkertanker.
// Click "Extensions" and search for "DHT11". Add "DHT11_DHT22" by Alan Krantas.
//
// Physical setup:
// DHT11 temperature/humidity sensor:
// Connect S → micro:bit pin 0
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// UV sensor (GUVA-S12SD):
// Connect S → micro:bit pin 1
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// OLED display (I2C):
// Connect GND → micro:bit GND
// Connect VCC → micro:bit 3V
// Connect SCL → micro:bit pin 19
// Connect SDA → micro:bit pin 20
// --- Setup ---
let temp2 = 0;
let hum2 = 0;
let uvRaw = 0;
let uvIdx = 0;
OLED.init(128, 64);
OLED.writeStringNewLine("Environment");
OLED.writeStringNewLine("Dashboard");
basic.pause(2000);
// --- Main Loop ---
basic.forever(function () {
// Read DHT11
dht11_dht22.queryData(DHTtype.DHT11, DigitalPin.P0, true, false, true);
temp2 = dht11_dht22.readData(dataType.temperature);
hum2 = dht11_dht22.readData(dataType.humidity);
// Read UV sensor
uvRaw = pins.analogReadPin(AnalogPin.P1);
uvIdx = Math.round(Math.map(uvRaw, 0, 1023, 0, 11));
// Update OLED display
OLED.clear();
OLED.writeStringNewLine("Temp: " + temp2 + " C");
OLED.writeStringNewLine("Humid: " + hum2 + " %");
OLED.writeStringNewLine("UV: " + uvIdx + " / 11");
// Built-in light level for comparison
OLED.writeStringNewLine("Light: " + input.lightLevel());
// Log to serial
serial.writeValue("temp", temp2);
serial.writeValue("humidity", hum2);
serial.writeValue("uvIndex", uvIdx);
serial.writeValue("light", input.lightLevel());
basic.pause(2000);
});Plant Nanny
A plant care monitor: reads soil moisture, UV light, and temperature, then shows plant health on an OLED screen. When soil is too dry, a servo opens a water valve (or just alerts you to water manually). Components: Soil moisture sensor + UV sensor + Servo + OLED. Requires “OLED_SSD1306” MakeCode extension.
// @ts-nocheck
// A plant care monitor: reads soil moisture, temperature, and UV light,
// then shows plant health status on an OLED screen. When soil is too dry,
// the servo opens a water valve (or you can just use the alert to water manually).
//
// MakeCode extensions required:
// Click "Extensions"
// search for "OLED". Add "OLED_SSD1306" by Tinkertanker.
// search for "servo". Add "microservo" extension
//
// Physical setup:
// Soil moisture sensor:
// Connect S → micro:bit pin 0 (analog read)
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Insert the metal prongs into the soil.
// UV sensor (GUVA-S12SD):
// Connect S → micro:bit pin 1 (analog read)
// Connect V → micro:bit 3V
// Connect G → micro:bit GND
// Servo (for water valve — optional):
// Connect signal → micro:bit pin 2
// Connect VCC → battery pack positive
// Connect GND → micro:bit GND
// OLED display (I2C):
// Connect GND → micro:bit GND
// Connect VCC → micro:bit 3V
// Connect SCL → micro:bit pin 19
// Connect SDA → micro:bit pin 20
// --- Setup ---
let soilMoisture = 0;
let soilPercent = 0;
let uvRaw2 = 0;
let uvIdx2 = 0;
let dryThreshold = 30; // Below this % = needs water
OLED.init(128, 64);
OLED.writeStringNewLine("Plant Nanny");
OLED.writeStringNewLine("Starting...");
servos.P2.setAngle(0); // Valve closed
basic.pause(2000);
// --- Main Loop ---
basic.forever(function () {
// Read soil moisture (higher reading = wetter soil)
soilMoisture = pins.analogReadPin(AnalogPin.P0);
soilPercent = Math.round(Math.map(soilMoisture, 0, 1023, 0, 100));
// Read UV sensor
uvRaw2 = pins.analogReadPin(AnalogPin.P1);
uvIdx2 = Math.round(Math.map(uvRaw2, 0, 1023, 0, 11));
// Update OLED display
OLED.clear();
OLED.writeStringNewLine("Soil: " + soilPercent + " %");
OLED.writeStringNewLine("UV: " + uvIdx2 + " / 11");
OLED.writeStringNewLine("Temp: " + input.temperature() + " C");
// Check if plant needs water
if (soilPercent < dryThreshold) {
OLED.writeStringNewLine("NEEDS WATER!");
basic.showIcon(IconNames.Sad);
// Open water valve (servo to 90 degrees)
servos.P2.setAngle(90);
music.play(music.tonePlayable(262, music.beat(BeatFraction.Half)), music.PlaybackMode.InBackground);
} else {
OLED.writeStringNewLine("Plant is happy");
basic.showIcon(IconNames.Happy);
// Close water valve
servos.P2.setAngle(0);
}
serial.writeValue("soil", soilPercent);
serial.writeValue("uvIndex", uvIdx2);
basic.pause(5000);
});Wireless Social Network
Simple wireless messaging between two micro:bits using the radio. Press button A to send a message; received messages display on the LED screen.
// @ts-nocheck
// Simple wireless messaging between two micro:bits using the radio.
// Press button A to send a message; received messages display on the LED screen.
// --- Setup ---
radio.setGroup(1);
// --- Event Handlers ---
// Sends a message when button A is pressed
input.onButtonPressed(Button.A, function () {
radio.sendString("Micro Chat");
});
// Runs when a radio message is received
radio.onReceivedString(function (receivedString: string) {
basic.showString(receivedString);
});Future
MakeCode Data Logging
The Microbit MakeCode editor has built-in data logging that saves to the microbit’s flash memory. You can log data, then download it as a CSV file when you connect the Microbit to your computer via USB.
Add SD card module (standalone logging)
Connect an SD card reader via SPI pins: Requires additional hardware (~$5)