You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Microbit串口uart.read()丢字节问题求助

Micro:bit串口接收大字节数据丢包问题排查与解决

问题现象

向Micro:bit发送8字节数据时可完整接收,但发送12字节及以上数据时接收状态不稳定:16字节数据有时能成功接收,22字节数据则从未成功。怀疑串口会拆分接收的数据,但拼接各数据段后仍存在丢字节情况。

原始代码

from microbit import *

count = 0

def show_count_on_leds(c, brightness):
    display.clear()
    for i in range(min(c, 25)):
        x = i % 5
        y = i // 5
        display.set_pixel(x, y, brightness)
    
buffer = b""
    
while True:
    sleep(10)
    if uart.any():
        incoming = uart.read()
        if incoming:
            buffer += incoming
            count += len(incoming)
        
            if buffer and buffer[0] == ord('A') and buffer[-1] == ord('Z'):
                show_count_on_leds(count, 9)
                count = 0
                buffer = b""

问题原因

  1. 串口缓冲区溢出:Micro:bit默认UART缓冲区容量有限,发送大字节数据时,循环中sleep(10)的延迟加上LED显示操作的耗时,会导致程序无法及时读取串口数据,缓冲区满后新数据直接被丢弃。
  2. 帧同步逻辑不完善:当前代码仅检查缓冲区首尾是否为'A'和'Z',如果之前的残留数据未清空,或者数据拆分后某次接收的结尾不是'Z',会导致缓冲区积累无效数据,后续正确数据也无法触发处理逻辑。
  3. 固定延迟导致数据堆积:sleep(10)让程序每10ms才检查一次串口,大流量数据发送时,这段时间内串口缓冲区可能已经塞满,造成丢包。

解决办法

1. 增大串口缓冲区

初始化UART时指定更大的缓冲区,减少溢出概率:

uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=pin0, rx=pin1, buffersize=128)

2. 优化帧同步与错误处理

  • 自动丢弃缓冲区开头的无效数据,直到找到帧起始符'A';
  • 增加超时机制,长时间未收到完整帧时重置缓冲区,避免无效数据堆积。

3. 减少循环延迟

去掉或缩短固定sleep,让程序更频繁地检查串口数据,避免数据堆积。

4. 优化LED显示操作

减少显示函数的耗时,避免占用过多处理时间影响串口读取。

5. 增加接收确认机制

Micro:bit收到完整帧后向发送端返回确认信号,发送端确认后再发送下一包,避免连续发送导致数据溢出。

修改后的示例代码

from microbit import *

# 初始化UART,增大缓冲区至128字节
uart.init(baudrate=9600, bits=8, parity=None, stop=1, tx=pin0, rx=pin1, buffersize=128)

count = 0
buffer = b""
last_receive_time = running_time()

def show_count_on_leds(c, brightness):
    display.clear()
    max_pixels = min(c, 25)
    for i in range(max_pixels):
        x = i % 5
        y = i // 5
        display.set_pixel(x, y, brightness)

while True:
    if uart.any():
        incoming = uart.read()
        if incoming:
            buffer += incoming
            count += len(incoming)
            last_receive_time = running_time()
            
            # 丢弃开头的无效数据,直到找到起始符'A'
            while len(buffer) > 0 and buffer[0] != ord('A'):
                buffer = buffer[1:]
                count -= 1
            
            # 检查是否收到完整帧(结尾为'Z')
            if buffer and buffer[-1] == ord('Z'):
                show_count_on_leds(count, 9)
                # 发送接收确认信号
                uart.write(b'OK')
                count = 0
                buffer = b""
    
    # 超时处理:1秒未收到新数据则重置缓冲区
    if running_time() - last_receive_time > 1000 and len(buffer) > 0:
        count = 0
        buffer = b""

内容的提问来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:23:12