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)
  • 主要步骤

    1. 使用 IOMUXC_SetPinMux() 将引脚复用为 GPIO 功能 (ALT5)。
    2. 使用 IOMUXC_SetPinConfig() 设置 IO 属性:
      • 低速转换
      • 上拉 22K 电阻
      • 关闭开漏
      • 关闭迟滞比较器
    3. 使用 GPIO_PinInit() 将引脚初始化为 输入模式,默认电平为高电平(未按下)。

2. KEY_Scan 函数

作用:检测按键是否被按下,并返回对应的按键值。

  • 参数说明

    • mode = 0:不支持连续按下(必须松开后才能再次检测)。
    • mode = 1:支持连续按下(长按时会重复触发)。
  • 实现逻辑

    1. 使用静态变量 key_up 作为“按键松开标志”。
    2. 当检测到有按键按下 (KEYx == 0) 且 key_up == 1 时:
      • 延时 10ms 进行消抖。
      • key_up 置 0,表示按键已被按下。
      • 按优先级顺序返回按键值:KEY0 > KEY1 > KEY2 > WK_UP
    3. 当所有按键松开 (KEYx == 1) 时,将 key_up 重新置 1,允许下一次检测。
    4. 若无按键按下,返回 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,谢谢大家。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐