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

MicroPython下4位共阴7段屏多路复用API请求闪屏问题求助

解决Raspberry Pi Pico W多路复用显示时API请求阻塞黑屏的问题

核心思路

将温度获取(网络IO操作)与显示刷新(硬件扫描操作)彻底解耦,用后台任务定期更新温度数据,主线程仅负责读取现成数据并执行多路复用显示,从根源避免显示循环被网络请求阻塞。

可行实现方案

方案1:使用_thread后台线程(推荐)

利用MicroPython的_thread模块开启独立线程,专门处理API请求和温度更新,主线程专注于显示刷新,两者互不干扰。

代码示例

import machine
import _thread
import urequests
import time

# 全局变量存储当前温度:主线程只读,后台线程负责更新
current_temp = 0.0
UPDATE_INTERVAL = 10  # 温度更新间隔(单位:秒)

# 数码管硬件引脚定义(根据实际接线调整)
# 共阴7段引脚(a~g + 小数点,对应bit0~bit7)
SEG_PINS = [
    machine.Pin(0, machine.Pin.OUT), machine.Pin(1, machine.Pin.OUT),
    machine.Pin(2, machine.Pin.OUT), machine.Pin(3, machine.Pin.OUT),
    machine.Pin(8, machine.Pin.OUT), machine.Pin(9, machine.Pin.OUT),
    machine.Pin(10, machine.Pin.OUT), machine.Pin(11, machine.Pin.OUT)
]
# 4位选通引脚(共阴逻辑:低电平点亮对应数码管)
DIGIT_PINS = [
    machine.Pin(4, machine.Pin.OUT), machine.Pin(5, machine.Pin.OUT),
    machine.Pin(6, machine.Pin.OUT), machine.Pin(7, machine.Pin.OUT)
]

# 共阴7段码定义
SEG_CODES = {
    '0': 0x3F, '1': 0x06, '2': 0x5B, '3': 0x4F,
    '4': 0x66, '5': 0x6D, '6': 0x7D, '7': 0x07,
    '8': 0x7F, '9': 0x6F, '.': 0x80
}

def temp_update_thread():
    """后台线程:定期从API拉取温度并更新全局变量"""
    global current_temp
    temp_url = "你的温度API地址"
    while True:
        try:
            resp = urequests.get(temp_url)
            temp_data = resp.json()
            current_temp = temp_data["temperature"]  # 根据API返回结构调整键名
            resp.close()  # 必须关闭响应,避免内存泄漏
        except Exception as e:
            # 网络请求失败时,保留当前温度并打印错误
            print(f"温度更新失败: {str(e)}")
        time.sleep(UPDATE_INTERVAL)

def display_temp(temp):
    """多路复用扫描显示当前温度"""
    # 格式化温度为4位显示字符串(示例:25.3 → ["0", "2", "5.", "3"])
    temp_str = f"{temp:.1f}".zfill(4)
    display_chars = list(temp_str)
    # 给第三位添加小数点(可根据需求调整位置)
    if '.' not in display_chars:
        display_chars[2] += '.'
    
    # 执行多路复用扫描
    for idx in range(4):
        # 先关闭所有数码管
        for dp in DIGIT_PINS:
            dp.value(1)
        # 获取当前位的段码
        char = display_chars[idx]
        if '.' in char:
            base_char = char.replace('.', '')
            seg_code = SEG_CODES[base_char] | SEG_CODES['.']
        else:
            seg_code = SEG_CODES.get(char, 0x00)
        # 设置7段引脚电平
        for seg_idx in range(8):
            SEG_PINS[seg_idx].value((seg_code >> seg_idx) & 1)
        # 点亮当前数码管
        DIGIT_PINS[idx].value(0)
        # 延时1ms(平衡亮度与闪烁感)
        time.sleep_ms(1)

# 启动后台温度更新线程
_thread.start_new_thread(temp_update_thread, ())

# 主线程:持续执行显示循环
while True:
    display_temp(current_temp)

关键注意点

  • 后台线程的time.sleep()不会阻塞主线程的显示循环
  • 必须关闭urequests的响应对象,防止内存泄漏
  • 异常捕获确保网络故障时程序不会崩溃,保持原有温度显示

方案2:使用定时器中断

利用Pico的硬件定时器定期触发温度更新回调,同样实现显示与网络操作的解耦。

代码示例

import machine
import urequests
import time

current_temp = 0.0
UPDATE_INTERVAL = 10 * 1000  # 毫秒级更新间隔

# 数码管引脚与段码定义同方案1,省略重复代码

def temp_update_callback(timer):
    """定时器回调:更新温度数据"""
    global current_temp
    temp_url = "你的温度API地址"
    try:
        resp = urequests.get(temp_url)
        current_temp = resp.json()["temperature"]
        resp.close()
    except Exception as e:
        print(f"更新失败: {str(e)}")

# 初始化定时器:周期性触发回调
timer = machine.Timer(-1)
timer.init(period=UPDATE_INTERVAL, mode=machine.Timer.PERIODIC, callback=temp_update_callback)

# 主线程显示循环
while True:
    display_temp(current_temp)

注意点

  • 定时器回调函数中避免过长时间的阻塞操作(如网络超时),否则可能导致回调堆叠
  • 若API请求耗时超过定时器间隔,建议改用线程方案更稳定

额外优化建议

  • 调整多路复用的延时时间(1~2ms),平衡数码管亮度与闪烁感
  • 对温度数据做防抖处理(如连续两次获取差值超过阈值才更新),避免显示频繁跳动
  • 给API请求添加超时参数:urequests.get(temp_url, timeout=2),减少极端情况下的阻塞时间

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 12:31:03