Linux之ARM(MX6U)裸机之按键输入实验(GPIO的输入、输出)

前面几章试验都是讲解如何使用 I.MX6U 的 GPIO 输出控制功能,I.MX6U 的 IO 不仅能作 为输出,而且也可以作为输入。I.MX6U-ALPHA 开发板上有一个按键,按键连接了一个 IO,将 这个 IO 配置为输入功能,读取这个 IO 的值即可获取按键的状态(按下或松开)。

1.按键输入简介

按键就两个状态:按下或弹起,将按键连接到一个 IO 上,通过读取这个 IO 的值就知道按 键是按下的还是弹起的。至于按键按下的时候是高电平还是低电平要根据实际电路来判断。
I.MX6U-ALPHA 开发板上有一个按键 KEY0,我们将会编写代码通过这个 KEY0 按键 来控制开发板上的蜂鸣器,按一下 KEY0 蜂鸣器打开,再按一下蜂鸣器就关闭。

2. 硬件原理分析

用到的硬件有以下几种:
1) LED 灯 LED0。
2)蜂鸣器。
3)1 个按键 KEY0
原理图如下:在这里插入图片描述
在这里插入图片描述

按键 KEY0 是连接到 I.MX6U 的 UART1_CTS 这个 IO 上的,KEY0 接了一个 10K 的上拉电阻,因此 KEY0 没有按下的时候 UART1_CTS 应该是高电平,当 KEY0 按下以后 UART1_CTS 就是低电平。

配置寄存器位GPIO:
在这里插入图片描述
配置电气属性
在这里插入图片描述
在这里插入图片描述

描述
*bit 16:0 HYS 关闭
*bit [15:14]11 默认 22K 上拉
*bit [13]1 pull 功能
*bit [12]1 pull/keeper 使能
*bit [11]0 关闭开路输出
*bit [7:6]10 速度 100Mhz
*bit [5:3]000 关闭输出
*bit [0]0 低转换率

3.实验程序编写

基于在(蜂鸣器试验)的基础复制一下,重新创建 VSCode 工程,工作区名字为“key”, 在工程目录的 bsp 文件夹中创建名为“key”和“gpio”两个文件夹。按键相关的驱动文件都放 到“key”文件夹中,本章试验我们对 GPIO 的操作编写一个函数集合,也就是编写一个 GPIO 驱动文件,GPIO 的驱动文件放到“gpio”文件夹里面。
新建 bsp_gpio.c 和 bsp_gpio.h 这两个文件,将这两个文件都保存到刚刚创建的 bsp/gpio 文 件夹里面,

3.1编写bsp_gpio.h

#ifndef __BSP_GPIO_H
#define __BSP_GPIO_H
#include "imx6ul.h"


/*枚举类型和结构体定义*/
typedef enum _gpio_pin_direction
{
   kGPIO_DigitalInput = 0U,     /*输入*/
   kGPIO_DigitalOutput = 1U,    /*输出*/

} gpio_pin_direction_t;

/*GPIO配置结构体*/
typedef struct _gpio_pin_config
{
   gpio_pin_direction_t direction;   /*GPIO方向:输入还是输出*/
   uint8_t outputLogic;              /*如果是输出的话,默认输出电平*/

} gpio_pin_config_t;

/*函数声明*/

void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config);
int gpio_pinread(GPIO_Type *base, int pin);
void gpio_pinwrite(GPIO_Type *base, int pin, int value);


#endif

bsp_gpio.h 中定义了一个枚举类型 gpio_pin_direction_t 和结构体 gpio_pin_config_t,枚举类 型 gpio_pin_direction_t 表示 GPIO 方向,输入或输出。结构体 gpio_pin_config_t 是 GPIO 的配置 结构体,里面有 GPIO 的方向和默认输出电平两个成员变量。

3.2编写bsp_gpio.c

#include "bsp_gpio.h"

/*
 * @description : GPIO 初始化。
 * @param - base : 要初始化的 GPIO 组。
 * @param - pin : 要初始化 GPIO 在组内的编号。
 * @param - config : GPIO 配置结构体。
 * @return : 无
 */


void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
{
   
    if(config->direction == kGPIO_DigitalInput)   /* 输入 */
     {
         base->GDIR &= ~(1 << pin);
     }
    else
    {
        base->GDIR |= 1 << pin;
        gpio_pinwrite(base,pin, config->outputLogic);/*默认输出电平*/
    }
    
}

/*
 * @description : 读取指定 GPIO 的电平值 。
 * @param – base : 要读取的 GPIO 组。
 * @param - pin : 要读取的 GPIO 脚号。
 * @return : 无
 */


int gpio_pinread(GPIO_Type *base, int pin)
{

    return (((base->DR) >> pin) & 0x1);
}

/*
 * @description : 指定 GPIO 输出高或者低电平 。
 * @param – base : 要输出的的 GPIO 组。
 * @param - pin : 要输出的 GPIO 脚号。
 * * @param – value : 要输出的电平, 1 输出高电平, 0 输出低低电平
 * @return : 无
 */

void gpio_pinwrite(GPIO_Type *base, int pin, int value)
{

    if(value == 0U)
    {
        base->DR &= ~(1U << pin);   /*  输出低电平*/
    }
    else
    {
        base->DR |= (1U << pin);   /*输出高点平*/
    }
    
}

文件 bsp_gpio.c 中有三个函数:gpio_init、gpio_pinread 和 gpio_pinwrite,函数 gpio_init 用 于初始化指定的 GPIO 引脚,最终配置的是 GDIR 寄存器,此函数有三个参数,这三个参数的 含义如下:

参数含义
base要初始化的 GPIO 所属于的 GPIO 组,比如 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(低电平)。

接下来编写按键驱动文件,新建 bsp_key.c 和 bsp_key.h 这两个文件,将这两个文件都保存 到刚刚创建的 bsp/key 文件夹里面,

3.3编写bsp_key.h

#ifndef __BSP_KEY_H
#define __BSP_KEY_H

#include "imx6ul.h"

 /* 定义按键值 */ 
 enum keyvalue{ 
     KEY_NONE   = 0, 
     KEY0_VALUE, 
 };
/*函数声明*/

 void key_init(void); 
 int key_getvalue(void); 
 
#endif // !__BSP_KEY_H

bsp_key.h 文件中定义了一个枚举类型:keyvalue,此枚举类型表示按键值,因为 I.MX6UALPHA 开发板上只有一个按键,因此枚举类型里面只到 KEY0_VALUE。

3.4编写bsp_key.c

#include "bsp_key.h"
#include "bsp_gpio.h"
#include "bsp_delay.h"

/*KEY初始化*/
void key_init(void)
{

   gpio_pin_config_t key_config;

   /* 1、初始化 IO 复用, 复用为 GPIO1_IO18 */ 
   IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0); 

   /* 2、、配置 UART1_CTS_B 的 IO 属性  
    *bit 16:0 HYS 关闭 
    *bit [15:14]: 11 默认 22K 上拉 
    *bit [13]: 1 pull 功能 
    *bit [12]: 1 pull/keeper 使能 
    *bit [11]: 0 关闭开路输出 
    *bit [7:6]: 10 速度 100Mhz 
    *bit [5:3]: 000 关闭输出 
    *bit [0]: 0 低转换率 
    */ 

   IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xF080);  
   
   /* 3.初始化GPIO GPIO1_IO18设置为输入*/
   key_config.direction = kGPIO_DigitalInput;
   gpio_init(GPIO1,18, &key_config);

}

int key_getvalue(void)
{
   int ret = 0;
   static unsigned char release = 1;   /*按键松开*/

   if((release==1)&&(gpio_pinread(GPIO1, 18)== 0))  /*KEY0按下*/
   {
       delay(10);
       release = 0;
       if(gpio_pinread(GPIO1, 18)== 0)
       {
         ret= KEY0_VALUE;
       }
   }
   else if (gpio_pinread(GPIO1, 18)==1)   /* KEY0 未按下 */ 
   {
       ret = 0;
       release = 1;   /*  标记按键释放*/
   }
    
    return ret;
}

bsp_key.c 中一共有两个函数:key_init 和 key_getvalue,key_init 是按键初始化函数,用来 初始化按键所使用的 UART1_CTS 这个 IO。函数 key_init 先设置 UART1_CTS 复用为 GPIO1_IO18,然后配置 UART1_CTS 这个 IO 为速度为 100MHz,默认 22K 上拉。最后调用函 数 gpio_init 来设置 GPIO1_IO18 为输入功能。
函数 key_getvalue 用于获取按键值,此函数没有参数,只有一个返回值,返回值表示按键 值,返回值为 0 的话就表示没有按键按下,如果返回其他值的话就表示对应的按键按下了。获 取按键值其实就是不断的读取 GPIO1_IO18 的值,如果按键按下的话相应的 IO 被拉低,那么 GPIO1_IO18 值就为 0,如果按键未按下的话 GPIO1_IO18 的值就为 1。此函数中静态局部变量 release 表示按键是否释放。

3.5修改main.c

#include "mian.h"
#include "bsp_clk.h"
#include "bsp_led.h"
#include "bsp_delay.h"
#include "bsp_beep.h"
#include "bsp_key.h"








int main(void)
{
    int i =0;
    int keyvalue =0 ;
    unsigned char led_state = OFF;
    unsigned char beep_state = OFF;

    clk_enable();     /* 使能所有的时钟     */ 
    led_init();        /* 初始化 led          */ 
    beep_init();      /* BEEP初始化*/
    key_init();        /* 初始化 key      */ 
    while (1)
    {
       keyvalue = key_getvalue();
       if(keyvalue)
       {
           switch (keyvalue)
           {
               case KEY0_VALUE:
                   beep_state = !beep_state;
                   beep_switch(beep_state);
                   break;
           }
       }
       i++;
       if(i==50)
       {
           i=0;
           led_state = !led_state;
           led_switch(LED0, led_state);
       }

       delay(10);
    }
    
    return 0;
}

main.c 函数先初始化 led 灯、蜂鸣器和按键,然后在 while(1)循环中不断的调用函数 key_getvalue 来读取按键值,如果 KEY0 按下的话就打开/关闭蜂鸣器。LED0 作为系统提示指 示灯闪烁,闪烁周期大约为 500ms。

4. 编译下载验证

4.1编写 Makefile

CROSS_COMPILE 	?= arm-linux-gnueabihf-
TARGET		  	?= key

CC 				:= $(CROSS_COMPILE)gcc
LD				:= $(CROSS_COMPILE)ld
OBJCOPY 		:= $(CROSS_COMPILE)objcopy
OBJDUMP 		:= $(CROSS_COMPILE)objdump

INCDIRS 		:= imx6ul \
				   bsp/clk \
				   bsp/led \
				   bsp/delay \
				   bsp/beep\
				   bsp/gpio\
				   bsp/key
				   			   
SRCDIRS			:= project \
				   bsp/clk \
				   bsp/led \
				   bsp/delay \
				   bsp/beep\
				   bsp/gpio\
				   bsp/key
				   
				   
INCLUDE			:= $(patsubst %, -I %, $(INCDIRS))

SFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))

SFILENDIR		:= $(notdir  $(SFILES))
CFILENDIR		:= $(notdir  $(CFILES))

SOBJS			:= $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS			:= $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS			:= $(SOBJS) $(COBJS)

VPATH			:= $(SRCDIRS)

.PHONY: clean
	
$(TARGET).bin : $(OBJS)
	$(LD) -Timx6ul.lds -o $(TARGET).elf $^
	$(OBJCOPY) -O binary -S $(TARGET).elf $@
	$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis

$(SOBJS) : obj/%.o : %.S
	$(CC) -Wall -nostdlib -c -O2  $(INCLUDE) -o $@ $<

$(COBJS) : obj/%.o : %.c
	$(CC) -Wall -nostdlib -c -O2  $(INCLUDE) -o $@ $<
	
clean:
	rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

4.2链接脚本编写

ECTIONS{
    . = 0x87800000;
    .text :
    {
        obj/start.o
        *(.text)

    }
    .rodata ALIGN(4) : {*(.rodata*)}
    .data ALIGN(4)  : {*(.data)}
    . = ALIGN(4) ;
    __bss_start = .;
    .bss ALIGN(4) : { *(.bss) *(COMMON)}
    __bss_end = .;
    

}

这里注意bss段需要四字节对其,否则会清除其他字段的内容,造成程序的崩溃

4.3 编译下载

使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 key.bin 文件 下载到 SD 卡中,命令如下:

chmod 777 imxdownload   //给予 imxdownload 可执行权限,一次即可
 ./imxdownload key.bin /dev/sdd  //烧写到 SD 卡中 

烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板。如果代码运行正常的 话 LED0 会以大约 500ms 周期闪烁, 按下开发板上的 KEY0 按键,蜂鸣器打开,再按下 KEY0 按键,蜂鸣器关闭。

具体烧写到SD卡的详细操作请看(SD卡烧写)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值