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
相关产品推荐
相关产品推荐

