MicroPython实现GPIO控制函数指定时机后台精准运行方法
MicroPython GPIO精准后台定时实现方案
问题本质
当前代码属于阻塞式顺序执行逻辑:主循环按顺序执行calc_one_two()→func()→some_other_actions(),只要some_other_actions()这类耗时任务在运行,后续的GPIO控制逻辑必须等它完全执行完才能启动;哪怕在func()里用time.sleep_ms()做延时,本质还是CPU空等阻塞,无法实现和其他耗时任务并行、精准时间点触发的需求。
原阻塞式问题代码如下:
import time from machine import Pin a_1 = Pin(21, Pin.OUT) a_2 = Pin(20, Pin.OUT) def do_something(x): print(x) def some_other_actions(): time.sleep(10) def calc_one_two(): return 1, 2 def func(a, b, on_tmr=2, off_tmr=1): a_1.on() do_something(a) time.sleep_ms(on_tmr) # sleep for 2ms a_1.off() time.sleep_ms(off_tmr) # sleep for 1ms a_2.on() do_something(b) time.sleep_ms(on_tmr) # sleep for 2ms a_2.off() time.sleep_ms(off_tmr) # sleep for 1ms while True: one, two = calc_one_two() func(one, two) some_other_actions() # actions that need some time
实现方法
用MicroPython内置的硬件定时器machine.Timer实现后台精准调度,硬件定时器由芯片内置定时器外设驱动,定时触发不受主循环阻塞任务影响,到点会自动抢占执行回调函数,从根源解决主循环阻塞导致的时序偏移问题。
改造后可直接运行的代码
import time from machine import Pin, Timer # 硬件初始化 a_1 = Pin(21, Pin.OUT) a_2 = Pin(20, Pin.OUT) tim = Timer(0) # 调用硬件定时器0,不同芯片定时器编号可按需调整 # 时序状态机参数 current_step = 0 ON_DURATION = 2 # 高电平持续2ms OFF_DURATION = 1 # 低电平间隔1ms step_trigger_flag = 0 # 主从逻辑传递事件的标志位 a_val = 0 b_val = 0 def do_something(x): print(x) def some_other_actions(): time.sleep(10) def calc_one_two(): return 1, 2 # 定时器回调,1ms触发一次,仅执行微秒级快操作 def tmr_callback(t): global current_step, step_trigger_flag # 时序周期共6ms:a1高2ms→低1ms→a2高2ms→低1ms循环 if current_step == 0: # 0ms位置:a1拉高 a_1.on() step_trigger_flag = 1 current_step += 1 elif current_step == ON_DURATION: # 2ms位置:a1拉低 a_1.off() current_step += 1 elif current_step == ON_DURATION + OFF_DURATION: # 3ms位置:a2拉高 a_2.on() step_trigger_flag = 2 current_step += 1 elif current_step == ON_DURATION + OFF_DURATION + ON_DURATION: # 5ms位置:a2拉低 a_2.off() current_step += 1 elif current_step == ON_DURATION*2 + OFF_DURATION*2: # 6ms位置:重置状态进入下一轮循环 current_step = 0 else: current_step += 1 # 初始化定时器,周期1ms循环触发 tim.init(period=1, mode=Timer.PERIODIC, callback=tmr_callback) # 主循环,执行耗时任务不会影响GPIO时序精度 while True: one, two = calc_one_two() a_val, b_val = one, two # 检测定时器置位标志,执行打印等慢操作 if step_trigger_flag == 1: do_something(a_val) step_trigger_flag = 0 elif step_trigger_flag == 2: do_something(b_val) step_trigger_flag = 0 # 哪怕此处休眠10s,GPIO输出时序依然精准运行 some_other_actions()
关键注意事项
- 定时器回调运行在中断上下文,绝对不能在回调里放耗时操作:包括
print()、time.sleep()、内存分配、文件读写等,否则会导致时序抖动、系统崩溃,仅保留GPIO翻转、变量赋值这类几微秒就能完成的操作 - 日志打印、复杂计算这类慢逻辑,通过标志位传递到主循环执行即可,不会影响GPIO控制精度
- 硬件定时器的定时精度通常在10微秒以内,完全满足毫秒级GPIO时序要求,不会被主循环的长耗时任务阻塞
- 不同型号MicroPython板卡的可用硬件定时器数量有差异,若定时器0被占用可更换其他编号
内容的提问来源于stack exchange,提问作者0livaw
相关产品推荐
相关产品推荐

