目录
前言
话说 上一回 我们了解了如何开始使用 MicroPython
对 Pi Pico 进行一些编程控制。
现在,让我们继续把 Pico 连接电脑,打开 Thonny 开始进行下一环节~
如果 Thonny 的命令行没有显示表示已连接的提示文字,点一下上面的 “停止” 按钮,或许就可以了
中断
作为几乎所有单片机都必备的功能,中断的原理和概念不必赘述,只需要再次明确创建中断的流程:
- 定义一个引脚为
中断输入
,在 Pico 任何一个 GPIO 引脚都可以设定为中断引脚。 - 创建一个
中断处理程序
的函数。 - 将
中断处理程序
与中断输入
配对。
以下代码声明了一个下拉的输入引脚,且中断定义为上升沿触发,与之前按钮输入的触发方式是一样的。此时你会发现:
- 板载 LED 是 2 秒闪烁一次
- 按下按钮后,IDE 中会输出一个提示性文字,并且灯光会快速闪烁 5 次
- 停顿 4 秒后再次以 2 秒的频率闪烁
from machine import Pin
from utime import sleep
led = Pin(25, Pin.OUT)
but = Pin(16, Pin.IN, Pin.PULL_DOWN)
def int_handler(pin):
but.irq(handler=None)
print("Interrupt")
for i in range(5):
led.toggle()
sleep(0.2)
sleep(4)
but.irq(handler=int_handler)
but.irq(trigger=Pin.IRQ_RISING, handler=int_handler)
while True:
led.toggle()
sleep(2)
有时会发现触发中断之后自动再次触发个 1~2 次,我的做法是这样的:
from machine import Pin
from utime import sleep, time
led = Pin(25, Pin.OUT)
but = Pin(16, Pin.IN, Pin.PULL_DOWN)
st = time()
lt = int(st)
def int_handler(pin):
global lt
if time() - lt < 6:
but.irq(handler=int_handler)
return
lt = time()
but.irq(handler=None)
sleep(1)
print(lt - st, end=' - ')
print("Interrupt")
for i in range(6):
led.toggle()
sleep(0.2)
sleep(3)
but.irq(handler=int_handler)
but.irq(trigger=Pin.IRQ_RISING, handler=int_handler)
while True:
led.toggle()
sleep(2)
模拟输入
Pi Pico 有三个模拟输入,他们都有 12 位的分辨率。
- GPIO 26 – ADC0 (Pin 31)
- GPIO 27 – ADC1 (Pin 32)
- GPIO 28 – ADC2 (Pin 34)
还有第四个 ADC 用于内部温度传感器。
由于手头没有电位器,所以用土壤湿度传感器的模拟输出来进行模拟输入的测试:
import machine
import utime
earthWater = machine.ADC(28)
i = 1
while True:
print(f"{i}: {earthWater.read_u16()}")
utime.sleep(2)
i += 1
模拟输出
MicroPython machine
库带有 PWM 输出功能,很容易就能实现这一点。将 LED 灯的正极连接 16 引脚,负极接 GND,使用如下代码可以观察到 LED 的亮度随数值变化的发光情况。
import machine
import utime
led = machine.PWM(machine.Pin(16))
led.freq(1000)
while True:
for i in range(0, 65535, 1000):
led.duty_u16(i)
utime.sleep(0.1)
for i in range(65535, 0, -1000):
led.duty_u16(i)
utime.sleep(0.1)
结合上面的模拟输入操作,我们可以使用电位器控制 LED 的亮度。(这里我把湿度传感器插入水里来修改模拟输入的值)
import machine
import utime
earthWater = machine.ADC(26)
led = machine.PWM(machine.Pin(16))
led.freq(1000)
i = 1
while True:
wet = earthWater.read_u16()
print(f"{i}: {65535 - wet}")
led.duty_u16(wet)
utime.sleep(2)
i += 1
结合第一节的中断,我们可以做一个还算经典的 “点一下换个亮度” 的小应用。ps:如果是低电平,可以声明的时候 PULL_UP
设置中断的时候再 IRQ_FALLING
就像以下代码做的这样。如果高电平则像 第一节 那样设置。
import machine
import utime
# 用于提示程序没有进入中断的闪烁指示灯
bled = machine.Pin(25, machine.Pin.OUT)
# 中断触发按钮
but = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)
# 修改亮度的 LED
led = machine.PWM(machine.Pin(21))
led.freq(1000)
# 设置亮度参数的变量
light = 0
li = 1
led.duty_u16(light)
# 防止中断函数误触发的参数
lt = utime.time()
# 中断函数
def int_handler(pin):
global light
global li
global lt
if utime.time() - lt < 3:
but.irq(handler=int_handler)
return
lt = utime.time()
but.irq(handler=None)
utime.sleep(1)
light += li*1000
if li * light in [6000, 0]: li = -li
led.duty_u16(light)
print(f"now led is {light}")
utime.sleep(1)
but.irq(handler=int_handler)
# 指定中断按钮
but.irq(trigger=machine.Pin.IRQ_FALLING, handler=int_handler)
# 主程序闪烁主板上的板载 LED
while True:
bled.toggle()
utime.sleep(2)
末尾闲言
掌握到现在,我感觉已经差不多可以做一些简单的控制项目了。但是没有联网终究是不太符合 “物联网”。或者结合语音控制?总之 Pico 真有趣w
第二天我优化了一下代码,现在更灵活了~并且增加了长按 5 直接关灯的功能。
import machine
import utime
bled = machine.Pin(25, machine.Pin.OUT)
but = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP)
led = machine.PWM(machine.Pin(21))
led.freq(1000)
light = 0
li = 1
def led_init():
global light
global li
light = 0
li = 1
led.duty_u16(light)
def int_handler(pin):
global light
global li
but.irq(handler=None)
light += li*1000
if li * light in [6000, 0]: li = -li
led.duty_u16(light)
print(f"now led is {light}")
utime.sleep(1)
t1 = utime.time()
# 抬起检测
while not but.value():
# 重置关灯
if utime.time() - t1 > 5:
led_init()
# 抬起检测
while not but.value(): pass
but.irq(handler=int_handler)
but.irq(trigger=machine.Pin.IRQ_FALLING, handler=int_handler)
while True:
bled.toggle()
utime.sleep(2)