6.【NXP 号令者RT1052】开发——实战-按键输入
6.【NXP 号令者RT1052】开发——实战-按键输入
在本章中,我们将利用板载的 4 个按键,来控制板载的两个LED 的亮灭。
6.1 硬件设计
我们要到的东西有:
1) 指示灯 DS0、DS1。
2) 4 个按键:KEY0、KEY1、KEY2、和 KEY_UP
打开原理图。



在号令者 RT1052 开发板上的按键KEY0 连接在 P105(GPIO1_IO05)上、KEY1 连接在 P501(GPIO5_IO01)上、KEY2 连接在P326(GPIO3_IO26)上、KEY_UP 连接在 P500(GPIO5_IO00)上。
可以看见是共阴,那么就是低电平有效。并且外部都没有(KEY0 除外)接上拉电阻,所以,需要在 RT1052 内部设置上拉电阻。另外,KEY0 和 BOOT_MODE1 共用,按住KEY0,则 BOOT_MODE1 接 GND,所以上电的时候,不要按住 KEY0,否则无法正常启动。
6.2 软件设计
用 VScode打开上一次的TEST项目,并且用Keil MDK打开项目。然后在HARDWARE 文件夹下新建一个 KEY 文件夹,用来存放与按键相关的代码。
然后写入 key.c代码
#include "key.h"
#include "delay.h"
//按键初始化函数
//KEY_UP -> WAKEUP(GPIO5_IO00)
//KEY0 -> GPIO_AD_B0_05(GPIO1_IO05)
//KEY1 -> PMIC_ON_REQ(GPIO5_IO01)
//KEY2 -> GPIO_EMC_40(GPIO3_IO26)
void KEY_Init(void)
{
gpio_pin_config_t key_config;
//IO功能设置
IOMUXC_SetPinMux(IOMUXC_SNVS_WAKEUP_GPIO5_IO00,0); //SNVS_WAKEUP配置为ALT5,即GPIO5_00
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_05_GPIO1_IO05,0); //GPIO_AD_B0_05配置为ALT5,即GPIO1_IO05
IOMUXC_SetPinMux(IOMUXC_SNVS_PMIC_ON_REQ_GPIO5_IO01,0); //PMIC_ON_REQ,即GPIO5_IO01
IOMUXC_SetPinMux(IOMUXC_GPIO_EMC_40_GPIO3_IO26,0); //GPIO_EMC_40配置为ALT5,即GPIO3_IO26
//配置KEY相关IO的功能
//低转换速度,关闭输出驱动,速度为100Mhz,关闭开路功能,使能pull/keepr
//选择pull功能,上拉22K Ohm,关闭Hyst
IOMUXC_SetPinConfig(IOMUXC_SNVS_WAKEUP_GPIO5_IO00,0xF080);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_05_GPIO1_IO05,0xF080);
IOMUXC_SetPinConfig(IOMUXC_SNVS_PMIC_ON_REQ_GPIO5_IO01,0xF080);
IOMUXC_SetPinConfig(IOMUXC_GPIO_EMC_40_GPIO3_IO26,0xF080);
//KEY_UP默认电平设置
key_config.direction=kGPIO_DigitalInput; //输入
key_config.interruptMode=kGPIO_NoIntmode; //不使用中断功能
key_config.outputLogic=1; //默认高电平
GPIO_PinInit(GPIO5,0,&key_config); //初始化GPIO5_00
//KEY0默认电平设置
key_config.direction=kGPIO_DigitalInput; //输入
key_config.interruptMode=kGPIO_NoIntmode; //不使用中断功能
key_config.outputLogic=1; //默认高电平
GPIO_PinInit(GPIO1,5,&key_config); //初始化GPIO1_05
//KEY1默认电平设置
key_config.direction=kGPIO_DigitalInput; //输入
key_config.interruptMode=kGPIO_NoIntmode; //不使用中断功能
key_config.outputLogic=1; //默认高电平
GPIO_PinInit(GPIO5,1,&key_config); //初始化GPIO5_01
//KEY2默认电平设置
key_config.direction=kGPIO_DigitalInput; //输入
key_config.interruptMode=kGPIO_NoIntmode; //不使用中断功能
key_config.outputLogic=1; //默认高电平
GPIO_PinInit(GPIO3,26,&key_config); //初始化GPIO3_26
}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,WKUP按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>WK_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1; //按键松开标志
if(mode==1)key_up=1; //支持连按
if(key_up&&(KEY1==0||KEY2==0||KEY0==0||WK_UP==0))
{
delay_ms(10);
key_up=0;
if(KEY0==0) return KEY0_PRES;
else if(KEY1==0) return KEY1_PRES;
else if(KEY2==0) return KEY2_PRES;
else if(WK_UP==0) return WKUP_PRES;
}else if(KEY1==1&&KEY2==1&&KEY0==1&&WK_UP==1)key_up=1;
return 0; //无按键按下
}
1. KEY_Init 函数
作用:完成按键 IO 的初始化,将按键引脚配置为 GPIO 输入模式,并设置上拉电阻。
-
按键对应引脚
- KEY_UP → WAKEUP (GPIO5_IO00)
- KEY0 → GPIO_AD_B0_05 (GPIO1_IO05)
- KEY1 → PMIC_ON_REQ (GPIO5_IO01)
- KEY2 → GPIO_EMC_40 (GPIO3_IO26)
-
主要步骤
- 使用
IOMUXC_SetPinMux()将引脚复用为 GPIO 功能 (ALT5)。 - 使用
IOMUXC_SetPinConfig()设置 IO 属性:- 低速转换
- 上拉 22K 电阻
- 关闭开漏
- 关闭迟滞比较器
- 使用
GPIO_PinInit()将引脚初始化为 输入模式,默认电平为高电平(未按下)。
- 使用
2. KEY_Scan 函数
作用:检测按键是否被按下,并返回对应的按键值。
-
参数说明
mode = 0:不支持连续按下(必须松开后才能再次检测)。mode = 1:支持连续按下(长按时会重复触发)。
-
实现逻辑
- 使用静态变量
key_up作为“按键松开标志”。 - 当检测到有按键按下 (
KEYx == 0) 且key_up == 1时:- 延时 10ms 进行消抖。
- 将
key_up置 0,表示按键已被按下。 - 按优先级顺序返回按键值:KEY0 > KEY1 > KEY2 > WK_UP。
- 当所有按键松开 (
KEYx == 1) 时,将key_up重新置 1,允许下一次检测。 - 若无按键按下,返回
0。
- 使用静态变量
3. 按键优先级
在多个按键同时按下时,函数会按照以下优先级返回:
KEY0 > KEY1 > KEY2 > WK_UP。
开始
↓
按键初始化 (KEY_Init)
- 配置 IOMUXC 复用为 GPIO
- 设置 PAD 属性 (上拉、输入模式)
- GPIO_PinInit 输入,高电平默认
↓
进入 KEY_Scan()
↓
检查是否允许检测 (`key_up == 1` 或 mode=1)
↓
有按键按下?(KEY0/KEY1/KEY2/WK_UP == 0)
┌───────────────否───────────────┐
↓ │
返回 0 (无按键) ← 所有按键松开? → 是 → key_up=1
│
↓
是
↓
延时 10ms 消抖
↓
再次检测按键
↓
根据优先级返回键值
(KEY0 > KEY1 > KEY2 > WK_UP)
↓
设置 key_up=0 (等待松开)
↓
结束
然后我们按同样的方法,新建一个 key.h 文件,也保存在 KEY 文件夹下面。在 key.h 中输入如下代码
#ifndef _KEY_H
#define _KEY_H
#include "sys.h"
/*******************************************
KEY_UP -> WAKEUP(GPIO5_IO00)
KEY0 -> GPIO_AD_B0_05(GPIO1_IO05)
KEY1 -> PMIC_ON_REQ(GPIO5_IO01)
KEY2 -> GPIO_EMC_40(GPIO3_IO26)
*******************************************/
#define KEY0 GPIO_PinRead(GPIO1,5) //KEY0按键GPIO1_05
#define KEY1 GPIO_PinRead(GPIO5,1) //KEY1按键GPIO5_01
#define KEY2 GPIO_PinRead(GPIO3,26) //KEY2按键GPIO3_26
#define WK_UP GPIO_PinRead(GPIO5,0) //WK_UP按键GPIO5_00
#define KEY0_PRES 1 //KEY0按下后返回值
#define KEY1_PRES 2 //KEY1按下后返回值
#define KEY2_PRES 3 //KEY2按下后返回值
#define WKUP_PRES 4 //WKUP按下后返回值
void KEY_Init(void);
u8 KEY_Scan(u8 mode);
#endif
这段代码里面最关键就是 4 个宏定义:
#define KEY0 GPIO_PinRead(GPIO1,5) //KEY0按键GPIO1_05
#define KEY1 GPIO_PinRead(GPIO5,1) //KEY1按键GPIO5_01
#define KEY2 GPIO_PinRead(GPIO3,26) //KEY2按键GPIO3_26
#define WK_UP GPIO_PinRead(GPIO5,0) //WK_UP按键GPIO5_00
这里使用的是 GPIO_PinRead 函数来实现读取某个 IO 口的状态,实际上就是读取 DR 寄存器,大家可以自行查阅 FSL 库中的此函数的源码,很简单。
在 key.h 中,我们还定义了 KEY0_PRES / KEY1_PRES/ KEY2_PRES/WKUP_PRES 等 4 个宏定义,分别对应开发板四个按键(KEY0/KEY1/KEY2/ KEY_UP)按键按下时 KEY_Scan 返回的值。通过宏定义的方式判断返回值.
现在把两个文件保存一下,然后在Keil MAK中添加到组,和添加路径。我就不在复述了。

接下来我们添加 main.c代码
#include "sys.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
int main(void)
{
u8 key=0;
u8 led0sta=1,led1sta=1; //LED0,LED1的当前状态
MPU_Memory_Protection(); //初始化MPU
RT1052_Clock_Init(); //配置系统时钟
DELAY_Init(600); //延时函数初始化
LPUART1_Init(115200); //初始化串口1
LED_Init(); //初始化LED
KEY_Init(); //初始化KEY
LED0(0); //先点亮红灯
while(1)
{
key=KEY_Scan(0); //得到键值
if(key)
{
switch(key)
{
case WKUP_PRES: //控制LED0,LED1互斥点亮
led1sta=!led1sta;
led0sta=!led1sta;
break;
case KEY2_PRES: //控制LED0翻转
led0sta=!led0sta;
break;
case KEY1_PRES: //控制LED1翻转
led1sta=!led1sta;
break;
case KEY0_PRES: //同时控制LED0,LED1翻转
led0sta=!led0sta;
led1sta=!led1sta;
break;
}
LED0(led0sta); //控制LED0状态
LED1(led1sta); //控制LED1状态
}else delay_ms(10);
}
}
这里,我们通过 led0sta 和 led1sta 来表示当前 LED 的状态,最后通过 LED0 和 LED1 这两个函数控制 DS0 和 DS1 的状态。(3 个目标工程需要添加 3 次)
然后编译,下载。




总结
这一节还是很简单,有了上一结学习GPIO的一些知识后,还是很容易。里面太基础的地方我就没有细讲了。OK,谢谢大家。
更多推荐

所有评论(0)