I.MX6ULL的蜂鸣器实验-GPIO输入实验

系列文章目录

驱动开发中引入私有数据的原因



一、前言

I.MX6ULL的 IO 不仅能作为输出,而且也可以作为输入。I.MX6U-ALPHA 开发板上有一个按键,按键连接了一个 IO,将这个 IO 配置为输入功能,读取这个 IO 的值即可获取按键的状态(按下或松开)。通过这个按键来控制蜂鸣器的开关,将 I.MX6UL 的 IO 作为输入来使用。


二、按键输入简介

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


三、硬件原理

蜂鸣器硬件原理
LED硬件原理

按键 KEY0 的原理图如图所示
在这里插入图片描述
从图可以看出,按键 KEY0 是连接到 I.MX6U 的 UART1_CTS 这个 IO 上的,KEY0
接了一个 10K 的上拉电阻,因此 KEY0 没有按下的时候 UART1_CTS 应该是高电平,当 KEY0按下以后 UART1_CTS 就是低电平。

四、程序编写

4.1主要编写内容

1、设置UART1_CTS复用为GPIO1_IO18
2、设置UART1_CTS的电气属性。
3、配置GPIO1_IO08为输入模式。
4、读取按键值,也就是GPIO1_IO08的高低电平

4.2程序编写前提工作

程序编写前提工作参考

重新创建 VSCode 工程,工作区名字为“key”,在工程目录的 bsp 文件夹中创建名为“key”和“gpio”两个文件夹。按键相关的驱动文件都放到“key”文件夹中,将 GPIO 的操作编写一个函数集合,也就是编写一个 GPIO驱动文件,GPIO 的驱动文件放到“gpio”文件夹里面。

4.3编写gpio驱动模块

新建 bsp_gpio.c 和 bsp_gpio.h 这两个文件,将这两个文件都保存到刚刚创建的 bsp/gpio 文件夹里面,然后在 bsp_gpio.h 文件夹里面输入如下内容:

#ifndef _BSP_GPIO_H
#define _BSP_GPIO_H
#define _BSP_KEY_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 的方向和默认输出电平两个成员变量。在 bsp_gpio.c 中输入如下所示内容:

0U和1U代表无符号整数(unsigned integers)的0和1

#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 : 无
* @0U和1U代表无符号整数(unsigned integers)的0和1
*/
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(低电平)。
我们以后就可以使用函数 gpio_init 设置指定 GPIO 为输入还是输出,使用函数gpio_pinread和 gpio_pinwrite 来读写指定的 GPIO


4.4编写按键KEY驱动模块

写按键驱动文件,新建 bsp_key.c 和 bsp_key.h 这两个文件,将这两个文件都保存
到刚刚创建的 bsp/key 文件夹里面,然后在 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 文件中定义了一个枚举类型:keyvalue,此枚举类型表示按键值,因为 I.MX6UALPHA 开发板上只有一个按键,因此枚举类型里面只到 KEY0_VALUE。如果是通用的驱动的话,有多个按键 KEY1_VALUE,KEY2_VALUE等等。
在 bsp_key.c 中输入如下所示内容:

IO电器属性:0xF080表示
在这里插入图片描述

#include "bsp_key.h"
#include "bsp_gpio.h"
#include "bsp_delay.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_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。(因为DR寄存器为1,默认是高电平)DR寄存器详解此函数中静态局部变量release 表示按键是否释放。代码中的 57 行是按键消抖延时函数,延时时间大约为 10ms,用于消除按键抖动。理想型的按键电压变化过程如图所示:
在这里插入图片描述按键没有按下的时候按键值为 1,当按键在 t1 时刻按键被按下以后按键值就变为 0,这是最理想的状态。但是实际的按键是机械结构,加上刚按下去的一瞬间人手可能也有抖动,实际的按键电压变化过程如图所示:
在这里插入图片描述
在图 中 t1 时刻按键被按下,但是由于抖动的原因,直到 t2 时刻才稳定下来,t1 到
t2 这段时间就是抖动。一般这段时间就是十几 ms 左右,从图 15.3.2 中可以看出在抖动期间会有多次触发,如果不消除这段抖动的话软件就会误判,本来按键就按下了一次,结果软件读取IO 值发现电平多次跳变以为按下了多次。所以我们需要跳过这段抖动时间再去读取按键的 IO值,也就是至少要在 t2 时刻以后再去读 IO 值。在代码中 57 行是延时了大约10ms 后再去读取 GPIO1_IO18 的 IO 值,如果此时按键的值依旧是 0,那么就表示这是一次有效的按键触发。

在 main.c 中输入如下代码:

1 #include "bsp_clk.h"
2 #include "bsp_delay.h"
3 #include "bsp_led.h"
4 #include "bsp_beep.h"
5 #include "bsp_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 			i++;
38 			if(i==50)
39 				{
40 					i = 0;
41 					led_state = !led_state;
42 					led_switch(LED0, led_state);
43 				}
44 				delay(10);
45 	}
46 return 0;
47 }

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


五、编译下载验证

5.1 编写 Makefile 和链接脚本

使用通用 Makefile,修改变量 TARGET 为 key,在变量 INCDIRS和 SRCDIRS 中追加“bsp/gpio”和“bsp/key”,修改完成以后如下所示:
在这里插入图片描述在这里插入图片描述
第 2 行修改变量 TARGET 为“key”,也就是目标名称为“key”。
第 11、12 行在变量 INCDIRS 中添加 GPIO 和按键驱动头文件(.h)路径。
第 19、20 行在变量 SRCDIRS 中添加 GPIO 和按键驱动文件(.c)路径。
链接脚本就使用第bsp试验中的链接脚本文件 imx6ul.lds 即可。

5.2编译下载

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

chmod 777 imxdownload //给予 imxdownload 可执行权限,一次即可
./imxdownload key.bin /dev/sdd //烧写到 SD 卡中,不能烧写到/dev/sda 或 sda1 设备里面!

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


END
在这里插入图片描述

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值