一、什么是ISR?
ISR (Interrupt Service Routine) 是在硬件中断触发时执行的一段代码。中断是硬件事件,它允许处理器暂停当前任务,转而执行对特定事件的响应代码。
主要特点:
触发条件:当某些硬件外设(例如定时器、外部引脚、串口接收数据等)触发中断时,ISR 会被调用。
优先级和响应:ISR 通常具有较高的优先级,因此它能够中断正在执行的任务或代码。
执行方式:ISR 中的代码必须尽可能短小,以尽快释放中断,让主程序能够继续执行。
ISR 基本规则
ISR 基本规则
尽量简短
ISR 中应尽可能只做状态更新、计数器累加或触发事件。
不应做耗时操作(如打印、延时、网络请求、I/O)。
禁止阻塞操作
不能在 ISR 中使用
time.sleep()、while等会阻塞 CPU 的操作。不能在 ISR 中使用常规的锁(Lock)、信号量(Semaphore)等可能阻塞的对象。
可使用的原子操作
对整数的赋值和布尔状态更新是原子操作(尤其是 32 位整数)。
对于复合操作(如
x += 1),如果不保证原子性,可能会出现竞态。
注意事项:
不可阻塞:ISR 不能调用可能阻塞的函数,如
sleep或等待其他资源。不可进行复杂操作:由于 ISR 必须尽快完成,通常不推荐在 ISR 中执行复杂的计算或操作,特别是那些涉及到动态内存分配的操作。
共享资源访问:如果 ISR 访问共享资源,可能会导致数据竞争问题,必须通过互斥锁、原子操作等手段避免。
二、什么是原子操作?
原子操作(Atomic Operation)是指在执行过程中不可被中断、不可被分割的操作,要么全部完成,要么完全不做。
1、原子操作的特性
不可中断,在多任务 / 中断环境下,不会因为中断或任务切换而被打断
一致性,对共享变量的修改是“要么完成,要么不完成”
最小粒度,通常是 CPU 支持的基本操作(读 / 写单个寄存器、加减整数)
2、常见的原子操作示例
1️⃣ 简单变量赋值(在 MCU 上通常是原子)
irq_flag = True
irq_count += 1 # 在某些 32-bit MCU 上单次加法也是原子条件:
变量大小 ≤ CPU 数据总线宽度(8/16/32 bit)
没有复杂操作(例如 += 包含读 - 改 - 写,需要注意 MCU 架构)
2️⃣ 位操作(单独一条指令)
result = a & b # 按位与(AND)&
result = a | b # 按位或(OR)|
result = a ^ b # 按位异或(XOR)^
result = ~a # 按位取反(NOT)~
result = a << 2 # 左移(Shift Left)<<
result = a >> 2 # 右移(Shift Right)>>
result = a & mask # 掩码操作
packed = (status << 4) | command # 位域(Bit fields)3️⃣ CPU 特殊指令
通过 machine.mem32 来访问和修改内存地址上的数据
import machine
# 访问指定的内存地址,通常是 CPU 特定寄存器
machine.mem32[0x3FF5A000] = 0x12345678 # 写入特定的寄存器
value = machine.mem32[0x3FF5A000] # 读取寄存器的值
print(hex(value))控制寄存器与中断管理
import machine
# 设置一个引脚产生中断
pin = machine.Pin(15, machine.Pin.IN, machine.Pin.IRQ_RISING)
# 中断服务程序
def irq_handler(pin):
print("Interrupt triggered")
# 设置中断处理函数
pin.irq(trigger=machine.Pin.IRQ_RISING, handler=irq_handler)处理器状态寄存器
import machine
# 进入深度睡眠模式
machine.deepsleep(5000) # 等待5秒后恢复三、MicroPython 提供的 ISR 安全接口
1、Pin 中断
Pin.irq()会将handler注册为 ISR。trigger可选:IRQ_RISING、IRQ_FALLING或IRQ_RISING | IRQ_FALLING。
2、micropython.schedule()
用于在 ISR 中“延迟执行”复杂操作。
ISR 内只做轻量操作,然后调用
micropython.schedule()把复杂任务交给主线程执行。
限制:schedule 函数最多只能有 32 个任务排队(具体视 MicroPython 版本)。
参数必须是小整数或小对象,避免大型对象。
import micropython
def deferred_task(arg):
# 这里可以安全执行复杂操作,如打印、I/O
print("Deferred task:", arg)
def irq_handler(pin):
micropython.schedule(deferred_task, 42)
pin = Pin(15, Pin.IN)
pin.irq(trigger=Pin.IRQ_RISING, handler=irq_handler)3、原子操作指令
整数赋值或状态机切换
可以暂时禁用中断,保证原子性操作。
micropython.disable_irq()/micropython.enable_irq()
4、共享数据
ISR 内共享数据建议使用整数、布尔量、列表或数组的单个元素。
对于多字节数据,使用
micropython.schedule()来保证安全。
四、ISR 中不能做,禁止的操作
文件 I/O
网络请求
分配大量内存(避免触发垃圾回收)
print()(ESP32 可以少量打印,但不安全)阻塞锁、事件等待
五、总结
1、可执行操作
2、禁止操作
3、共享数据策略
使用整数或布尔值:单次写入通常是原子操作。
复杂对象:使用
micropython.schedule()延迟处理。复合操作使用
disable_irq():
irq_state = micropython.disable_irq()
counter += 1
micropython.enable_irq(irq_state)4、平台特定 ISR 技巧
ESP32
可直接操作寄存器:
machine.mem32。可操作 GPIO、定时器寄存器。
支持
micropython.schedule()延迟任务。
STM32
可访问
machine.mem32或pyb模块。可通过 Timer / UART ISR 实现高速采样。