五向按键深度剖析:从触点原理到 Pico 状态判断,附 MicroPython 工程代码

1.五向按键基本知识

五向按键是一种常见的输入设备,通常用于电子产品的控制界面,如遥控器、游戏手柄和移动设备,其内部包含五个触点,中心有一个公用触点,周围则分布着多个固定触点。其原理是通过活动触点簧片与公用触点和周边固定触点的连接,实现多种状态的切换。当操作杆移动时,活动触点簧片与相应触点接触,从而形成电路连接。

五向按键就像一个按键,但实际上它包含五个不同的按键状态,通过不同方向的按压,用户可以在多个功能之间切换。这里,我们将五向按键的公用触点(COM 端)连接到 +5V 电源上。当没有任何一个按键按下时,测量到的任意一个按键的电压为 0V,因为所有触点处于开路状态,不会有电流流动;而当按下任意一个按键时,那个按键的活动触点簧片将与公用触点连接,形成闭合电路,此时测量到的对应按键电压将上升到电源电压(5V)。

2.应用实验

在以下程序中,我们使用树莓派 Pico 的 GPIO 引脚读取和处理一个五向摇杆(包含 7 个按键)输入的状态,并在按键被按下时打印相关的按键信息,这里,我们需要将 风雅一号板-通用兼容扩展板 插入到 风雅一号板-LCD屏幕人机交互板 上,并且打开 SWITCH3 拨码开关上所有选项,实物连接图如下所示:

五向按键连接情况如下表所示,其中五向按键的共用端(COM 端)连接到 +3V3 电源:

五向按键引脚 树莓派 Pico 引脚 说明
COM (公共端) 3V3(OUT) 公共电源端,接 Pico 的 3.3V 电源输出
UP GPIO20 上方向按键输入
DOWN GPIO18 下方向按键输入
LEFT GPIO16 左方向按键输入
RIGHT GPIO19 右方向按键输入
MID (确认键) GPIO17 中间按键输入

示例代码如下,在配套资料的文件夹:elegance-devkit v1\Demo\06 GPIO_5DJoystick 中:

# Python env   : MicroPython v1.23.0
# -*- coding: utf-8 -*-        
# @Time    : 2025/1/2 下午2:10   
# @Author  : 李清水            
# @File    : main.py       
# @Description : GPIO类实验,5D摇杆实验

# ======================================== 导入相关模块 =========================================

# 导入硬件相关模块
from machine import Pin
# 导入时间相关模块
import time

# ======================================== 全局变量 ============================================

# ======================================== 功能函数 ============================================

# ======================================== 自定义类 ============================================

# 自定义五向按键类
class DirectionalButton:
    """
​    一个用于处理五向按键的类。

​    该类封装了五向按键的功能,包括 UP、DOWN、LEFT、RIGHT、MID、SET 和 RST 按键的检测。
​    每个按键通过配置对应的 GPIO 引脚来监听按键按下和释放事件。按键的状态会存储在 `button_state` 字典中。
​    按键状态发生变化时,内部会触发中断处理函数来更新状态。提供的方法包括获取特定按键的状态、重置所有按键状态等。

​    Attributes:
​        up_pin (Pin): 用于 UP 按键的 GPIO 引脚对象,初始化时会设置为输入模式并启用下拉电阻。
​        down_pin (Pin): 用于 DOWN 按键的 GPIO 引脚对象,初始化时会设置为输入模式并启用下拉电阻。
​        left_pin (Pin): 用于 LEFT 按键的 GPIO 引脚对象,初始化时会设置为输入模式并启用下拉电阻。
​        right_pin (Pin): 用于 RIGHT 按键的 GPIO 引脚对象,初始化时会设置为输入模式并启用下拉电阻。
​        mid_pin (Pin): 用于 MID 按键的 GPIO 引脚对象,初始化时会设置为输入模式并启用下拉电阻。
​        set_pin (Pin): 用于 SET 按键的 GPIO 引脚对象,初始化时会设置为输入模式并启用下拉电阻。
​        rst_pin (Pin): 用于 RST 按键的 GPIO 引脚对象,初始化时会设置为输入模式并启用下拉电阻。
​        button_state (dict): 按键状态字典,记录每个按键的当前状态。字典中键名为按键名,值为按键的状态(True 为按下,False 为未按下)。

​    Methods:
​        get_button_state(button): 获取指定按键的当前状态,返回 True 表示按下,False 表示未按下。
​        reset_all(): 重置所有按键的状态,将所有按键标志设置为 False(未按下)。
​        _handle_button(pin): 按键中断处理函数,根据按键的引脚设置按键的状态。
​    """

​    ​def __init__(self, up_pin: int, down_pin: int, left_pin: int, right_pin: int,
                 mid_pin: int, set_pin: int = None, rst_pin: int = None) -> None:
        """
​        初始化五向按键类,配置所有按键的 GPIO 引脚并启用内置上拉电阻。

​        Args:
​            up_pin (int): UP 按键的 GPIO 引脚。
​            down_pin (int): DOWN 按键的 GPIO 引脚。
​            left_pin (int): LEFT 按键的 GPIO 引脚。
​            right_pin (int): RIGHT 按键的 GPIO 引脚。
​            mid_pin (int): MID 按键的 GPIO 引脚。
​            set_pin (int): SET 按键的 GPIO 引脚。
​            rst_pin (int): RST 按键的 GPIO 引脚。

​        Returns:
​            None
​        """
​        ​# 初始化各个方向的按键引脚,设置为输入模式,并启用下拉电阻
        self.up_pin     = Pin(up_pin, Pin.IN, Pin.PULL_DOWN)
        self.down_pin   = Pin(down_pin, Pin.IN, Pin.PULL_DOWN)
        self.left_pin   = Pin(left_pin, Pin.IN, Pin.PULL_DOWN)
        self.right_pin  = Pin(right_pin, Pin.IN, Pin.PULL_DOWN)
        self.mid_pin    = Pin(mid_pin, Pin.IN, Pin.PULL_DOWN)

        if set_pin is not None and rst_pin is not None:
            self.set_pin    = Pin(set_pin, Pin.IN, Pin.PULL_DOWN)
            self.rst_pin    = Pin(rst_pin, Pin.IN, Pin.PULL_DOWN)

        # 初始化按键状态字典,默认值为 False(未按下)
        self.button_state = {
            'UP': False,
            'DOWN': False,
            'LEFT': False,
            'RIGHT': False,
            'MID': False,
            'SET': False,
            'RST': False
        }

        # 为各个按键引脚设置中断处理函数
        self.up_pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._handle_button)
        self.down_pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._handle_button)
        self.left_pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._handle_button)
        self.right_pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._handle_button)
        self.mid_pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._handle_button)

        if set_pin is not None and rst_pin is not None:
            self.set_pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._handle_button)
            self.rst_pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._handle_button)

    def _handle_button(self, pin: Pin) -> None:
        """
​        按键中断处理函数,根据按键的引脚设置按键状态。

​        每次按键按下或松开时,更新对应按键的状态。

​        Args:
​            pin (Pin): 触发中断的按键引脚。

​        Returns:
​            None
​        """
​        ​if pin == self.up_pin:
            self.button_state['UP'] = (pin.value() == 1)
        elif pin == self.down_pin:
            self.button_state['DOWN'] = (pin.value() == 1)
        elif pin == self.left_pin:
            self.button_state['LEFT'] = (pin.value() == 1)
        elif pin == self.right_pin:
            self.button_state['RIGHT'] = (pin.value() == 1)
        elif pin == self.mid_pin:
            self.button_state['MID'] = (pin.value() == 1)
        elif pin == self.set_pin:
            self.button_state['SET'] = (pin.value() == 1)
        elif pin == self.rst_pin:
            self.button_state['RST'] = (pin.value() == 1)

    def get_button_state(self, button: str) -> bool:
        """
​        获取指定按键的当前状态。

​        检查指定按键是否处于按下状态。

​        Args:
​            button (str): 要查询的按键,支持 'UP', 'DOWN', 'LEFT', 'RIGHT', 'MID', 'SET', 'RST'。

​        Returns:
​            bool: 返回指定按键的状态,True 表示按下,False 表示未按下。
​        """
​        ​return self.button_state.get(button, False)

    def reset_all(self) -> None:
        """
​        重置所有按键的状态为未按下。

​        用于在某些场景下需要清除所有按键状态时使用。

​        Args:
​            None

​        Returns:
​            None
​        """
​        ​for button in self.button_state:
            self.button_state[button] = False

# ======================================== 初始化配置 ==========================================

# 上电延时3s
time.sleep(3)
# 打印调试信息
print("FreakStudio : GPIO read 5D Joystick value")

# 创建五向按键对象,使用 GPIO 16 到 GPIO 20 连接按键
button = DirectionalButton(up_pin=20, down_pin=18, left_pin=16, right_pin=19, mid_pin=17)

# ========================================  主程序  ===========================================

# 主循环,读取按键状态并打印出来
while True:
    # 检查是否有按键被按下
    for button_name in ['UP', 'DOWN', 'LEFT', 'RIGHT', 'MID', 'SET', 'RST']:
        # 如果按键被按下,打印按键名称和状态
        if button.get_button_state(button_name):
            print(f"{button_name} button is pressed.")

    # 每隔 100 毫秒循环一次
    time.sleep(0.1)

DirectionalButton 类封装了五向摇杆的 7 个按键(UP、DOWN、LEFT、RIGHT、MID、SET、RST)的检测和状态管理,每个按键对应一个 GPIO 引脚,按键状态通过中断方式进行实时检测,包括如下方法:

  • 构造方法 __init__​:​构造函数接收七个引脚参数,这些引脚分别连接到五向摇杆的 7 个按键(UP、DOWN、LEFT、RIGHT、MID、SET、RST),使用 Pin.IN 来配置引脚为输入模式,并且通过 Pin.PULL_DOWN 启用下拉电阻(因为按键未按下时,输入引脚的状态是低电平 0,按下时变为高电平 1)。
  • 中断处理方法 _handle_button​:​中断函数会在每次按键按下(IRQ_FALLING)或松开(IRQ_RISING)时触发,按键的状态会通过检查引脚的电平来更新,在按下时,GPIO 引脚电平为高电平(1),松开时为低电平(0),每个按键都有对应的状态字典 (button_state),保存按键是否被按下的状态。
  • 获取按键状态 get_button_state​:​该函数接收一个按键名称(如 'UP')并返回该按键的当前状态,True 表示按下,False 表示未按下,通过字典的 get() 方法返回相应按键的状态。
  • 重置所有按键状态 reset_all​:​该函数将所有按键的状态设置为 False,即将它们的状态重置为“未按下”,通过字典遍历所有按键,将它们的状态重置。

在主循环中,我们创建 DirectionalButton 类的实例,并将引脚号传入对应的按键引脚,这里使用的是树莓派 Pico 的 GPIO 引脚 16 到 22 连接摇杆的各个按键,主循环中,程序不断检查每个按键的状态;对每个按键,调用 get_button_state() 方法获取当前状态,如果按键被按下,则打印相关信息(如 "UP button is pressed."),每次循环结束后,使用 time.sleep(0.1) 延时 100 毫秒,避免过于频繁地读取按键状态,减轻 CPU 负担。

烧录程序,打开终端,显示如下:

可以看到,按下不同按键时,都能够显示对应按键状态信息。


posted @ 2026-08-31 11:27  FreakStudio  阅读(19)  评论(0)    收藏  举报