i.MX6ULL终结者按键例程程序设计

本实验对应的例程在光盘资料的:i.MX6UL终结者光盘资料\04_裸机例程源码\6_key 目录下,我们在Ubuntu系统下使用命令“mkdir 6_key”建立“6_key”文件夹,如图 1所示:
在这里插入图片描述

图 1

使用命令“cd 6_key”进入6_key文件。如图 2所示:
在这里插入图片描述

图 2

然后使用命令“cp -r …/5_beep/* ./”将上一章试验中的所有内容拷贝到刚刚新建的“6_key”里面,如图 3所示:
在这里插入图片描述

图 3

拷贝完成以后的工程如图 4所示:
在这里插入图片描述

图 4

使用命令“mkdir drivers/gpio”在drivers驱动目录下新建“gpio”文件夹。GPIO操作驱动都放在这个目录下。如图 5所示:
在这里插入图片描述

图 5

使用命令“vi drivers/gpio/gpio.h”新建gpio.h文件。如图 14.3.6所示:
在这里插入图片描述

图 6

添加如下内容:

  1 #ifndef _BSP_GPIO_H
  2 #define _BSP_GPIO_H
  3 #define _BSP_KEY_H
  4 #include "imx6ul.h"
  5 
  6 /* 枚举类型和结构体定义 */
  7 typedef enum _gpio_pin_direction
  8 {
    
    
  9     kGPIO_DigitalInput = 0U,            /* 输入 */
 10     kGPIO_DigitalOutput = 1U,           /* 输出 */
 11 } gpio_pin_direction_t;
 12 
 13 
 14 typedef struct _gpio_pin_config
 15 {
    
    
 16     gpio_pin_direction_t direction; /* GPIO方向:输入还是输出 */
 17     uint8_t outputLogic;            /* 如果是输出的话,默认输出电平 */
 18 } gpio_pin_config_t;
 19 
 20 
 21 /* 函数声明 */
 22 void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config);
 23 int gpio_pinread(GPIO_Type *base, int pin);
 24 void gpio_pinwrite(GPIO_Type *base, int pin, int value);
 25 
 26 #endif

gpio.h 中定义了一个枚举类型 gpio_pin_direction_t 和结构体 gpio_pin_config_t。
gpio_pin_direction_t:GPIO方向,输入或输出。
gpio_pin_config_t:GPIO配置结构体,里面有 GPIO 的方向和默认输出电平两个成员变量。
部分截图如图 7所示:
在这里插入图片描述

图 7

添加完成之后,保存退出文件。
使用命令“vi drivers/gpio/gpio.c”新建gpio.c文件。如图 8所示:
在这里插入图片描述

图 8

添加内容如下:

1 #include "gpio.h"
  2 
  3 /*
  4  * @description         : GPIO初始化。
  5  * @param - base        : 要初始化的GPIO组。
  6  * @param - pin         : 要初始化GPIO在组内的编号。
  7  * @param - config      : GPIO配置结构体。
  8  * @return                      : 无
  9  */
 10 void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
 11 {
    
    
 12         if(config->direction == kGPIO_DigitalInput) /* 输入 */
 13         {
    
    
 14                 base->GDIR &= ~( 1 << pin);
 15         }
 16         else                                                                                /* 输出 */
 17         {
    
    
 18                 base->GDIR |= 1 << pin;
 19                 gpio_pinwrite(base,pin, config->outputLogic);/* 设置默认输出
    电平 */
 20         }
 21 }
 22 
 23  /*
 24   * @description         : 读取指定GPIO的电平值 。
 25   * @param - base        : 要读取的GPIO组。
 26   * @param - pin         : 要读取的GPIO脚号。
 27   * @return              : 无
 28   */
 29  int gpio_pinread(GPIO_Type *base, int pin)
 30  {
    
    
 31          return (((base->DR) >> pin) & 0x1);
 32  }
 33 
 34  /*
 35   * @description         : 指定GPIO输出高或者低电平 。
 36   * @param - base        : 要输出的的GPIO组。
 37   * @param - pin         : 要输出的GPIO脚号。
 38   * @param - value       : 要输出的电平,1 输出高电平, 0 输出低低电平
 39   * @return              : 无
 40   */
 41 void gpio_pinwrite(GPIO_Type *base, int pin, int value)
 42 {
    
    
 43          if (value == 0U)
 44          {
    
    
 45                  base->DR &= ~(1U << pin); /* 输出低电平 */
 46          }
 47          else
 48          {
    
    
 49                  base->DR |= (1U << pin); /* 输出高电平 */
 50          }
 51 }
 52 
 53 

文件 gpio.c 中有三个函数: gpio_init、 gpio_pinread 和 gpio_pinwrite。
gpio_init:用于初始化指定的GPIO引脚,实际上就是配置的是GDIR寄存器,此函数的三个参数含义如下:
base: 要初始化的GPIO所属于的GPIO 组,我们本实验中使用的“UART1_CTS”引脚即GPIO1_IO18就属于 GPIO1 组。
pin:要初始化GPIO在组内的标号,GPIO1_IO18在组内的编号就是18。
config: 要初始化的GPIO配置结构体,用来指定GPIO配置为输出还是输入。
gpio_pinread:读取指定的GPIO值,即获取DR寄存器的指定位,此函数有两个参数和一个返回值,含义如下:
Base:要读取的GPIO所属于的GPIO组,GPIO1_IO18属于GPIO1组。
pin:要读取的GPIO在组内的标号,GPIO1_IO18 在组内的编号即18。

返回值:读回GPIO值,为0或者1。

gpio_pinwrite:控制指定的GPIO引脚输出高电平(1)或者低电平(0),即设置DR寄存器 的指定位,此函数的三个参数含义如下:
Base:要设置的GPIO所属于的GPIO组,GPIO1_IO18属于GPIO1组。
pin:要设置的 GPIO在组内的标号,GPIO1_IO18 在组内的编号就是18。
Value:要设置的值,1(高电平)或者0(低电平)。

在之后的应用程序中,我们如需gpio功能,都会用到此驱动来读或写GPIO。
部分截图图 9。
在这里插入图片描述

图 9

添加之后保存并退出。
然后使用命令“mkdir drivers/key”在drivers驱动目录下新建“key”文件夹。按键驱动都放在这个目录下。如图 10所示:
在这里插入图片描述

图 10

然后使用命令“vi drivers/key/key.h”新建“key.h”文件,如图 11所示:
在这里插入图片描述

图 11

然后再在key.h里添加如下内容:

  1 #ifndef _BSP_KEY_H
  2 #define _BSP_KEY_H
  3 #include "imx6ul.h"
  4 
  5 /* 定义按键值 */
  6 enum keyvalue{
    
    
  7         KEY_NONE   = 0,
  8         KEY0_VALUE,
  9         KEY1_VALUE,
 10         KEY2_VALUE,
 11 };
 12 
 13 /* 函数声明 */
 14 void key_init(void);
 15 int key_getvalue(void);
 16 
 17 
 18 #endif

这里定义了一个枚举类型“keyvalue”,代表不同的按键,由于开发板上只有一个gpio功能按键,所以我们只用到KEY0_VALUE,剩下的是一些函数声明,添加后如图 12所示:
在这里插入图片描述

图 12

然后保存退出,之后使用命令“vi drivers/key/key.c”新建key.c文件。如图 13所示:
在这里插入图片描述

图 13

添加内容如下:

  1 #include "key.h"
  2 #include "gpio.h"
  3 #include "delay.h"
  4 
  5 /*
  6  * @description : 初始化按键
  7  * @param               : 无
  8  * @return              : 无
  9  */
 10 void key_init(void)
 11 {
    
    
 12         gpio_pin_config_t key_config;
 13 
 14         /* 1、初始化IO复用, 复用为GPIO1_IO18 */
 15         IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);
 16 
 17         /* 2、、配置UART1_CTS_B的IO属性 
 18          *bit 16:0 HYS关闭
 19          *bit [15:14]: 11 默认22K上拉
 20          *bit [13]: 1 pull功能
 21          *bit [12]: 1 pull/keeper使能
 22          *bit [11]: 0 关闭开路输出
 23          *bit [7:6]: 10 速度100Mhz
 24          *bit [5:3]: 000 关闭输出
 25          *bit [0]: 0 低转换率
 26          */
 27         IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);
 28 
 29         /* 3、初始化GPIO */
 30         //GPIO1->GDIR &= ~(1 << 18);    /* GPIO1_IO18设置为输入 */      
 31         key_config.direction = kGPIO_DigitalInput;
 32         gpio_init(GPIO1,18, &key_config);
 33 
 34 }
 35 
 36 /*
 37  * @description : 获取按键值 
 38  * @param               : 无
 39  * @return              : 0 没有按键按下,其他值:对应的按键值
 40  */
 41 int key_getvalue(void)
 42 {
    
    
 43         int ret = 0;
 44         static unsigned char release = 1; /* 按键松开 */
 45 
 46         if((release==1)&&(gpio_pinread(GPIO1, 18) == 0))                /* KEY0         */
 47         {
    
    
 48                 delay(10);              /* 延时消抖             */
 49                 release = 0;    /* 标记按键按下 */
 50                 if(gpio_pinread(GPIO1, 18) == 0)
 51                         ret = KEY0_VALUE;
 52         }
 53         else if(gpio_pinread(GPIO1, 18) == 1)
 54         {
    
    
 55                 ret = 0;
 56                 release = 1;    /* 标记按键释放 */
 57         }
 58 
 59         return ret;
 60 }

此文件一共有两个函数key_init 和 key_getvalue:
key_init:用来初始化KEY所使用的 GPIO。我们查阅手册可以知道,引脚UART1_CTS需要复用成GPIO1_IO18来使用,IO速度配置成100MHz,默认22K上拉。
key_getvalue:用来获取UART1_CTS引脚的电平状态,只有一个返回值,返回0代表没有被按下,反之不是0代表被按下。函数中静态局部变量release 表示按键是否释放,即按键是否弹起。

在这里我们要注意,我们印象中按键按下弹起的过程,电压是瞬间由高到低,由低变高。如图 14所示:
在这里插入图片描述

图 14

但是时间上,当类似按键这种机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。因而在闭合及断开的瞬间均伴随有一连串的抖动,图 15是按键按下弹起瞬间电压效果图:
在这里插入图片描述

图 15

抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。这个时间对于CPU来说就非常长了,如果程序一直在循环读IO电平值的话,会引起程序多次误读。
为了不产生这种现象,我们需要在软件上添加按键消抖。原理很简单,我们可以了解到,按键按下后有一段时间会产生抖动,所以我们需要在读取到引脚电平发生变化后,跳过这段时间,再去读取一次引脚的电平值。

程序检测到按键由高变低后,第48行做了延时10ms的工作。第50行重新读取电平状态,确定按下后再返回按键实际状态。
部分截图如图 16所示:
在这里插入图片描述

图 16

修改之后保存退出。
然后使用命令“vi main.c”修改主函数。如图 17所示:
在这里插入图片描述

图 17

修改内容如下。

  1 #include "clk.h"
  2 #include "delay.h"
  3 #include "led.h"
  4 #include "beep.h"
  5 #include "key.h"
  6 
  7 /*
  8  * @description : main函数
  9  * @param               : 无
 10  * @return              : 无
 11  */
 12 int main(void)
 13 {
    
    
 14         int i = 0;
 15         int keyvalue = 0;
 16         unsigned char led_state = OFF;
 17         unsigned char beep_state = OFF;
 18 
 19         clk_enable();           /* 使能所有的时钟                       */
 20         led_init();              /* 初始化led                    */
 21         beep_init();            /* 初始化beep                   */
 22         key_init();              /* 初始化key                    */
 23 
 24         while(1)
 25         {
    
    
 26                 keyvalue = key_getvalue();
 27                 if(keyvalue)
 28                 {
    
    
 29                         switch ((keyvalue))
 30                         {
    
    
 31                                 case KEY0_VALUE:
 32                                         beep_state = !beep_state;
 33                                         beep_switch(beep_state);
 34                                         break;
 35                         }
 36                 }
 37 
 38                 i++;
 39                 if(i==50)
 40                 {
    
    
 41                         i = 0;
 42                         led_state = !led_state;
 43                         led_switch(LED0, led_state);
 44                 }
 45                 delay(10);
 46         }
 47 
 48         return 0;
 49 }

我们在main.c里添加key.h头文件,然后主函数中添加初始化key函数,然后在while(1)循环中扫描按键,当按键按下时就打开或关闭蜂鸣器。部分截图如图 18所示:
在这里插入图片描述

图 18

然后保存并退出。在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46635880/article/details/108746704