器→工具, 电子电路

Microbit学习之Python API

钱魏Way · · 7 次浏览
!文章内容如有错误或排版问题,请提交反馈,非常感谢!

Microbit的Python API主要基于micro:bit库,该库提供了丰富的硬件接口和功能。为了更加全面的学习,我们以官方Python Editor作为参考。

目录

核心API学习

显示模块 (display)

Micro:bit 的显示模块是其最核心的功能之一,它控制着板载的 5×5 LED 矩阵。这个模块提供了丰富的功能,从简单的文本显示到复杂的动画效果。

基本显示功能

文本显示

from microbit import *

# 滚动显示文本(默认从右向左)
display.scroll("Hello Micro:bit!")

# 带参数的滚动显示
display.scroll("Python", delay=100, wait=False, loop=True, monospace=False)
  • delay: 滚动速度(毫秒),值越小越快(默认150)
  • wait: 是否阻塞程序(默认True,显示完才执行后续代码)
  • loop: 是否循环显示(默认False)
  • monospace: 是否使用等宽字体(默认False)

显示数字

# 直接显示整数
display.show(42)

# 显示浮点数(自动四舍五入)
display.show(3.14159)  # 显示3

# 显示字符
display.show('A')

清除显示

display.clear()  # 关闭所有LED

图像显示系统

内置图像

MicroPython 预置了数十种常用图像:

# 显示内置图像
display.show(Image.HEART)
display.show(Image.HAPPY)
display.show(Image.SAD)
display.show(Image.ARROW_N)  # 北箭头

其他内置图像:Images — BBC micro:bit MicroPython 1.1.1 documentation

自定义图像

您可以制作自己的图像。 每个 LED 的亮度由介于 0(关闭)和 9(最亮)之间的数字来表示:

smile = Image("00000:"
             "09090:"
             "00000:"
             "90009:"
             "09990")

display.show(smile)

备注:MicroBit v1.5的板子不能调整亮度,仅V2板子支持。

图像操作

# 图像反转(亮的变暗,暗的变亮)
inverted = Image.HEART.invert()
display.show(inverted)

# 图像位移
shifted = Image.ARROW_E.shift_left(1)  # 左移1像素
display.show(shifted)

像素级控制

设置单个像素

# 点亮(2,3)位置的LED(亮度9)
display.set_pixel(2, 3, 9)

# 关闭(1,1)位置的LED
display.set_pixel(1, 1, 0)
  • 坐标范围:x (0-4), y (0-4)
  • 亮度范围:0 (关) 到 9 (最亮)

获取像素状态

brightness = display.get_pixel(0, 4)  # 返回(0,4)的亮度值

动画效果

图像序列动画

# 创建动画帧
frames = [
    Image("00000:00000:00900:00000:00000"),
    Image("00000:09990:09090:09990:00000"),
    Image("99999:90009:90009:90009:99999")
]

# 播放动画
display.show(frames, delay=200, loop=True, clear=True)
  • delay: 帧间隔(毫秒)
  • loop: 是否循环播放
  • clear: 播放结束后是否清屏

动态生成动画

# 创建心跳动画
while True:
    display.show(Image.HEART)
    sleep(500)
    display.show(Image.HEART_SMALL)
    sleep(500)

实用技巧与示例

显示传感器数据

while True:
    temp = temperature()
    # 温度值显示在中间列
    display.show(str(temp)[0:5])  # 最多显示5字符
    sleep(1000)

创建简单游戏

# 简单的点灯游戏
x, y = 2, 2
display.set_pixel(x, y, 9)

while True:
    if button_a.was_pressed():
        display.set_pixel(x, y, 0)
        x = (x + 1) % 5
        display.set_pixel(x, y, 9)
    
    if button_b.was_pressed():
        display.set_pixel(x, y, 0)
        y = (y + 1) % 5
        display.set_pixel(x, y, 9)

调试技巧

串口输出:结合print()调试显示逻辑

print("Current temperature:",temperature())

按钮(button)

Micro:bit 正面有两个

按钮。 按钮 A 和按钮 B 可用作输入,以便在按下它们时在程序中进行一些操作。

button_a, button_b对象的方法:is_pressed(), was_pressed(), get_presses()。

button_a.get_presses()

  • 统计型方法:返回整数,代表按压次数而不是布尔值
  • 累加计数:自动记录自上次读取以来的完整按压
  • 自动重置:每次调用后自动清零计数器
  • 完整按压要求:只统计”按下并释放”的完整按压序列

button_a.is_pressed() vs button_a.was_pressed() 全面解析

在 MicroPython 的 Micro:bit 编程中,这两种方法都是用于检测按钮状态的,但它们的用途和内部机制有显著区别。理解这些差异对于开发响应式的用户交互程序至关重要。

核心区别对比表

特性 button_a.is_pressed() button_a.was_pressed()
检测内容 按钮当前物理状态 自上次检查后的按钮状态变化
返回值时间窗口 当前瞬间状态 从上一次调用到当前的变化
返回类型 布尔值 (True/False) 布尔值 (True/False)
状态重置 无自动重置 检测后自动重置
典型用途 持续检测(如长按) 单次动作检测(如点击)
调用频率影响 高频率调用可能导致忽略事件
编程范式 状态检测 事件检测

button_a.is_pressed()

  • 工作原理:直接检查按钮当前的物理状态
  • 行为特点:
    • 只要按钮被按住,始终返回True
    • 松开后立即返回False
    • 不记录历史状态变化
  • 适用场景:
# 长按检测示例
from microbit import *

while True:
    if button_a.is_pressed():
        display.show(Image.ARROW_E)  # 持续显示右箭头
    else:
        display.clear()

button_a.was_pressed()

  • 工作原理:检测从上一次调用该方法到现在的按钮变化
  • 行为特点:
    • 仅在按钮按下并释放(完成一次完整点击)后返回True
    • 返回True 后自动重置状态
    • 如果调用间隔中未发生完整点击,返回False
  • 最佳实践场景:
# 单次点击计数示例
from microbit import *

count = 0

while True:
    if button_a.was_pressed():
        count += 1
        display.show(count)
        sleep(200)  # 防抖延时

常见误用场景与解决方案

误用1:高频调用导致事件丢失

# 错误示范
while True:
    if button_a.was_pressed(): 
        # 如果循环执行太快,可能错过快速点击
        do_something()
        
# 解决方案:添加适当延时
while True:
    if button_a.was_pressed():
        do_something()
    sleep(100)  # 100ms间隔足以检测人类点击速度

误用2:误用is_pressed()检测单次点击

# 错误示范
while True:
    if button_a.is_pressed(): 
        # 会多次触发而不是仅一次
        increment_counter()
        
# 正确方法:添加状态机
clicked = False
while True:
    if button_a.is_pressed() and not clicked:
        increment_counter()
        clicked = True
    elif not button_a.is_pressed():
        clicked = False

高级使用技巧

组合使用实现双击检测

from microbit import *
import time

last_press = 0
double_click_threshold = 500  # 500ms间隔内算双击

while True:
    if button_a.was_pressed():
        current = time.ticks_ms()
        if current - last_press < double_click_threshold:
            display.show(Image.YES)  # 检测到双击
        last_press = current

创建长按/短按区别

from microbit import *

long_press_time = 1000  # 1秒算长按

while True:
    if button_a.is_pressed():
        start = time.ticks_ms()
        while button_a.is_pressed():
            elapsed = time.ticks_diff(time.ticks_ms(), start)
            if elapsed > long_press_time:
                display.scroll("Long press")
                break
        else:
            display.scroll("Short press")

Microbit 按钮技术细节

内部状态机

  • 每次调用was_pressed() 后,内部状态标志被清除
  • 实际点击检测:按下 → 释放(才算一次完整点击)
  • 硬件消抖:Microbit 有约 20ms 的硬件消抖滤波

内置传感器

Micro:bit 内置了多种传感器,让开发者无需额外硬件即可创建丰富的交互项目。V1.5 和 V2.0 版本在传感器方面有显著差异。

传感器概览对比表

传感器类型 V1.5 V2.0 主要区别
加速度计 V2.0 灵敏度更高
磁力计 V2.0 精度提升
温度传感器 相同实现
光线传感器 V2.0 新增功能
麦克风 V2.0 新增功能
触摸感应 V2.0 新增功能

加速度计 (Accelerometer)

用途:检测运动、倾斜、震动和自由落体

from microbit import *

while True:
    # 读取三轴加速度值(单位:毫g)
    x = accelerometer.get_x()
    y = accelerometer.get_y()
    z = accelerometer.get_z()
    
    # 检测特定动作
    if accelerometer.is_gesture("shake"):
        display.show(Image.SURPRISED)
    
    # 检测倾斜方向
    if accelerometer.current_gesture() == "face up":
        display.show(Image.HAPPY)
    
    sleep(100)

磁力计 (Compass)

用途:检测磁场强度、方向(电子罗盘)。

第一次使用罗盘时,您可能会被要求通过玩一个小游戏来校准它。 在显示屏上滚动显示 ‘TILT TO FILL SCREEN‘。 倾斜 micro:bit 直到每个 LED 灯都亮起,然后会出现一张快乐的脸。 该操作可确保罗盘能够提供准确的读数。

from microbit import *

# 必须先校准
compass.calibrate()

while True:
    # 获取方向(0-360度)
    heading = compass.heading()
    
    # 获取磁场强度(微特斯拉)
    x, y, z = compass.get_x(), compass.get_y(), compass.get_z()
    
    # 显示方向箭头
    if heading < 45 or heading > 315:
        display.show(Image.ARROW_N)  # 北
    elif heading < 135:
        display.show(Image.ARROW_E)  # 东
    
    sleep(500)

温度传感器

用途:测量处理器温度(非环境温度)

from microbit import *

while True:
    temp = temperature()  # 摄氏度
    display.scroll(f"{temp}C")
    sleep(5000)

注意:测量的是处理器温度,通常比环境温度高3-5°C

光线传感器 (仅V2.0)

用途:测量环境光强度

# 仅适用于V2.0
from microbit import *

while True:
    # 获取光线强度 (0-255)
    light_level = display.read_light_level()
    print(light_level)
    sleep(1000)

V2.0特性

  • 使用LED矩阵反向测量光线
  • 适合检测光照变化而非绝对亮度
  • 可用于创建光控开关

麦克风 (仅V2.0)

用途:检测声音级别和事件

# 仅适用于V2.0
from microbit import *

# 设置声音事件阈值
microphone.set_threshold(SoundEvent.LOUD, 128)

while True:
    # 获取当前声音级别 (0-255)
    level = microphone.sound_level()
    print(level)
    
    # 检测特定声音事件
    if microphone.current_event() == SoundEvent.LOUD:
        display.show(Image.SURPRISED)
    elif microphone.was_event(SoundEvent.QUIET):
        display.show(Image.ASLEEP)
    
    sleep(100)

高级功能

  • get_events():获取所有待处理的声音事件
  • set_analog_period(period):设置模拟信号周期
  • 可用于拍手检测、声音激活项目

触摸感应 (仅V2.0)

用途:检测电容触摸

# 仅适用于V2.0
from microbit import *

while True:
    # 检测引脚触摸
    if pin0.is_touched():
        display.show("0")
    
    # 检测Logo区域触摸(金手指)
    if pin_logo.is_touched():
        display.show(Image.HEART)
    
    sleep(200)

可用触摸点

  • 引脚:0, 1, 2, 3, 4, 5, 6, 7, 9, 10
  • Logo区域:pin_logo
  • 可用于创建触摸开关、交互式界面

扬声器 (仅V2.0)

用途:播放声音和音乐

# 仅适用于V2.0
from microbit import *
import music
import speech
import audio

# 您可以设置 micro:bit 播放音乐的节奏或速度: 节奏以 bpm 为单位,即每分钟节拍数。 数字低于 120 表示比正常节奏慢,高于 120 表示比正常节奏快。
music.set_tempo(bpm=120)

# 播放内置音乐
music.play(music.BIRTHDAY)

# 播放音符
music.play(['c', 'd', 'e', 'c'])

# 音调 micro:bit 可以播放由频率或音调定义的声音
music.pitch(440)

# 语音合成(完全听不清)
speech.say("Hello world", speed=120)

# 播放内置声音
audio.play(Sound.HELLO)

引脚操作指南

Micro:bit 的引脚系统是其最强大的功能之一,允许开发者连接各种外部设备和传感器。

引脚功能分类

引脚 数字I/O 模拟输入 模拟输出(PWM) 触摸感应(V2) 特殊功能
0 UART RX
1 UART TX
2
3 LED行1
4 LED行2
5 按钮A
6 LED列1
7 LED列2
8
9 按钮B
10
11 保留
12 保留
13 SPI SCK
14 SPI MISO
15 SPI MOSI
16 SPI CS
19 I2C SCL
20 I2C SDA
LOGO V2触摸区

基础引脚操作

数字输入/输出

from microbit import *

# 设置引脚为输出模式
pin0.write_digital(1)  # 输出高电平 (3.3V)
pin0.write_digital(0)  # 输出低电平 (0V)

# 读取数字输入
value = pin1.read_digital()  # 返回0或1
if value == 1:
    display.show(Image.YES)

模拟输入

# 读取模拟值 (0-1023)
light_level = pin2.read_analog()  # 光敏电阻示例
display.scroll(str(light_level))

# 电压计算
voltage = pin2.read_analog() * 3.3 / 1023

PWM输出

# 设置PWM占空比 (0-1023)
pin0.write_analog(512)  # 50%占空比

# 控制舵机角度 (0-180度)
def set_servo_angle(pin, angle):
    pulse_width = 500 + (angle * 2000 // 180)  # 500-2500μs
    duty_cycle = pulse_width * 1024 // 20000  # 20ms周期
    pin.write_analog(duty_cycle)

set_servo_angle(pin0, 90)  # 舵机转到90度

高级引脚功能

触摸感应 (V2专有)

if pin0.is_touched():
    display.show(Image.HAPPY)

# 读取原始触摸值
touch_value = pin0.read_analog()  # 0-1023

# Logo区域触摸
if pin_logo.is_touched():
    display.show(Image.HEART)

中断处理

def on_pin_rise():
    display.show("R")

# 设置中断处理
pin0.on_event(PinEvent.RISE, on_pin_rise)  # 上升沿触发
pin1.on_event(PinEvent.FALL, lambda: display.show("F"))  # 下降沿
pin2.on_event(PinEvent.TOUCH, lambda: display.show("T"))  # V2触摸

脉冲测量

# 测量脉冲宽度 (微秒)
pulse_width = pin0.read_pulse_high()  # 高电平时间
pulse_width = pin0.read_pulse_low()   # 低电平时间

# 超声波测距示例
def measure_distance(trigger, echo):
    # 发送10μs触发脉冲
    trigger.write_digital(1)
    sleep(10)
    trigger.write_digital(0)
    
    # 测量回波脉冲宽度
    duration = echo.read_pulse_high()
    
    # 计算距离 (声速340m/s)
    distance = (duration * 0.034) / 2  # cm
    return distance

dist = measure_distance(pin0, pin1)

通信协议支持

I2C通信

from microbit import i2c

# 扫描I2C设备
devices = []
for addr in range(0, 128):
    try:
        i2c.read(addr, 1)
        devices.append(addr)
    except:
        pass

# 读取加速度计数据 (地址0x19)
i2c.write(0x19, b'\x28')  # 设置寄存器
data = i2c.read(0x19, 6)  # 读取6字节
x = (data[1] << 8) | data[0]

SPI通信

from microbit import spi

# 初始化SPI
spi.init(baudrate=1000000, bits=8, mode=0, 
         sclk=pin13, mosi=pin15, miso=pin14)

# 发送数据
spi.write(b'\x01\x02\x03')

# 同时发送和接收
received = spi.write_read(b'\xAA\x55')

UART串口通信

from microbit import uart

# 初始化UART
uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=pin0, rx=pin1)

# 发送数据
uart.write("Hello World\n")

# 接收数据
if uart.any():
    data = uart.read()
    display.scroll(data)

引脚配置选项

上拉/下拉电阻

# 设置内部上拉电阻
pin0.set_pull(pin0.PULL_UP)   # 默认高电平
pin1.set_pull(pin1.PULL_DOWN) # 默认低电平
pin2.set_pull(pin2.NO_PULL)   # 无上拉/下拉

省电技巧

# 关闭未使用引脚
def disable_unused_pins():
    for pin in [pin8, pin11, pin12, pin13, pin14, pin15, pin16]:
        pin.set_pull(pin.NO_PULL)
        pin.write_digital(0)

引脚模式设置

# 设置引脚为模拟输入
pin0.set_analog_period(20)  # 设置PWM周期(毫秒)

# 设置触摸模式(V2)
pin0.set_touch_mode(True)  # 启用触摸检测

引脚状态检测

# 获取引脚模式
mode = pin0.get_mode()  # 返回: digital_in, digital_out, analog, touch

# 获取引脚编号
pin_num = pin0.get_id()

引脚冲突管理

引脚复用机制

Micro:bit 的物理引脚与内部功能复用关系:

P0:LED列1、ADC输入、GPIO
P1:LED列2、ADC输入、GPIO
P2:LED列3、ADC输入、GPIO
P3:LED行1、GPIO
P4:LED行2、GPIO
P5:按钮A、GPIO
P6:LED行3、GPIO
P7:LED列4、GPIO
P8:预留
P9:LED列5、GPIO
P10:LED列6、GPIO
P11:按钮B、GPIO
P12:预留
P13:SPI时钟
P14:SPI数据输入
P15:SPI数据输出
P16:预留
P19:I2C数据
P20:I2C时钟

常见冲突场景

  • LED矩阵与GPIO使用冲突
  • 按钮引脚(P5/P11)与其他功能冲突
  • I2C/SPI总线与自定义外设冲突
  • 模拟输入与数字输出冲突

硬件层解决方案

禁用冲突功能

# 禁用LED矩阵以释放P3-P4,P6-P7,P9-P10
def safe_pin_write(pin, value):
    if pin in [pin3, pin4, pin6, pin7, pin9, pin10]:
        display.off()
        pin.write_digital(value)
        display.on()
    else:
        pin.write_digital(value)

引脚重映射

# I2C重映射到其他引脚
i2c.init(freq=100000, sda=pin1, scl=pin2)

# SPI重映射
spi.init(baudrate=1000000, mosi=pin16, miso=pin17, sclk=pin18)

使用非冲突引脚

优先使用无复用功能的引脚:

  • P0, P1, P2 (但注意LED列控制)
  • P8, P12, P13-P16, P19-P20

软件层解决方案

分时复用技术

import microbit

def run_led_matrix():
    display.on()
    display.show(Image.HEART)
    sleep(1000)
    display.off()

def read_sensor():
    # 在LED关闭时读取传感器
    return pin1.read_analog()

while True:
    run_led_matrix()
    sensor_value = read_sensor()
    # 处理传感器数据...
    sleep(1000)

中断优先级管理

from microbit import *

# 高优先级中断
def critical_irq():
    # 紧急处理代码
    pass

# 低优先级任务
def normal_task():
    # 非关键功能
    pass

# 配置中断优先级
pin0.irq(trigger=Pin.IRQ_RISING, handler=critical_irq, priority=1)

引脚状态缓存

pin_state_cache = {}

def safe_pin_write(pin, value):
    # 检查引脚状态
    if pin in pin_state_cache and pin_state_cache[pin] != value:
        # 解决冲突逻辑
        resolve_conflict(pin)
    
    pin.write_digital(value)
    pin_state_cache[pin] = value

高级冲突解决方案

多路复用器扩展

使用CD74HC4067等芯片扩展引脚:

# 控制多路复用器选择通道
def select_mux_channel(channel):
    pin8.write_digital(channel & 1)
    pin12.write_digital((channel >> 1) & 1)
    pin16.write_digital((channel >> 2) & 1)

# 读取16个模拟传感器
for ch in range(16):
    select_mux_channel(ch)
    value = pin2.read_analog()

I2C总线扩展

使用I2C GPIO扩展芯片(如PCF8574):

# 初始化I2C
i2c.init()

# PCF8574地址
PCF_ADDR = 0x20

# 设置扩展引脚输出
def set_expander_pins(value):
    i2c.write(PCF_ADDR, bytes([value]))

# 读取扩展引脚
def read_expander_pins():
    return i2c.read(PCF_ADDR, 1)[0]

虚拟引脚系统

class VirtualPin:
    def __init__(self, physical_pin):
        self.phys_pin = physical_pin
        self.mode = None
    
    def set_mode(self, mode):
        if self.mode and self.mode != mode:
            raise PinConflictError(f"Pin {self.phys_pin} mode conflict")
        self.mode = mode
    
    def write_digital(self, value):
        self.set_mode('digital_out')
        self.phys_pin.write_digital(value)
    
    def read_analog(self):
        self.set_mode('analog_in')
        return self.phys_pin.read_analog()

# 使用虚拟引脚
vpin0 = VirtualPin(pin0)

特定冲突场景解决方案

LED矩阵与传感器冲突

# 自定义LED刷新函数避免冲突
def safe_display_show(image):
    display.off()
    # 快速刷新LED
    for _ in range(5):  # 刷新5次保证可见
        display.show(image)
        sleep(50)
    display.off()

# 主循环
while True:
    sensor_val = pin1.read_analog()
    safe_display_show(Image.HEART)
    sleep(1000)

按钮与GPIO冲突

# 使用中断代替轮询
def button_a_handler():
    # 按钮A处理逻辑
    pass

# 安全配置按钮中断
if not pin5.is_touched():
    pin5.set_touch_mode(pin5.RESISTIVE)
    pin5.irq(trigger=pin5.IRQ_TOUCH, handler=button_a_handler)

I2C总线设备冲突

# I2C设备分时复用
def read_i2c_device(address, register):
    # 保存当前I2C状态
    saved_sda = i2c.sda
    saved_scl = i2c.scl
    
    # 配置I2C
    i2c.init(sda=pin1, scl=pin2)
    
    # 读取设备
    i2c.write(address, bytes([register]))
    data = i2c.read(address, 1)
    
    # 恢复I2C状态
    i2c.init(sda=saved_sda, scl=saved_scl)
    
    return data

调试与诊断工具

引脚状态监控

def print_pin_status():
    pins = [pin0, pin1, pin2, pin3, pin4, pin5, pin6, 
            pin7, pin8, pin9, pin10, pin11, pin12, 
            pin13, pin14, pin15, pin16, pin19, pin20]
    
    for i, p in enumerate(pins):
        try:
            mode = "IN" if p.get_mode() == 0 else "OUT"
            value = p.read_digital() if mode == "IN" else "-"
            print(f"P{i}: {mode} {value}")
        except:
            print(f"P{i}: Conflict!")

冲突检测算法

def detect_conflicts():
    # 检查LED引脚
    led_pins = [pin3, pin4, pin6, pin7, pin9, pin10]
    for p in led_pins:
        if p.read_digital() != 0 and display.is_on():
            print(f"LED conflict on P{led_pins.index(p)+3}")
    
    # 检查按钮引脚
    if pin5.read_digital() == 0 and button_a.is_pressed():
        print("Button A conflict")
    
    # 检查I2C引脚
    if pin19.read_digital() == 0 or pin20.read_digital() == 0:
        print("I2C pins in use")

最佳实践指南

引脚使用优先级

  • 优先使用P0、P1、P2(模拟功能)
  • 其次使用P8、P12、P13-P16
  • 最后考虑复用引脚(P3-P4,P6-P7,P9-P11)

无线电通信(radio)

Micro:bit 的无线电模块是其最强大的功能之一,允许设备之间进行无线通信。这个功能基于蓝牙低功耗(BLE)技术,但提供了更简单的抽象接口。

硬件基础架构

Micro:bit 的无线电功能通过主控芯片内置的射频模块实现:

版本 主控芯片 射频模块 关键特性
V1.5 Nordic nRF51822 2.4GHz 射频收发器 BLE 4.0,最大速率1Mbps
V2.0 Nordic nRF52833 增强型2.4GHz收发器 BLE 5.1,支持2Mbps高速模式

核心组件

  • 射频收发器:负责信号的调制/解调
  • 频率合成器:生成4GHz工作频率
  • 功率放大器:可配置发射功率(-20dBm至+4dBm)
  • 基带处理器:处理数据包和协议栈
  • 天线系统:PCB集成倒F天线(工作在4GHz)

无线电工作原理

发送过程

接收过程

核心技术特点

物理层深度解析

信号传播特性

  • 衍射:绕过障碍物(但金属会完全阻挡)
  • 反射:墙壁等表面反射引起多径干扰
  • 衰减:遵循自由空间路径损耗公式:
损耗(dB) = 32.44 + 20*log10(f) + 20*log10(d)
  • f=频率MHz
  • d=距离km

例如:2.4GHz@10米 ≈ 60dB损耗

实际性能指标

指标 V1.5 V2.0 测试条件
理论带宽 1Mbps 2Mbps 无干扰环境
实测吞吐量 80Kbps 210Kbps 32字节包长
有效距离 30米 70米 开阔场地
延迟 2-5ms 1-3ms 设备对传
功耗 发送:15mA
接收:12mA
发送:13mA
接收:10mA
功率等级0
同时连接 6-8台 12-16台 星型网络

与标准无线技术对比

特性 Micro:bit Radio Bluetooth BLE Wi-Fi Zigbee
拓扑结构 网状/星型 点对点/星型 星型 网状
连接建立 即时 需配对 需关联 需组网
适用距离 <100米 <100米 <100米 <100米
典型速率 200Kbps 1Mbps >1Mbps 250Kbps
功耗 极低 极低
抗干扰 中等

无线电模块基础

基本使用步骤

import radio  # 导入模块
radio.on()    # 启用无线电
radio.config(channel=7)  # 设置频道(0-100)

# 发送消息
radio.send("Hello Micro:bit!")

# 接收消息
incoming = radio.receive()
if incoming:
    display.scroll(incoming)

完整配置参数

radio.config(
    length=32,       # 消息长度(1-251字节)
    queue=3,         # 接收队列大小
    channel=7,       # 通信频道(0-100)
    power=6,         # 发射功率(0-7,7最强)
    data_rate=radio.RATE_1MBIT,  # 传输速率
    address=0x756269, # 地址(类似MAC地址)
    group=0,         # 组号(0-255)
    security=None    # 安全设置(V2新增)
)

重要参数说明

参数 范围 默认值 说明
channel 0-100 7 避免WiFi常用频道(1,6,11)
power 0-7 6 7=最大功率(+4dBm),0=最低功率(-30dBm)
data_rate RATE_250KBIT
RATE_1MBIT
RATE_2MBIT
RATE_1MBIT V2支持所有速率,V1仅支持1MBIT
group 0-255 0 逻辑分组,只接收同组消息
length 1-251 32 较大值增加吞吐量但降低可靠性

核心API详解

发送消息

# 发送字符串
radio.send("Temperature:25C")

# 发送字节数据
data = b'\x01\x02\x03\x04'
radio.send_bytes(data)

# 发送结构化数据(推荐)
import ustruct
packet = ustruct.pack('4sif', b"DATA", 42, 3.14)
radio.send_bytes(packet)

接收消息

# 接收字符串
msg = radio.receive()
if msg:
    print("Received:", msg)

# 接收字节数据
data = radio.receive_bytes()
if data:
    # 解析结构化数据
    id, value, temp = ustruct.unpack('4sif', data)

高级接收(V2)

# 接收完整数据包(含元数据)
packet = radio.receive_full()
if packet:
    payload, rssi, timestamp = packet
    print(f"Payload: {payload}, RSSI: {rssi}dBm, Time: {timestamp}ms")

通信协议设计

简单文本协议

# 发送端
radio.send(f"TEMP:{temperature()},LIGHT:{light_level}")

# 接收端
msg = radio.receive()
if msg and msg.startswith("TEMP:"):
    parts = msg.split(',')
    temp = float(parts[0].split(':')[1])
    light = int(parts[1].split(':')[1])

二进制协议

# 定义协议格式
# 字节0: 数据类型 (1=温度, 2=湿度...)
# 字节1-4: 浮点数值
# 字节5: 校验和

def create_packet(data_type, value):
    data = bytearray(6)
    data[0] = data_type
    data[1:5] = ustruct.pack('f', value)
    data[5] = sum(data[0:5]) & 0xFF  # 简单校验
    return data

# 解析数据
def parse_packet(data):
    if len(data) != 6 or sum(data[0:5]) & 0xFF != data[5]:
        return None  # 校验失败
    data_type = data[0]
    value = ustruct.unpack('f', data[1:5])[0]
    return (data_type, value)

安全通信(V2专有)

AES-128加密

from radio import security
import cryptolib

# 设置加密密钥(16字节)
key = b'MicrobitSecret!'
security.set_key(key)

# 启用加密
radio.config(security=security.AES)

# 发送加密数据(自动加密)
radio.send("Sensitive data")

# 接收时自动解密
msg = radio.receive()  # 已解密

地址过滤

# 设置允许的地址列表
allowed_addresses = [0x123456, 0x789ABC]
security.set_address_filter(allowed_addresses)

# 只接收来自这些地址的消息

高级技巧与优化

省电策略

# 间歇性唤醒
while True:
    radio.on()
    # 发送/接收数据
    radio.send("Ping")
    sleep(100)  # 等待响应
    
    radio.off()  # 关闭无线电省电
    sleep(9000)  # 休眠9秒

信号强度检测(RSSI

# V2支持接收信号强度指示
packet = radio.receive_full()
if packet:
    _, rssi, _ = packet
    # RSSI是负值,值越大信号越好(如-50比-70好)
    if rssi > -70:  # 良好信号
        display.show(Image.YES)

抗干扰技术

# 频道跳频
channels = [7, 23, 42, 56]
current_channel = 0

while True:
    radio.config(channel=channels[current_channel])
    # 通信...
    
    # 定期切换频道
    if button_a.was_pressed():
        current_channel = (current_channel + 1) % len(channels)

数据压缩

import zlib  # V2支持

# 发送压缩数据
data = "Long text message..." * 10
compressed = zlib.compress(data.encode())
radio.send_bytes(compressed)

# 接收端
compressed = radio.receive_bytes()
if compressed:
    data = zlib.decompress(compressed).decode()

调试与故障排除

常见问题

  • 无通信:检查频道、组号、无线电是否开启
  • 数据丢失:减少数据长度、降低传输速率
  • 干扰:避开WiFi频道(1,6,11)
  • 距离短:增加发射功率(config(power=7))

调试工具

# 无线电状态监测
def radio_status():
    print("Channel:", radio.config().get('channel', 'N/A'))
    print("Queue size:", len(radio.receive_bytes()))
    # V2特有
    if hasattr(radio, 'rssi'):
        print("RSSI:", radio.rssi())

性能测试

# 吞吐量测试
import time

radio.on()
radio.config(length=251, data_rate=radio.RATE_2MBIT)

start = time.ticks_ms()
count = 0
data = b'x' * 250  # 250字节数据

while time.ticks_diff(time.ticks_ms(), start) < 5000:  # 5秒测试
    radio.send_bytes(data)
    count += 1

蓝牙功能

Micro:bit 的蓝牙功能是其最强大的特性之一,允许设备与其他蓝牙设备(如手机、电脑)进行无线通信。

蓝牙功能概述

硬件支持

  • 5:支持蓝牙4.0(BLE)
  • 0:支持蓝牙5.0(BLE),兼容蓝牙4.0,提供更快的速度和更远的距离

核心功能

  • 与智能手机/平板配对通信
  • 无线编程(无需USB线)
  • 创建自定义蓝牙服务
  • 与其他Micro:bit通信(通过蓝牙而非无线电)
  • 低功耗模式(节省电池)

基础蓝牙操作

启用蓝牙

import bluetooth
bluetooth.init()  # 初始化蓝牙模块

设置设备名称

bluetooth.set_device_name("MyMicrobit")

开始广播

bluetooth.start_advertising(interval=200)  # 广播间隔200ms

检测连接状态

if bluetooth.is_connected():
    display.show(Image.HAPPY)
else:
    display.show(Image.SAD)

蓝牙配对与连接

手机配对流程

  • Micro:bit运行蓝牙程序
  • 手机蓝牙设置中搜索”MyMicrobit”
  • 配对连接(无需PIN码)
  • 使用蓝牙调试App(如nRF Connect)查看服务

连接管理

# 获取连接句柄
conn_handle = bluetooth.connection()

# 断开连接
bluetooth.disconnect()

创建蓝牙服务

定义服务UUID

from bluetooth import UUID

# 自定义服务UUID
SERVICE_UUID = UUID(0x180F)  
CHAR_UUID = UUID(0x2A19) 

创建特征

battery_char = bluetooth.Characteristic(
    CHAR_UUID,
    bluetooth.FLAG_READ,  # 只读特征
    value="50%",           # 初始值
    max_len=5              # 最大长度
)

创建服务

battery_service = bluetooth.Service(
    SERVICE_UUID,
    [battery_char],  # 包含的特征列表
    nbr_chars=1      # 特征数量
)

注册服务

bluetooth.add_service(battery_service)

数据通信

读取数据

# 更新特征值
bluetooth.update_char_value(battery_char, "75%")

# 在手机端读取将得到"75%"

写入数据

# 创建可写特征
led_char = bluetooth.Characteristic(
    UUID(0xFFE1),
    bluetooth.FLAG_WRITE,
    max_len=1
)

# 写入回调函数
def on_write(conn_handle, char_handle, value):
    if value == b'\x01':
        display.show(Image.YES)
    elif value == b'\x00':
        display.clear()

bluetooth.set_write_callback(on_write)

通知功能

# 创建支持通知的特征
temp_char = bluetooth.Characteristic(
    UUID(0x2A6E), 
    bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY
)

# 启用通知
bluetooth.char_notify_enable(temp_char)

# 更新值并通知
while True:
    temp = temperature()
    bluetooth.update_char_value(temp_char, f"{temp}C")
    sleep(5000)

无线编程(蓝牙DFU)

启用无线编程模式

# 在main.py中添加
import bluetooth
bluetooth.enable_irq(handler=None)
bluetooth.set_advertising(interval=200, name="MicrobitDFU")

手机端操作

  • 安装”Micro:bit”官方App
  • 搜索并连接Micro:bit
  • 选择hex文件上传
  • 等待编程完成(LED闪烁)

蓝牙与无线电协同

蓝牙网关

import bluetooth
import radio

radio.on()
bluetooth.init()

def on_bluetooth_data(data):
    # 将蓝牙数据转发到无线电
    radio.send(data)

def on_radio_data():
    # 将无线电数据转发到蓝牙
    data = radio.receive()
    bluetooth.send(data)

# 主循环
while True:
    if bluetooth.is_connected():
        data = bluetooth.receive()
        if data:
            on_bluetooth_data(data)
    
    if radio.any():
        on_radio_data()
    
    sleep(100)

高级功能

低功耗模式

# 配置低功耗参数
bluetooth.config(
    power=0,            # 最低发射功率
    interval=1000,       # 广播间隔1秒
    timeout=30           # 30秒无连接停止广播
)

# 深度睡眠
if not bluetooth.is_connected():
    bluetooth.stop_advertising()
    microbit.sleep(10000)  # 休眠10秒

安全配对

# V2支持安全配对
bluetooth.set_security(
    level=bluetooth.SECURITY_MEDIUM,
    bond=True,          # 绑定设备
    mitm=True           # 中间人保护
)

# 设置配对密码
bluetooth.set_passkey("123456")

多连接

# V2支持最多3个连接
if bluetooth.can_accept_connection():
    bluetooth.accept_connection()

调试与问题解决

常见问题

  • 无法连接:重启Micro:bit和手机蓝牙
  • 服务不可见:确认UUID设置正确
  • 数据丢失:减少数据包大小
  • 功耗过高:增加广播间隔

调试工具

# 打印蓝牙状态
def print_ble_status():
    print("Connected:", bluetooth.is_connected())
    print("Address:", bluetooth.address())
    print("RSSI:", bluetooth.rssi())
    print("Services:", bluetooth.list_services())

LED状态指示

  • 慢闪:广播中
  • 快闪:连接建立中
  • 常亮:已连接
  • 熄灭:未启用蓝牙

文件系统

Micro:bit 的文件系统是其重要功能之一,特别是在 V2 版本中得到了显著增强。以下是对 Micro:bit 文件系统的详细介绍:

文件系统基础

硬件支持

  • 5:
    • 无专用文件系统存储
    • 可通过特殊技巧模拟文件操作(有限)
  • 0:
    • 512KB Flash 存储器
    • 其中 256KB 专用于文件系统
    • FAT 格式兼容文件系统

文件系统特性

特性 V1.5 V2.0
存储空间 无专用空间 256KB
文件数量限制 最多约100个文件
文件大小限制 最大64KB
持久存储 重启后丢失 断电保持
USB访问 不支持 支持(MAINTENANCE模式)

文件系统访问方式

USB 访问模式

  • 按住复位按钮
  • 连接USB线
  • 释放复位按钮
  • 电脑显示为”MAINTENANCE”驱动器
  • 可直接拖放文件操作

Python API 访问

import os

# 列出文件
files = os.listdir()
print(files)

# 创建文件
with open('data.txt', 'w') as f:
    f.write("Hello Microbit!")

# 读取文件
with open('data.txt', 'r') as f:
    content = f.read()
    print(content)

# 删除文件
os.remove('old.txt')

文件系统管理技巧

空间优化

# 定期清理旧文件
MAX_FILES = 10
MAX_SIZE = 100 * 1024  # 100KB

def cleanup_files():
    files = sorted(os.listdir(), key=os.size, reverse=True)
    total_size = sum(os.size(f) for f in files)
    
    # 删除最旧的文件直到满足限制
    while len(files) > MAX_FILES or total_size > MAX_SIZE:
        oldest = min(files, key=os.stat)
        size = os.size(oldest)
        os.remove(oldest)
        files.remove(oldest)
        total_size -= size

# 每周清理一次
if running_time() % (7 * 24 * 3600 * 1000) < 1000:
    cleanup_files()

错误处理

def safe_file_op(func, *args):
    try:
        return func(*args)
    except OSError as e:
        if e.args[0] == 28:  # ENOSPC
            display.show(Image.SAD)
            return "存储空间不足"
        elif e.args[0] == 2:  # ENOENT
            return "文件不存在"
        else:
            return f"错误: {e}"

# 安全写入
result = safe_file_op(lambda: open('data.txt', 'w').write("test"))

文件系统检查

def check_fs_integrity():
    files = os.listdir()
    for f in files:
        try:
            with open(f, 'r') as test_file:
                test_file.read(1)
        except OSError:
            print(f"损坏文件: {f}")
            os.remove(f)
    
    # 检查剩余空间
    usage = os.statvfs('/')
    if usage[3] < 10:  # 少于10个块
        display.show(Image.SKULL)

V1.5 文件系统模拟

EEPROM 模拟

# V1.5使用Flash模拟EEPROM
import microbit

# 写入数据
microbit.storage.store("key", "value")

# 读取数据
value = microbit.storage.load("key")

# 删除数据
microbit.storage.remove("key")

文件系统模拟

# 简单的键值存储模拟文件系统
FILE_SYSTEM = {}

def v1_write_file(name, content):
    FILE_SYSTEM[name] = content

def v1_read_file(name):
    return FILE_SYSTEM.get(name, None)

def v1_list_files():
    return list(FILE_SYSTEM.keys())

注意事项与最佳实践

  • 写寿命管理:
    • Flash芯片有约10万次擦写寿命
    • 避免高频写入同一位置
    • 使用追加模式而非覆盖
  • 电源安全:
    • 写入时避免断电
    • 使用sync()确保数据写入
with open('important.dat', 'w') as f:
    f.write(data)
    os.sync()  # 强制写入物理存储
  • 文件命名规范:
    • 使用3格式(主名8字符,扩展名3字符)
    • 避免特殊字符
    • 使用小写字母
  • 性能优化:
    • 批量写入减少文件操作
    • 使用二进制格式提高效率
    • 避免频繁打开/关闭文件
  • 安全考虑:
    • 敏感数据加密存储
    • 验证文件完整性
    • 限制文件访问权限

参考链接:BBC micro:bit MicroPython documentation — BBC micro:bit MicroPython 1.1.1 documentation

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注