How to read SEN0465 Oxygen Sensor with Micro:bit on MakeCode Python
Marco Antonio PG 2026-06-15 01:23:18 7 Views0 Replies Tutorial: How to read DFRobot Oxygen Sensor (SEN0465) with Micro:bit in MakeCode Python
The Problem
When trying to connect the SEN0465 oxygen sensor (on the DFRobot Gas Sensor V1.1 base) to a Micro:bit using MakeCode, you might run into a hurdle: there are no official blocks, and sending a standard I2C read command only returns null values (0x00 or 0xFF).
This happens because the module does not act like standard I2C memory. To wake up and transmit the oxygen concentration, it requires a strict 9-byte data frame, which includes a start header (0xFF), the master command (0x88), and a Checksum (0x77) at the end.
If the MakeCode compiler does not send the memory buffer in this exact format, the sensor completely ignores the request.
Hardware Setup & Physical Connections
1. DIP Switches
For the module to communicate via the I2C bus and use memory address 0x74 (the one used in our code), the small switches on the V1.1 base must be set to the 0 (OFF) position:
-SEL: 0 (Enables I2C mode)
-A1: 0
-A0: 0
2. Wiring to the Micro:bit
Connect the sensor directly to your Micro:bit expansion board using the nomenclature printed on the base's silkscreen:
-(+) -> 3.3V (or 3V)
-(-) -> GND
-(C/R) -> Pin SCL 19
-(D/T) -> Pin SDA 20
The Solution: Validated Code for MakeCode Python
The MakeCode compiler is very strict with memory management. To avoid overflow errors, we must instantiate a 9-byte buffer, populate it sequentially, and include an anti-noise validation filter that checks for the correct response header (0xFF) before calculating the percentage.
Copy and paste the following code into the Python tab of MakeCode:
Python
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# 1. Global Variables (Default address for DFRobot base)
I2C_ADDR = 0x74
# 2. Strict 9-byte master frame
CMD_O2 = bytearray(9)
CMD_O2[0] = 0xFF # Header
CMD_O2[1] = 0x01
CMD_O2[2] = 0x88 # "Read all data" command
CMD_O2[3] = 0x00
CMD_O2[4] = 0x00
CMD_O2[5] = 0x00
CMD_O2[6] = 0x00
CMD_O2[7] = 0x00
CMD_O2[8] = 0x77 # Checksum
# 3. Robust reading function
def read_oxygen():
# Write the command to the bus
pins.i2c_write_buffer(I2C_ADDR, CMD_O2, False)
basic.pause(100) # Sensor processing time
# Read the 9-byte response
resp = pins.i2c_read_buffer(I2C_ADDR, 9, False)
# 4. Validation: Check the packet header (Anti-noise filter)
if resp[0] == 0xFF:
# Valid packet, extract High and Low concentration bytes
b_high = resp[2]
b_low = resp[3]
# Bitshift and calculation
raw_concentration = (b_high << 8) | b_low
return raw_concentration / 10
else:
# Invalid packet (returns error to prevent false alarms)
return -1
# --- Main Loop ---
def on_forever():
percentage = read_oxygen()
# Check if the reading was successful (20.9% is normal in open air)
if percentage != -1:
serial.write_line("O2: " + str(percentage) + " %")
else:
serial.write_line("Read error: Check I2C connection")
basic.pause(1000)
basic.forever(on_forever)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Quick Test:
Open your device's serial console. To confirm the sensor is actually measuring gas displacement, you can place a glass over the probe and light a lighter inside to consume the trapped oxygen. You will see the console readings drop quickly from 20.9% down to deficiency levels (around 18%), confirming your code works perfectly.


