基于linux平台的嵌入式开发每日一练(八)

今天是2020.08.07 星期五 阵雨。
第5、6、7节讲解了在i.mx6ul开发板进行裸机编程,并且基于LED和BEEP的驱动学习了i.mx6ul芯片引脚的GPIO功能的一个子功能–输出功能。本节我们再来学习GPIO功能的另一个子功能–输入功能。以按键驱动为例子。

一、分析按键硬件原理图,梳理按键输入给你实现的条件

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

二、编写按键驱动,并实现使用按键控制蜂鸣器实验

沿用上一节工程,在bsp文件夹中创建key和gpio两个文件夹。按键的相关驱动放在key文件夹中。另外我们对FGPIO的操作编写一个函数集合(即是GPIO驱动文件)放在GPIO文件夹中。

  • 创建bsp_gpio.c和bsp_gpio.h两个文件并保存到GPIO文件夹中。
    新建bsp_gpio.h、bsp_gpio.c文件
    vim bsp_gpio.h
    vim bsp_gpio.c
    编写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文件内容:

#include "bsp_gpio.h"
//GPIO初始化
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);/* 默认输出电平 */
	}
 }
//读取指定 GPIO 的电平值
int gpio_pinread(GPIO_Type *base, int pin)
  {
 	 return (((base->DR) >> pin) & 0x1);
 }
//指定 GPIO 输出高或者低电平
 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。

  • 创建bsp_key.h和bsp_key.c文件并保存到bsp/key文件夹中
    vim bsp_key.h
    vim bsp_key.c
    编写bsp_key.h内容:
 #ifndef _BSP_KEY_H
 #define _BSP_KEY_H
 #include "imx6ul.h"
	 /* 定义按键值 */
	 enum keyvalue{
	 KEY_NONE = 0,
	 KEY0_VALUE,//默认是1
	 };
	 /* 函数声明 */
	 void key_init(void);
	 int key_getvalue(void);
 #endif

编写bsp_key.c文件内容:

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

//初始化按键
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 为输入功能。

  • 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。

三、编写Makefile文件、链接文件并编译烧录程序

Makefile 使用上一节编写的通用 Makefile,修改变量 TARGET 为 key,在变量 INCDIRS和 SRCDIRS 中追加“bsp/gpio” 和“bsp/key”,修改完成以后如下所示:

1 CROSS_COMPILE ?= arm-linux-gnueabihf-
2 TARGET ?= key
3 
4
/* 省略掉其它代码...... */
5 
6
INCDIRS := imx6ul \
7 bsp/clk \
8 bsp/led \
9 bsp/delay \
10 bsp/beep \
11 bsp/gpio \
12 bsp/key
13
14 SRCDIRS := project \
15 bsp/clk \
16 bsp/led \
17 bsp/delay \
18 bsp/beep \
19 bsp/gpio \
20 bsp/key
21
22 /* 省略掉其它代码...... */
23
24 clean:
25 rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

第 2 行修改变量 TARGET 为“key”,也就是目标名称为“key”。
第 11、 12 行在变量 INCDIRS 中添加 GPIO 和按键驱动头文件(.h)路径。
第 19、 20 行在变量 SRCDIRS 中添加 GPIO 和按键驱动文件(.c)路径。
链接脚本就使用上一节中的链接脚本文件 imx6ul.lds 即可。

  • 编译
make
  • 下载
 chmod 777 imxdownload //给予 imxdownload 可执行权限,一次即可
./imxdownload key.bin /dev/sdd //烧写到 SD 卡中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值