文章目录
- GPIO外设的概念
- 什么是GPIO
- GPIO内部结构
- 输出部分
- 输入部分
- 【MicroPython】machine.Pin类函数详解
- 实操
GPIO外设的概念
外设(外部设备)
在早期UART和LCD控制器与cpu不在同一芯片上,所以被称作外部设备
随着半导体技术的发展,各种外设被集成到一片芯片上,仍称外设
- 芯片外部的外设称为片外外设
- 芯片内部但在内核之外的外设称为片内外设
什么是GPIO
外设GPIO
全称:通用型输入输出端口 (General-purpose inpou/output)
简单来说,就是MCU可以直接控制的引脚
MCU经常通过GPIO引脚与外部器件连接实现控制,读取或者通讯
因此GPIO可以说是大多数MCU的最重要的功能,也是外部连接的主要途径
我们看下下面RP2040的系统概述图
可以看到内核可以通过SIO(Software control of GPIO)
直接控制GPIO
但是SPI等外设需要通过GPIO才能实现对应的功能
点灯程序就是控制通过GPIO输出的高/低电平进行点亮或者熄灭发光二极管
GPIO内部结构
输出部分
- 输出速度 决定了GPIO最快的反转速度
- 输出使能 决定了是否输出
- 输出数据 决定了输出电平
- 输出能力 决定GPIO的驱动能力
输入部分
- 输入使能 决定是否能够输入
- 输入数据 输入GPIO的电平
- 输入迟滞 是否使用施密特触发器
注意:
现阶段的MicroPython 无法控制输出速度,输出能力,输入迟滞
由上述结构可以将GPIO分为4类
- 开漏输入
- 悬空输入
- 上拉输入
- 下拉输入
【MicroPython】machine.Pin类函数详解
- machine.Pin(id, mode=None, pull=None, value)
- Pin对象构造函数:根据参数初始化GPIO并返回
- id:GPIO编号,数值为0-29,如使用GPIO13则此处填写13,。;
- mode:模式,可选None 不初始化、Pin.IN(0) 输入模式、Pin.OUT(1) 输出模式、Pin.OPEN_DRAIN(2) 开漏模式;
- pull:使用内部上下拉电阻,仅在输入模式下有效,可选 None 悬空、Pin.PULL_UP(1) 上拉、Pin.PULL_DOWN(2)
下拉; - value:输出或开漏模式下端口值,0为低(off)、1为高(on);
第一个参数ID,代表GPIO编号,数值应在0-29,如使用GPIO13则此处填写13。
第二个参数mode代表GPIO模式 可设置为不初始化,输入模式 输出模式 和开漏模式
第三个参数pull为使用内部上下拉电阻,可设置为上拉 下拉 和悬空 注意该参数仅在输入模式下有效。
第四个参数为输出数值,输出或开漏模式下端口值有效。
- Pin.init(mode=None, pull=None)
- 重新初始化GPIO口;
- mode:模式,可选None、Pin.IN(0)、Pin.OUT(1)、Pin.OPEN_DRAIN(2);
- pull:使用内部上下拉电阻,仅在输入模式下有效,可选 None、Pin.PULL_UP(1)、Pin.PULL_DOWN(2);
其作用为重新初始化GPIO,参数与PIN构造函数相同,这里就不一一赘述了.
- Pin.value([x])
- 不填写参数的情况下返回GPIO端口数值,
- 在填写参数的情况下将参数写入GPIO端口中,参数可为0或者1;
PIN类中value函数作用为在不填写参数的情况下返回GPIO端口数值,在填写参数的情况下将参数写入GPIO端口中,参数可为0或者1;
- Pin.toggle()
- 输出或开漏模式下将端口设置翻转
PIN类中toggle函数为在输出或开漏模式下端口值进行一次翻转
- Pin.low()
- 输出或开漏模式下将端口设置为低;
- Pin.off()
- 输出或开漏模式下将端口设置为低;
- Pin.high()
- 输出或开漏模式下将端口设置为高;
- Pin.on()
- 输出或开漏模式下将端口设置为高;
以上四个函数均用于输出或开漏模式下,Low OFF 设置为低(0), high和on设置为高(1)
- Pin.irq(handler=None,trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING))
- 外部中断函数
- 用于设置外部中断
- handler:中断触发回调函数;
- trigger:中断触发条件,设置为:
- Pin.IRQ_FALLING 下降沿中断。
- Pin.IRQ_RISING 在上升沿中断
PIN类irq函数为外部中断函数, 第一个参数为中断触发回调函数; 第二个参数trigger为中断触发条件,设置为边缘触发或者电平触发。
实操
准备扩展工具;
- pico 1
- 面包板 1
- 直插按键 1
- 直插LED 1
- 适当阻值的直插电阻 1
- 杜邦线若干
将按键连接到GPIO15上面
将外部LED连接到GPIO16上面,通过1K电阻进行限流
码代码:
导入machine库中的Pin类
import machine
from machine import Pin
前者会将整个machine库导入
后者将单独导入machine库中的Pin类
相比前者,后者占用的内存更小
from machine import Pin
import utime
# 输入模式
# 初始化GPIO15,输入模式,使用内部上拉的Pin对象并赋予给了button
button_num = 15
button = Pin(button_num, Pin.IN, Pin.PULL_UP)
# 输出模式
# 初始化GPIO16,输出模式
external_led_num = 16;
external_led = Pin(external_led_num, Pin.OUT)
# 初始化GPIO25,输出模式
led_num = 25
led = Pin(led_num, Pin.OUT)
print("button gpio={0}".format(button_num))
while True:
#led灯关闭
# 按键释放完后将GPIO25(led)设置为低电平
# 然后等待按间再次按下
lef.off()
# 读取按钮的值
# 读取GPIO15的数值并判断是否为0,0表示按钮被按下
# 等待10ms后重新判断按钮是否被按下
# 若还是按下就开始执行下一步
if(button.value() == 0):
# 进行了一个软件消抖,即检测出按键闭合后执行一个10ms的延时,要前沿抖动消失后再一次检测按键状态
# 若仍保持闭合状态下的电平,则认为有键按下,才转入按键处理程序
utime.sleep(0.01)
if(button.value() == 0):
# 按键按下时,GPIO16反转
external_led.toggle()
# 打开ledGPIO25设为高电平
led.on()
print("button is pressed.")
# 通过while循环等待按键释放,等待按键释放完后将会回到代码的顶端
while(button.value() == 0):
utime.sleep(0.01)
为什么要等待10ms后重新判断按键是否被按下?
在实际情况中,机械触点断开或者闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会一下就稳定的连接
在一起,也不会在断开时一下就断开
因此在闭合或断开的瞬间会产生一系列的抖动
如何避免?
- 按键消抖
硬件消抖 | 软件消抖 | |
优点 | 较少的软件开销 | 硬件的成本较低 |
缺点 | 硬件成本较高 | 较多的软件开销 |