MicroPython 开发ESP32应用教程 之 Timer、GPIO中断

随着我们课程的递进,大家会发现,我们之前课程中的例子,虽然功能都能实现,但总觉得体验感不够好,比如按键控制GRB灯珠的时候,很容易出现按键后,灯珠没有反应,还有蓝牙发送指令控制灯珠的时候也会出现延迟等问题,今天,我们就讲解如何改善这类现象。

要想改善这类现象,需要用到Timer、GPIO中断,我们先分别介绍一下这些知识。

一、Timer

 在 MicroPython 中,Timer类用于实现硬件定时器功能,可以用于周期性任务、定时中断、PWM 生成等。以下是 Timer 的常见应用场景和示例:

 1. 基本概念
        定时器 ID: ESP32S3 支持 4 个定时器
        定时器模式:
                  Timer.PERIODIC:周期性执行回调函数。
                  Timer.ONE_SHOT:单次执行回调函数。
        回调函数:定时器触发时调用的函数。  2. 基本用法
   

2、初始化定时器、停止定时器

from machine import Timer

# 初始化定时器(ID=0,模式为周期性)
tim = Timer(0)
tim.init(period=1000, mode=Timer.PERIODIC, callback=lambda t: print("Timer triggered!"))


tim.deinit()  # 停止并关闭定时器

参数说明:
period:定时周期(单位:毫秒)。
mode:Timer.PERIODIC 或 Timer.ONE_SHOT。
callback:定时器触发时调用的函数(需接受一个参数,通常是定时器对象)。

 3、应用举例

from machine import Timer, Pin

led = Pin(2, Pin.OUT)  # 假设我们用 GPIO2 连接 LED

def toggle_led(t):
    led.value(not led.value())  # 切换 LED 状态

# 初始化定时器,每 500ms 触发一次
tim = Timer(0)
tim.init(period=500, mode=Timer.PERIODIC, callback=toggle_led)

4、PWM输出

from machine import Timer, Pin, PWM

pwm = PWM(Pin(2))  # 假设使用 PWM 控制 LED 亮度
pwm.freq(1000)     # 设置 PWM 频率

def set_duty(duty):
    pwm.duty(duty)

# 定时改变 PWM 占空比
duty = 0
def pwm_callback(t):
    global duty
    duty = (duty + 10) % 1023
    pwm.duty(duty)

tim = Timer(0)
tim.init(period=50, mode=Timer.PERIODIC, callback=pwm_callback)

二、GPIO 中断

在 MicroPython 中配置 GPIO 中断可以实现对外部事件的快速响应(如按键按下、传感器信号触发等)。以下是详细的配置方法和示例:

1. GPIO 中断的基本概念
        触发条件:支持多种触发模式,如:
                  Pin.IRQ_RISING:上升沿触发(低电平 → 高电平)。
                  Pin.IRQ_FALLING:下降沿触发(高电平 → 低电平)。
                  Pin.IRQ_LOW_LEVEL:低电平持续触发。
                  Pin.IRQ_HIGH_LEVEL:高电平持续触发。
                  Pin.IRQ_CHANGE:电平变化触发(上升沿和下降沿均触发)。(我在s3上测试,好象不支持电平变化触发中断)
        中断服务函数(ISR):当触发条件满足时,自动调用绑定的回调函数。

2. 配置 GPIO 中断的步骤
        2.1 初始化 GPIO 引脚
        设置引脚为输入模式,并启用上拉/下拉电阻(可选):

from machine import Pin

# 初始化引脚为输入模式,启用内部上拉电阻(假设连接按键到 GND)
pbootkey = Pin(0, Pin.IN,Pin.PULL_UP) #配置GPIO0为输入端口

        2.2 定义中断回调函数
         回调函数需要接收一个参数(触发中断的引脚对象):
 

def     button_handler(pin):
    time.sleep_ms(10)	#消除抖动
    if pin.value() == 0:
        led.value(not led.value())
    # 此处执行中断处理逻辑   

         2.3 绑定中断触发条件和回调函数**

# 配置中断:下降沿触发(按键按下时从高电平变为低电平)
pbootkey.irq(trigger = Pin.IRQ_FALLING,handler=button_handler)

 3、 多引脚共享中断
        多个引脚可以绑定到同一个回调函数:
 

button1 = Pin(14, Pin.IN, Pin.PULL_UP)
button2 = Pin(15, Pin.IN, Pin.PULL_UP)

def shared_handler(pin):
    print("Interrupt from pin:", pin)

button1.irq(trigger=Pin.IRQ_FALLING, handler=shared_handler)
button2.irq(trigger=Pin.IRQ_FALLING, handler=shared_handler)

4. 动态修改中断配置

# 禁用中断
button.irq(handler=None)

# 重新启用中断(例如切换触发模式)
button.irq(trigger=Pin.IRQ_RISING, handler=button_handler)

三、应用实例

 接下来,我们利用今天介绍的知识来改善前面课程讲解的实例。

1、通过开发板上的boot按键来控制开发板上的GRB灯珠

def     button_handler(pin):
    time.sleep_ms(10)	#消除抖动
    if pin.value() == 0:
        wsled.ws2812_Change_Status()

2、通过Timer回调函数来扫描aht20温湿度值

这里我们设定1分钟扫描一次。

想要详细了解aht20及aht10的朋友,可以参考:CH592F /CH582通过硬件IIC读写AHT10 /AHT20,并将数据通过BLE发送给上位机

def monitor(t):
    global ahtx_interval
    ahtx_interval += 1
    if ahtx_interval >= (AHT20_Interval / MOINTOR_Interval):
        ahtx_interval = 0
        wendu = aht20_sensor.temperature
        shidu = aht20_sensor.relative_humidity
        tft.showstring("实测温湿度:\n温度 : {:>4.1f} ℃\n湿度 : {:>4.1f} %".format(wendu,shidu),0,42,color(0,0,0xff))

3、通过Timer回调函数监控蓝牙发送控制GRB灯珠的指令

def monitor(t):
    command = ble.get_rec_cmd()
    if command == 'LED ON':
        wsled.ws2812_Power(1)
#            print(ble.ble_msg)
        ble.send('LED is ON.')
#            ble.ble_msg = ''
    # 关闭LED
    elif command == 'LED OFF':
        wsled.ws2812_Power(0)
#        print('LED is OFF.')
        ble.send('LED is OFF.')

4、通过Timer回调函数改变GRB灯珠状态

def monitor(t):
    wsled.ws2812_LED_Cycle()

想要了解ws2812灯珠控制原理及代码介绍的朋友,可以参考:

MicroPython 开发基于ESP32S3控制ws2812灯带的程序

最后给出主程序的完整代码,需要各模块实现代码的朋友请参考:

MicroPythonforESP32S3Timer回调函数、GPIO中断处理函数、aht20温湿度测量及显示、BLE控制ws2812灯珠、st7735TFT显示屏驱动、中文字符支持资源-优快云文库


from machine import I2C,SPI,Pin,Timer
from micropython import const
import time
from esp32_ble import  ESP32_BLE
from esp32_wifi import esp32_wifi
from ahtx0 import AHT20,ahtx_interval
from st7735 import ST7735,color
from ws2812 import WS2812
spi = SPI(2,
                  baudrate=20000000,
                  polarity=0,
                  phase=0,
                  sck=Pin(4),
                  mosi=Pin(5),
                  miso=None)

# 定义控制引脚
dc = Pin(7,Pin.OUT)
cs = Pin(15,Pin.OUT)
rst= Pin(6,Pin.OUT)
#bl = Pin(9, Pin.OUT)
# 初始化显示屏 (128x160)
tft = ST7735(128, 160, spi, dc, cs, rst,None,rotate=0)

i2c = I2C(0,scl=Pin(1),sda=Pin(2),freq=200000)
aht20_sensor = AHT20(i2c)

pin = Pin(48, Pin.OUT)   #配置GPIO8为输出端口,控制ws2812灯珠的DIN信号
wsled = WS2812(pin,1,3,1)

MOINTOR_Interval = const(100)
AHT20_Interval = const(6000)

def monitor(t):
    global ahtx_interval
    wsled.ws2812_LED_Cycle()
    ahtx_interval += 1
    if ahtx_interval >= (AHT20_Interval / MOINTOR_Interval):
        ahtx_interval = 0
        wendu = aht20_sensor.temperature
        shidu = aht20_sensor.relative_humidity
        tft.showstring("实测温湿度:\n温度 : {:>4.1f} ℃\n湿度 : {:>4.1f} %".format(wendu,shidu),0,42,color(0,0,0xff))

    command = ble.get_rec_cmd()
    if command == 'LED ON':
        wsled.ws2812_Power(1)
#            print(ble.ble_msg)
        ble.send('LED is ON.')
#            ble.ble_msg = ''
    # 关闭LED
    elif command == 'LED OFF':
        wsled.ws2812_Power(0)
#        print('LED is OFF.')
        ble.send('LED is OFF.')
#            ble.ble_msg = ''
    
def     button_handler(pin):
    time.sleep_ms(10)	#消除抖动
    if pin.value() == 0:
        wsled.ws2812_Change_Status()

if __name__ == "__main__":
    
    pbootkey = Pin(0, Pin.IN,Pin.PULL_UP) #配置GPIO0为输入端口
    pbootkey.irq(trigger = Pin.IRQ_FALLING,handler=button_handler)
    
    tft.clear()
    wendu = aht20_sensor.temperature
    shidu = aht20_sensor.relative_humidity
    tft.showstring("实测温湿度:\n温度 : {:>4.1f} ℃\n湿度 : {:>4.1f} %".format(wendu,shidu),0,42,color(0,0,0xff))
    ble = ESP32_BLE("913 AI App")
    tim = Timer(0)
    tim.init(period = MOINTOR_Interval,mode=Timer.PERIODIC,callback=monitor)
    
    while True:
        time.sleep(1)        

 

### ESP32 中断使用方法及示例 ESP32中断功能非常强大,支持多种类型的中断事件以及灵活的配置方式。以下是关于如何在 ESP32 上实现 GPIO 中断和定时器中断的具体说明。 #### 一、GPIO 中断 ESP32 支持五种类型的 GPIO 中断事件:`LOW`、`HIGH`、`CHANGE`、`FALLING` 和 `RISING`[^1]。这些中断可以通过 Arduino IDE 或者 Micropython 实现。 ##### 配置 GPIO 中断 (Arduino IDE 示例) 以下是一个简单的 GPIO 中断配置示例: ```cpp // 定义使用的 GPIO 引脚号 const int interruptPin = 4; volatile int state = LOW; // 记录当前状态 void setup() { Serial.begin(9600); pinMode(interruptPin, INPUT_PULLUP); // 设置为上拉输入模式 attachInterrupt(digitalPinToInterrupt(interruptPin), changeState, FALLING); // 绑定中断到指定引脚 } void loop() { digitalWrite(LED_BUILTIN, state); // 控制内置 LED 显示状态 } void changeState() { // 中断服务程序 state = !state; } ``` 上述代码实现了当检测到 GPIO 引脚上的下降沿 (`FALLING`) 时触发中断,并改变内置 LED 的亮灭状态。 --- #### 二、定时器中断 除了 GPIO 中断外,ESP32 还可以利用硬件定时器来生成周期性的中断信号。下面展示了一个基于 MicroPython 平台的定时器中断示例[^2]。 ##### 配置定时器中断 (MicroPython 示例) ```python from machine import Timer def handle_timer(timer): # 定义定时器回调函数 print("Timer triggered!") # 创建并初始化一个硬件定时器对象 timer = Timer(0) # 启动定时器,每秒触发一次中断 timer.init(period=1000, mode=Timer.PERIODIC, callback=lambda t:handle_timer(t)) ``` 此代码片段展示了如何通过 Thonny 开发环境设置一个每隔一秒触发一次的定时器中断。 --- #### 总结 无论是 GPIO 中断还是定时器中断,在实际应用中都需要特别注意中断优先级和服务时间长度等问题。如果处理不当可能会导致系统性能下降甚至崩溃。因此建议开发者合理规划资源分配情况下的最佳实践方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

永远的元子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值