ESP32-CAM 中断处理程序(Interrupt Service Routine)

ESP32-CAM 中断处理程序(Interrupt Service Routine)

在合适的硬件上,MicroPython 提供了用 Python 编写中断处理程序的能力。中断处理程序——也称为中断服务程序 (ISR)——被定义为回调函数。这些是为了响应诸如定时器触发引脚上的电压变化之类的事件而执行的。此类事件可能发生在程序代码执行过程中的任何一点。这会带来重大后果,其中一些是 MicroPython 语言特有的。其他的对于能够响应实时事件的所有系统都是通用的。

下面详述的要点并列出了中断处理程序代码的主要建议。

  • 保持代码尽可能简短。
  • 避免内存分配:没有附加到列表或插入字典,没有浮点数。
  • 考虑使用micropython.schedule 来解决上述约束。
  • 在 ISR 返回多个字节的情况下,使用预先分配的bytearray. 如果要在 ISR 和主程序之间共享多个整数,请考虑使用数组 (array.array)。
  • 如果主程序和 ISR 之间共享数据,请考虑在访问主程序中的数据之前禁用中断并在之后立即重新启用它们。
  • 分配一个紧急异常缓冲区。

紧急异常缓冲区

如果 ISR 中发生错误,MicroPython 无法生成错误报告,除非为此目的创建特殊缓冲区。如果以下代码包含在使用中断的任何程序中,调试将得到简化。紧急异常缓冲区只能保存一个异常堆栈跟踪。这意味着,如果在堆被锁定的情况下处理异常期间抛出第二个异常,则第二个异常的堆栈跟踪将替换原来的堆栈跟踪 - 即使第二个异常得到了干净的处理。如果稍后打印缓冲区,这可能会导致混淆异常消息。

import micropython
micropython.alloc_emergency_exception_buf(100)

简单

出于各种原因,保持 ISR 代码尽可能短和简单很重要。它应该只做在导致它的事件之后必须立即做的事情:可以延迟的操作应该委托给主程序循环。

例外

如果 ISR 引发异常,它不会传播到主循环。除非异常由 ISR 代码处理,否则中断将被禁用。

中断处理程序设计

ISR 应该设计得尽可能简单。他们应该总是在很短的、可预测的时间内返回。这很重要,因为当 ISR 运行时,主循环不是:主循环不可避免地会在代码中的随机点执行暂停。这种暂停可能是难以诊断错误的来源,特别是如果它们的持续时间很长或可变。
中断是根据优先级方案组织的。ISR 代码本身可能会被更高优先级的中断所中断。如果两个中断共享数据,这会产生影响。
应该避免或最小化循环结构。通常应避免对中断设备以外的设备进行 I/O:磁盘访问、print 语句和 UART 访问等 I/O相对较慢,其持续时间可能会有所不同。这里的另一个问题是文件系统函数不可重入:在 ISR 和主程序中使用文件系统 I/O 会很危险。至关重要的是,ISR 代码不应等待事件。
代码关键部分的一个例子是访问多个可能受 ISR 影响的变量。如果在访问各个变量之间碰巧发生中断,则它们的值将不一致。这是一个被称为竞争条件的危险实例:ISR 和主程序循环竞争改变变量。为避免不一致,必须采用一种方法来确保 ISR 在关键部分的持续时间内不会改变值。实现此目的的一种方法是 disable_irq() 在该部分开始之前和 enable_irq() 结束时发出。

定时器与引脚触发示例

from machine import Timer, Pin
import utime
# 紧急异常缓冲区
import micropython
micropython.alloc_emergency_exception_buf(100)
# LED状态反转
def toggle_led(led_pin):
    led_pin.value(not led_pin.value())


def led_blink_timed(timer, led_pin, millisecond):
    '''
    led 按照特定的频率进行闪烁
    LED闪烁周期 = 1000ms / 频率
    状态变换间隔(period) = LED闪烁周期/ 2 
    '''
    # 计算状态变换间隔时间 ms
    period = int(0.5 * millisecond)
    # 初始化定时器
    # 这里回调是使用了lambada表达式,因为回调函数需要传入led_pin
    timer.init(period=period, mode=Timer.PERIODIC, callback=lambda t: toggle_led(led_pin))


# 声明引脚 D2 作为LED的引脚
led_pin = Pin(33, Pin.OUT)
timer = Timer(1)  # 创建定时器对象
# 定时器触发
led_blink_timed(timer, led_pin, millisecond=500)
# 引脚上的电压变化触发
led_pin.irq(trigger=Pin.IRQ_FALLING, handler=lambda t:print("IRQ_FALLING"))

参考资料

  • mPython help documentation, https://mpython.readthedocs.io/en/master/index.html
  • MicroPython 文档, http://micropython.86x.net/en/latet/index-2.html
  • MicroPython documentation, https://docs.micropython.org/en/latest/index.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值