编写中断处理程序 — MicroPython 1.13 文档 (youvtec.com)
代码的临界区的示例是访问多个变量,这些变量受ISR影响。若中断在对单个变量的访问间发生,则其值将会不一致。 这是一种叫作”竞态条件”的问题的实例:ISR和主程序循环争相修改变量。为避免不一致性,必须采取一种方法来确保ISR不会在临界区持续过程中修改值。 实现此目的的方式之一是在临界区开始前发出 pyb.disable_irq()
,并在其结束时发出 pyb.enable_irq()
。这是此方法的示例:
import pyb, micropython, array
micropython.alloc_emergency_exception_buf(100)
class BoundsException(Exception):
pass
ARRAYSIZE = const(20)
index = 0
data = array.array('i', 0 for x in range(ARRAYSIZE))
def callback1(t):
global data, index
for x in range(5):
data[index] = pyb.rng() # simulate input
index += 1
if index >= ARRAYSIZE:
raise BoundsException('Array bounds exceeded')
tim4 = pyb.Timer(4, freq=100, callback=callback1)
for loop in range(1000):
if index > 0:
irq_state = pyb.disable_irq() # Start of critical section
for x in range(index):
print(data[x])
index = 0
pyb.enable_irq(irq_state) # End of critical section
print('loop {}'.format(loop))
pyb.delay(1)
tim4.callback(None)
临界区可包含一行代码和一个变量。思考以下的代码碎片。
count = 0
def cb(): # An interrupt callback
count +=1
def main():
# Code to set up the interrupt callback omitted
while True:
count += 1
此示例说明了故障的潜在原因。主循环中的 count += 1
行携带了一个称为”读-修改-写”的特定的竞态条件问题。这是实时系统中故障的典型原因。 在主循环中,读取 t.counter
值,将其增加1,并写回。在少数情况下,中断发生在读取后、写入前。中断更改 t.counter
,但其改变在ISR返回时被主循环覆盖。 在实时系统中,这可能会导致极少的、难以预测的故障。
如上所述,若在主代码中修改了Python内置类型的实例或在ISR中访问实例,则应多加注意。执行更改的代码应被视为临界区,以确保ISR运行时实例处于有效状态。
micropython.schedule(func, arg)
将执行的函数调度为“非常快速”。该函数传递arg值作为其唯一参数。“非常快速”意味着运行时间将尽其所能尽早执行该函数,假定运行尽可能高效,以下条件依然有效:
- 预定函数不会抢占另一预定函数。
- 预定函数总在“操作码之间”执行,也就意味着所有基本Python操作(例如添加一个列表)都确保为极小的。
- 给定端口可能会定义“临界区”,预定函数不会在该区域中执行。函数可能在临界区内预定,但函数只在退出该区域后才会执行。临界区一个例子即抢占中断处理程序(一个IRQ)。
该函数可用来从抢占IRQ中预定回调。这样的IRQ对IRQ(例如,堆可能被锁定)中运行的代码进行了限制,并预定一个稍后会回调的函数能够接触这些限制。
有一个用来存放预定函数的堆栈,若堆栈已满,则 schedule 会引发 RuntimeError 。
How to use micropython.schedule effectively
How to use micropython.schedule effectively - MicroPython Forum (Archive)
from pyb import Timer
import micropython
import time
def cb(arg): # Scheduled callback
print(arg)
def cb1(tim): # Hard IRQ
micropython.schedule(cb, 'Timer 1')
def cb2(tim):
micropython.schedule(cb, 'Timer 2')
t1 = Timer(1, freq=1.1, callback=cb1)
t2 = Timer(2, freq=1, callback=cb2)