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

发布者:Jinyu2022最新更新时间:2021-10-27 来源: eefocus关键字:Linux  ARM  按键输入  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 的原理图如图 15.2.1 所示:

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


配置寄存器位GPIO:

配置寄存器的电器属性:

image.png

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_KEY_H

#define __BSP_KEY_H


#include "imx6ul.h"


typedef enum _gpio_pin_direction {


    kGPIO_DigitalInput = 0U,  /*输入*/

    kGPIO_DigitalOutput = 1U,  /*输出*/


}gpio_pin_direction_t;


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_KEY_H


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<

    }

    else

    {

        base->DR |= (1U << pin);  /*输出高电平*/

    }

    

}


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

image.png

函数 gpio_pinread 是读取指定的 GPIO 值,也就是读取 DR 寄存器的指定位,此函数有两个参数和一个返回值,参数含义如下:

image.png

函数 gpio_pinwrite 是控制指定的 GPIO 引脚输入高电平(1)或者低电平(0),就是设置 DR 寄存器的指定位,此函数有三个参数,参数含义如下:

image.png

我们以后就可以使用函数 gpio_init 设置指定 GPIO 为输入还是输出,使用函数 gpio_pinread和 gpio_pinwrite 来读写指定的 GPIO


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


3.3、gpio_key.h

#ifndef __BSP_KEY_H

#define __BSP_KEY_H


#include "imx6ul.h"

#include "bsp_delay.h"


/*定义按键值*/

enum keyvalue {

    KEY_NONE =0,

    KEY_VALUE ,

};


/*函数声明*/

void key_init();

int key_get_value();


#endif // !__BSP_KEY_H


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


3.4、gpio_key.c

#include "bsp_key.h"


/*

 * @description : 初始化按键

 * @param : 无

 * @return : 无

 */


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);


}


/*

* @description : 获取按键值

* @param : 无

* @return : 0 没有按键按下,其他值:对应的按键值

*/

int key_get_value(void)

{

    int ret =0;

    static unsigned char release =1; /*按键松开*/


    if((release == 1) &&  (gpio_pin_read(GPIO1,18) == 0))

    {

        delay(10);  /**/

        release = 0;

        if(gpio_pin_read(GPIO1,18) == 0)

        {

            ret = KEY_VALUE;

        }


    }

    else if(gpio_pin_read(GPIO1,18) == 1)

    {

        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 "main.h"


int main() 

{

    int i=0;

    int keyvalue=0;   

    unsigned char led_status= OFF;

    unsigned char beep_status= OFF;


    clk_enable();  //使能外设时钟

    led_init(); //初始化LED

    init_beep();//初始化蜂鸣器

    key_init(); //初始化key

    

    while(1)

    {

        keyvalue = key_getvalue();

        if(keyvalue)

        {

            switch (keyvalue)

            {

            case KEY_VALUE:

                beep_status=!beep_status;

                beep_switch(beep_status);

                break;

            

            default:

                break;

            }

        }

        

        i++;

        if(i==50)

        {

            i=0;

            led_status=!led_status;

            led_switch(LED0,led_status);

        }


    }


    return 0;

}


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


4、编译下载验证

4.1、连接脚本的编写

SECTIONS

{

    . = 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.2、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/key

   bsp/gpio 

   

   

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:


4.3、编译下载

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


chmod 777 imxdownload              //给予 imxdownload 可执行权限,一次即可

./imxdownload key.bin  /dev/sdd    //烧写到 SD 卡中


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

关键字:Linux  ARM  按键输入  GPIO 引用地址:Linux之ARM(IMX6U)裸机按键输入实验(GPIO的输出与输入)

上一篇:Linux之ARM(IMX6U)裸机主频和时钟配置
下一篇:Linux之ARM(IMX6U)裸机C语言蜂鸣器驱动实验--驱动编写,编译

推荐阅读最新更新时间:2024-11-18 18:42

STM32L--GPIO
1. 每个GPIO均有以下寄存器: 4个32位配置寄存器:GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR和GPIOx_PUPDR GPIOx_MODER :配置IO端口方向为输入/输出/AF/模拟 GPIOx_OTYPER :选择输出类型:推挽/开漏 GPIOx_OSPEEDR :选择IO速度(与IO端口方向无关) GPIOx_PUPDR :选择上拉/下拉电阻(与IO端口方向无关) 2个32位数据寄存器:GPIOx_IDR、GPIOx_ODR 1个32位置位/复位寄存器:GPIOx_BSRR(使用该寄存器读写寄存器可以避免在读写期间被IRQ中断,该读写操作属于一个原子操作) 该寄存器
[单片机]
STM32L--<font color='red'>GPIO</font>
Arm大陆出货10年增长百倍 CEO:看好物联网爆发式增长
Arm最近把过去的“ARM”改成“arm”,企业标志改版了,看起来更灵活弹性。因为5G与物联网(IoT),Arm持续投入研发,也将过去占据手机95%以上市场的实力,持续转移到新兴的物联网领域。尤其,面对竞争对手英特尔(Intel)在大陆加强布局,日前Arm也宣布在大陆设立合资公司,将让大陆有机会参与决定下一代芯片技术的架构、规格和标准。 Arm CEO Simon Segars近日接受大陆媒体专访时表示,被软银(SoftBank)收购后,Arm加大内部研发投入,加速物联网业务布局。目前物联网普及力道低于预期,仅完成约20%;同时物联网应用不只局限在智能家庭;Arm在大陆设立合资公司,即欲加快大陆市场布局。 Simon Se
[半导体设计/制造]
MDK-ARM代码格式化插件AStyle
今天分享两点内容: 1.一个代码格式化插件【AStyle】 --- 来自关注我的朋友推荐! 2.STM32时钟及注意事项; 1AStyle插件 前两天,一位关注我的朋友(*inbun Yi*)给我推荐了这款AStyle插件,我当时看了下感觉还可以。于是,下来就下载并添加到MDK-ARM中试用了一下,挺好用的。所以,这里也给大家推荐一下。 代码格式化插件,顾名思义就是格式化代码,简单理解就是对代码进行排版的插件。比如:代码缩进。 插件下载地址: http://astyle.sourceforge.net/ 具体下载安装过程我就不说了,可以参考: https://zhuanlan.zhihu.com/p/23012
[单片机]
MDK-<font color='red'>ARM</font>代码格式化插件AStyle
ch32和gd32哪个好用?
Ch32和Gd32是两个比较常见的芯片系列,都是基于ARM Cortex-M3内核设计的,因此具有类似的特点和性能。在选择使用哪个芯片时,需要根据具体的项目需求和开发难度加以考虑。 首先,我们来简单介绍一下这两个芯片系列的特点。Ch32是中国厂商江苏长鹰半导体公司生产的一款芯片,可以实现信号的高速处理和计算机视觉应用,广泛应用于机器人、智能家居、智能驾驶等领域。Gd32则是由中国厂商北京兆易创新科技有限公司生产的芯片,主要应用于工控、嵌入式、智能家居、智能穿戴等领域。 在开发难度方面,刚开始学习嵌入式开发的初学者可能会觉得Gd32更加好用,因为它有完善的开发工具链和丰富的文档资料,对于初学者来说更加友好。Ch32的开发工具链和文档
[单片机]
基于ARM芯片LPC2214和μC/OS-II实现数字微波监控系统的设计
随着嵌入式系统开发的普及和深入,在更加复杂的应用中传统软件开发手段难以满足需求,嵌入式操作系统在开发中扮演着越来越重要的角色,已经被广泛应用于手机、移动计算机设备、网络设备和工控仿真等领域。嵌入式操作系统μC/OS-II源码是公开的,而且它是可移植、可固化、可裁减及可剥夺型的多任务实时内核,可用于各类8位、16位和32位单片机和DSP,目前得到广泛应用。本文给出一种数字微波设备监控系统的设计,该系统引入μC/OS-II之后,系统的开发效率得到提高,整个系统的健壮性得到增强,文中对软件设计应用中遇到的关键问题作了深入讨论并给出了相应的解决方案 1 数字微波设备监控系统的设计 微波通信是一种利用微波传输信息的通信手段,数字微波采用
[单片机]
基于<font color='red'>ARM</font>芯片LPC2214和μC/OS-II实现数字微波监控系统的设计
ARM总线方面知识
AMBA简介 随着深亚微米工艺技术日益成熟,集成电路芯片的规模越来越大。数字IC从基于时序驱动的设计方法,发展到基于IP复用的设计方法,并在SOC设计中得到了广泛应用。在基于IP复用的SoC设计中,片上总线设计是最关键的问题。为此,业界出现了很多片上总线标准。其中,由ARM公司推出的AMBA片上总线受到了广大IP开发商和SoC系统集成者的青睐,已成为一种流行的工业标准片上结构。AMBA规范主要包括了AHB(Advanced High performance Bus)系统总线和APB(Advanced Peripheral Bus)外围总线。 AMBA片上总线 AMBA 2.0规范包括四个部分:AHB、ASB、APB和Test
[嵌入式]
TI收购Luminary, 又进ARM快车道
  如果有人说:“一个人平均每天会接触超过300个MCU,”你一定以为他是电子发烧友。但当德州仪器(TI)副总裁兼高级嵌入式控制产品部总经理Brian Crutcher在你面前历数出来时,你才发现原来这个看似高科技的玩意已经弥漫在我们周围了。而且,MCU的利润一直不错,Microchip过去十年在8位单片机市场上的成功就是明证。 TI副总裁兼高级嵌入式控制产品部总经理Brian Crutcher   也正因此,在经济并不景气的环境下,TI正在转变经营策略——优化嵌入式市场。据Gartner公司统计,2008年TI微控制器销售收入是7.2亿多美元,在全球排名第8。与DSP和模拟业务相比,这样的成绩似乎并不能使TI满意,为了
[单片机]
另类的天才——ARM公司传奇
  西方有句谚语:条条大道通罗马。讲的是做一件事情可以用不同的方法达到同样效果,类似于我们今天说的多元化的思维。而在集成电路发展的历史中,这样多元思维的传奇企业并不多:台积电的代工算一个,因为它将设计与制造分离开来;而英国ARM公司开创的IP授权模式,则赋予整个的半导体行业另类的创意!他的传奇或许只是刚刚开始。   ARM的意思是Advanced RISC Machine。公司成立于1990年11月,是苹果电脑,Acorn电脑集团和VLSI Technology的合资企业。Acorn曾推出世界上首个商用单芯片RISC处理器,而苹果电脑当时希望将RISC技术应用于自身系统,ARM微处理器新标准因此应运而生。   80年代末9
[电源管理]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved