前面几篇文章试验都是讲解如何使用 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:
配置寄存器的电器属性:
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 寄存器,此函数有三个参数,这三个参数的含义如下: 函数 gpio_pinread 是读取指定的 GPIO 值,也就是读取 DR 寄存器的指定位,此函数有两个参数和一个返回值,参数含义如下: 函数 gpio_pinwrite 是控制指定的 GPIO 引脚输入高电平(1)或者低电平(0),就是设置 DR 寄存器的指定位,此函数有三个参数,参数含义如下: 我们以后就可以使用函数 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(IMX6U)裸机主频和时钟配置
下一篇:Linux之ARM(IMX6U)裸机C语言蜂鸣器驱动实验--驱动编写,编译
推荐阅读最新更新时间:2024-11-18 18:42
设计资源 培训 开发板 精华推荐
- DC1791A-D,基于 LTM2887-5I 的演示板,5V 电源,I2C 模块隔离器
- KA7805AE负输出电压电路的典型应用
- PAM8124EVB,基于PAM8124 15W高效D类音频功率放大器的评估板
- 显示 A8514 LED 驱动器计算值的典型应用
- 用于看门狗微控制器操作的 LTC3555EUFD-1 PowerPath 管理器的典型应用电路
- 使用 Infineon Technologies AG 的 OM7631NM 的参考设计
- LM2904VDR2G 电压基准运算放大器的典型应用
- 使用L6564H的25W宽范围高功率因数降压-升压转换器演示板
- AD8041-EVALZ,评估板经过精心布局和测试,证明可以实现 AD8041 器件规定的高速性能
- OP113ESZ-REEL7 多媒体声音编解码器耳机输出放大器典型应用