查看: 975|回复: 1

[MicroPython] ESP32 MicroPython教程:定时器中断

[复制链接]

简 介
本文主要介绍如何对运行在ESP32之上的MicroPython进行定时器中断的配置。有关ESP32定时器硬件的更多详情,请看这篇帖子: ESP32 Arduino:定时器中断 的第二部分

测试是使用集成在FireBeetle ESP32开发板中的DFRobot的ESP-WROOM-32模块上进行的。使用软件是MicroPython IDE uPyCraft。

代 码
首先需要导入machine模块,以使用与定时器中断配置和处理相关的函数。

[AppleScript] 纯文本查看 复制代码
import machine

接下来,声明一个计数器,定时器中断函数将使用这个计数器告知主代码中断已发生。之所以采取这种方式,主要是因为中断运行速度非常快,不应在中断内进行函数调用(比如print)。
当中断发生时,中断处理函数只是简单地让计数器递增,我们在中断函数外边使用循环对计数器的数值进行检查,并做出相应的操作。

[AppleScript] 纯文本查看 复制代码
interruptCounter = 0

我们还会再定义一个计数器(http://docs.micropython.org/en/latest/library/machine.Timer.html),用于保存自程序开始运行以来所发生的所有中断,以便将每一个新发生的中断计数值打印出来。

[AppleScript] 纯文本查看 复制代码
totalInterruptsCounter = 0

接着,新建一个Timer类的对象,这个类位于machine模块中。我们将使用这个对象对定时器中断进行配置。
该类的构造函数可接收一个数值参数(0到3),表示所要使用的定时器硬件(ESP32共有4种定时器硬件)。本例将使用定时器0。

[AppleScript] 纯文本查看 复制代码
timer = machine.Timer(0)

然后,声明一个叫做handleInterrupt的中断处理函数。该函数的输入参数是当中断被触发时的一个Timer类对象,但是在我们的代码中不会用到它。
函数内部逻辑非常简单,只是不断地递增interruptCounter变量。鉴于我们将对这个全局变量进行操作和修改,因此需要使用global关键字对其进行声明,然后才能使用。

[AppleScript] 纯文本查看 复制代码
def handleInterrupt(timer):
  global interruptCounter
  interruptCounter = interruptCounter+1

声明完中断处理函数之后,调用先前所创建Timer对象的init方法,以对定时器进行初始化。
该函数的输入参数包括中断周期(单位为毫秒)、定时器模式(一次性还是周期性)以及负责处理中断的回调函数。
本例将定时器设置为周期性运行(每秒一次)。所以周期参数就是1000,定时器模式参数是Timer类的PERIODIC常量。对于一次性定时器,只需将模式参数改成Timer类的ONE_SHOT常量即可。
最后,在回调参数中,把先前声明的中断处理函数传给它即可。

[AppleScript] 纯文本查看 复制代码
timer.init(period=1000, mode=machine.Timer.PERIODIC, callback=handleInterrupt)

现在定时器已经启动,我们再来看其他代码。如前所述,根据ISR发出的中断信号,我们将在主代码中对中断进行处理。由于例程非常简单,我们只是在一个无限循环中对interruptCounter变量进行轮询,以确定其值是否大于0。如果大于0,那就表示我们有中断需要处理。
当然,在实际的应用程序中,通常会需要进行其他计算,而不会仅仅对这个变量进行轮询。
如果检测到了中断,我们就需要使interruptCounter变量递减,表示我们将要对其进行处理。因为这个变量是与ISR共享的变量,为了避免冲突,递减操作需要在一个禁用中断的关键代码段内执行。
当然,这个关键代码段应该越短越好,然后就要重新使能中断。只有变量递减操作在关键代码段内执行,其余处理都在重新使能中断后的关键代码段之外进行。
所以,先通过调用machine模块的disable_irq函数将中断禁用。该函数会返回先前的IRQ状态,我们把它保存在一个变量中。要重新使能中断,只需调用machine模块的enable_irq函数(将之前保存的IRQ状态传给它作为输入参数)即可。在这两次函数调用之间,对共享变量进行访问和递减操作。


[AppleScript] 纯文本查看 复制代码
state = machine.disable_irq()
    interruptCounter = interruptCounter-1
    machine.enable_irq(state)

然后,将总中断计数器递增并打印出来,中断处理过程就完成了。最终代码如下所示,其中已经包含了打印代码以及检查中断是否发生的循环。


[AppleScript] 纯文本查看 复制代码
import machine
interruptCounter = 0
totalInterruptsCounter = 0
timer = machine.Timer(0)  
def handleInterrupt(timer):
  global interruptCounter
  interruptCounter = interruptCounter+1
timer.init(period=1000, mode=machine.Timer.PERIODIC, callback=handleInterrupt)
while True:
  if interruptCounter>0:
    state = machine.disable_irq()
    interruptCounter = interruptCounter-1
    machine.enable_irq(state)
    totalInterruptsCounter = totalInterruptsCounter+1
    print("Interrupt has occurred: " + str(totalInterruptsCounter))


测试代码
将代码上传到您的ESP32开发板并运行,即可对代码进行测试。输出结果如图1所示,控制台会每秒打印一条消息。

esp32-micropython-timer-interrupts.png


图1-ESP32上运行的MicroPython定时器中断例程输出结果。


注:本文作者是Nuno Santos,他是一位和蔼可亲的电子和计算机工程师,住在葡萄牙里斯本 (Lisbon)。
他写了很多有关ESP32、ESP8266的有用的教程和项目。

查看更多ESP32/ESP8266教程和项目,请点击 : ESP32教程汇总贴
英文版教程 : ESP32 tutorial



gada888  版主

发表于 2019-4-1 08:35:06

最近正在学这个
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
wifi气象站

硬件清单

btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2019 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail