正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-15.6讲 GPIO中断实验-GPIO驱动添加中断处理函数

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第15.6 讲” 的读书笔记。第15讲主要是介绍I.MX6U处理器GPIO中断控制实验。本节将参考正点原子的视频教程第15讲和配套的正点原子开发指南文档进行学习。

在第15.6讲视频教程中,正点原子会讲解了如何初始化gpio支持中断模式,并且如何启用gpio中断,如何关闭gpio中断,如何读取gpio的中断标志位,在中断处理结束之后如何清除gpio外设的中断标志位。

0. 概述

本章实验的功能和之前按键控制蜂鸣器的实验一样,只是按键采用中断的方式来处理。当按下KEY0以后就打开蜂鸣器,再次按下蜂鸣器KEY0就关闭蜂鸣器。

1. gpio按键电路原理分析

如之前按键KEY实验中分析的过的,正点原子I.MX6ULL ALPHA/Mini开发板的按键KEY0接 I.MX6ULL 处理器的 "UART1_CTS_B" 引脚。

当按键KEY0按下时,当默认按键松开时GPIO读取到高电平,当按键按下时GPIO读取到低电平。通过读取GPIO输入引脚的电平,当读取到低电平是说明按键KEY0被按下。

1.2 按键消抖

当然,如之前按键KEY0实验分析的那样还需要在检测到KEY0被按下时对按键进行消抖处理,防止按键按下瞬间的高低电平抖动操作按键被判断为多次误触发。

理想的按键的按键电平变化

实际按键的电平变化过程

2. 配置GPIO复用,GPIO方向

将I.MX6U处理器的 "UART1_CTS_B" 引脚配置为按键KEY0的gpio引脚输入input模式需要如下几步,我们在之前的按键实验里已经分析过,这里不再详细描述。

  1. 配置 "UART1_CTS_B" 引脚复用为 GPIO1_IO18 模式
  2. 配置"UART1_CTS_B" 引脚的电气特性,包括压摆率,下拉电阻,磁滞特性,等属性。
  3. 配置GPIOx_GIDR 寄存器,设置GPIO的输出方向是Output输出还是Input输入。
  4. 对于GPIO输出模式的话,写GPIOx_DR寄存器的对应bit位来控制GPIO的输出是低电平还是高高电平。

3. 配置GPIO中断模式

GPIO引脚作为input输入时可以根据GPIO引脚上的电平变化来触发中断,我们可以通过按键KEY0的 GPIO1_IO18 引脚的电平变化来触发gpio中断的方式来检测按键是否被按下。

在之前的按键KEY0实验里,我们通过处理器不断地循环来检测按键是否被按下,当处理器不停的循环检测按键的电平时处理器什么也不能干,这就造成了处理器资源的浪费。使用中断的方式可以极大的提高处理器系统的运行效率。

I.MX6U 处理器的GPIO输入接口中断通过寄存器 "GPIOx_ICR1, GPIOx_MR, GPIOx_ISR, GPIOx_EDGE_SEL" 来配置启用/关闭,GPIO输入中断触发类型(低电平触发,高电频触发,电平下降沿触发,电平上上沿触发,电平上升下降沿都触发)。

GPIO1_IO18 引脚的GPIO中断配置需要如下步骤:

  1. 设置GPIOx->ICR寄存器配置,对应引脚bit位的GPIO输入信号中断触发类型,选择是低电平触发,高电平触发,电平下降沿触发,还是电平上升沿触发。
  2. 设置GPIOx->MR寄存器,对应引脚bit位来使能或关闭gpio输入中断触发。
  3. 在gpio中断处理完成之后向 GPIOx->ISR 寄存器的对应引脚bit位写1,来清除gpio外设的中断标志位。

4. GPIO中断处理函数编写

如上面分析,GPIO中断驱动函数编写需要初始化GPIO引脚的IO口复用模式,IO口的电气特性,GPIO的工作模式为输入模式,GPIO口使能输入信号中断触发,GPIO口的输入信号中断触发方式,以及在处理完GPIO口的中断ID之后写1清楚对应的中断标志位。

在bsp/bsp_gpio.h中增加 GPIO 输入信号中断出发类型的枚举类型定义 ‘enum _gpio_int_mode’:

#ifndef __BSP_GPIO_H__
#define __BSP_GPIO_H__

#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "cc.h"


typedef enum _gpio_int_mode
{
	kGPIO_Noint 		 			= 0,
	kGPIO_LowInterrupt				= 1,
	kGPIO_HighInterrupt				= 2,
	kGPIO_RaisingEdgeInt			= 3,
	kGPIO_FalllingEdgeInt			= 4,
	kGPIO_FallingOrRaisingEdgeInt 	= 5,
} gpio_int_mode_t;

typedef enum _gpio_pin_direction
{
	kGPIO_DigitalOutput = 0U,	/*输出*/
	kGPIO_DigitalInput  = 1U,	/*输入*/
	
} gpio_pin_direction_t;

typedef struct _gpio_pin_config 
{
	gpio_pin_direction_t directioin;	/* GPIO 方向:输入还是输出 */
	int outputLogic; 					/* 如果是输出的话,默认输出电平 */
	gpio_int_mode_t intMode;			/* GPIO中断模式 */
} gpio_pin_config_t;


/* 初始化函数 */
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config);
void gpio_pinwrite(GPIO_Type *base, int pin, int value);
int  gpio_pinread(GPIO_Type *base, int pin);

void gpio_intmode_config(GPIO_Type *base, int pin, gpio_int_mode_t mode);
void gpio_int_enable(GPIO_Type *base, int pin);
void gpio_int_disable(GPIO_Type *base, int pin);
void gpio_int_cleanFlag(GPIO_Type *base, int pin);

#endif

在 'gpio_init()’ 初始化函数总增加gpio输入信号中断触发模式配置函数,gpio中断触发启用函数,gpio中断触发关闭函数。

#include "bsp_gpio.h"


/*
 * @description 	: GPIO初始化。
 * @param - base 	: 要初始化的寄存器组。
 * @param - pin		: 要初始化的寄存器脚号。
 * @param - config	: GPIO 配置结构体。
 * @return 			: 无
 */
void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
{
	if(config)
	{
		if(config->directioin == kGPIO_DigitalOutput){
			base->GDIR |= (1<<pin);								/* 输出 */

			gpio_pinwrite(base, pin, config->outputLogic);		/* 默认输出电平 */
		}
		else if(config->directioin == kGPIO_DigitalInput){
			base->GDIR &= ~(1<<pin);							/* 输入 */
		}

		if(config->directioin == kGPIO_DigitalInput){
			gpio_intmode_config(base, pin, config->intMode);		/* gpio中断触发方式配置 */
		}
	}
}

/*
 * @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 == 0)
		base->DR &= ~(1<<pin);
	else
		base->DR |= (1<<pin);
}

/*
 * @description 	: 读取指定 GPIO 的电平值。
 * @param – base 	: 要读取的 GPIO 组。
 * @param – pin 	: 要读取的 GPIO 脚号。
 * @return 			: 1 读取高电平, 0 读取低低电平。
 */
int  gpio_pinread(GPIO_Type *base, int pin)
{
	return ((base->DR >> pin) & 0x1);
}

/*
 * @description 	: 启用GPIO指定pin的中断。
 * @param – base 	: 要启用的 GPIO 组。
 * @param – pin 	: 要启用的 GPIO 脚号。
 * @return 			: 无。
 */
void gpio_int_enable(GPIO_Type *base, int pin)
{
	base->IMR |= (1 << pin);
}

/*
 * @description 	: 禁用GPIO指定pin的中断。
 * @param – base 	: 要禁用的 GPIO 组。
 * @param – pin 	: 要启用中断的 GPIO 脚号。
 * @return 			: 无。
 */
void gpio_int_disable(GPIO_Type *base, int pin)
{
	base->IMR &= ~(1 << pin);
}

/*
 * @description 	: 清除GPIO指定pin的中断标志。
 * @param – base 	: 要清除的 GPIO 组。
 * @param – pin 	: 要清除中断的 GPIO 脚号。
 * @return 			: 无。
 */
void gpio_int_cleanFlag(GPIO_Type *base, int pin)
{
	/* 写1清除对应的中断标志位 */
	base->ISR |= (1 << pin);
}

/*
 * @description 	: 设置GPIO中断触发类型。
 * @param – base 	: 要清除的 GPIO 组。
 * @param – pin 	: 要清除中断的 GPIO 脚号。
 * @return 			: 无。
 */
void gpio_intmode_config(GPIO_Type *base, int pin, gpio_int_mode_t mode)
{
	volatile unsigned int *icr;			/* volatile关键字要求立即写入内存,不要在寄存器中缓存 */
	unsigned int icrShift = pin;

	if(pin < 16)
	{
		icr = &base->ICR1;

	}
	else{
		icr = &base->ICR2;
		icrShift -= 16;
	}

	//我忘记了清理GPIO1->EDGESEL寄存器的对应pin
	base->EDGE_SEL &= ~(1 << pin);
	
	*icr &= ~(0x3 << (icrShift * 2));	/* 清零gpio->ICR 寄存器对应的位 */

	switch(mode)
	{
		case kGPIO_Noint:
			break;
		case kGPIO_LowInterrupt:
			*icr |= (0 << (icrShift * 2));
			break;
		case kGPIO_HighInterrupt:
			*icr |= (1 << (icrShift * 2));
			break;
		case kGPIO_RaisingEdgeInt:
			*icr |= (2 << (icrShift * 2));
			break;
		case kGPIO_FalllingEdgeInt:
			*icr |= (3 << (icrShift * 2));
			break;
		case kGPIO_FallingOrRaisingEdgeInt:
			base->EDGE_SEL |= (1 << pin);
			break;
	}
}

在 'gpio_intmode_config()' 中根据GPIO输入信号的中断触发类型设置对应的 GPIOx->CR1或者CPIOx->CR2寄存器对应bit位来选择GPIO输入信号中断触发类型。

4.1 KEY0 按键选择电平下降沿触发

根据正点原子I.MX6ULL ALPHA/Mini开发板的按键KEY0的电路原理图分析,当按下按键KEY0时GPIO1_IO18的输入信号从高电平变为低电平,所以我们的按键KEY0链接的GPIO1_IO18的输入中断触发方式选择为“电平下降沿触发”。

4.2 KEY0按键消抖

如之前KEY0按键实验中已经分析过得,我们物理按键不是理想的按键,在按键KEY0被按下的瞬间会有多次的电平高低跳变,按下按键一次可能或触发多次中断,所以需要在按键进行消抖。

5. 总结和实验遇到的问题记录

本节分析了将按键对应的GPIO口配置为gpio输入模式,并启用gpio口的中断触发,根据KEY0的电路原理图选择gpio口的中断触发类型。参考I.MX6ULL手册,将gpio输入模式的配置配置到 GPIOx->CR1, GPIOx->CRx, GPIOx->MR, GPIOx->ISR 寄存器里对应的bit位。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/629744.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Weblogic 管理控制台未授权远程命令执行漏洞(CVE-2020-14882,CVE-2020-14883)

1 漏洞概述 Weblogic Pre-Auth Remote Command Execution 漏洞&#xff08;CVE-2020-14882, CVE-2020-14883&#xff09;是针对 Oracle WebLogic Server 的两个安全漏洞。CVE-2020-14882 允许远程用户绕过管理员控制台组件中的身份验证&#xff0c;而 CVE-2020-14883 则允许经…

基于springboot+vue+Mysql的大学生社团活动平台

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Web应用开发中查找慢SQL的方法

每条SQL语句在执行时都需要消耗一定的I/O资源&#xff0c;SQL语句执行的快慢直接决定了硬件资源被占用时长的长短&#xff0c;慢SQL一般指查询很慢的SQL语句。在MySQL数据库中&#xff0c;可以通过慢查询来查看所有执行超时的SQL语句。在默认情况下&#xff0c;一般慢SQL是关闭…

基于NIOS-II软核流水灯和串口通信实现

文章目录 一、创建工程二、系统设计1. 在 “component library” 标签栏中找到 “Nios II Processor” 后点击 Add2. 在 ”Component Library” 标签栏中的查找窗口输入 jtag 找到 ”JTAG UART ”&#xff0c;然后点击 Add3. 添加片上存储器 On-Chip Memory(RAM)核4. 查找窗口输…

Keil手动安装编译器V5版本

V5编译器下载&#xff1a;免积分下载 新版的keil不会自动帮你安装V5版本的编译器&#xff0c;但是很多教程很多比赛所用单片机都是V5的编译器&#xff0c;所以用来开以前的或者开源的很多东西编译直接一大堆报错。 吐槽说完了接下来教你怎么解决 打开installer&#xff08;在…

springboot+vue+mybatis物业管理系统+PPT+论文+讲解+售后

快速发展的社会中&#xff0c;人们的生活水平都在提高&#xff0c;生活节奏也在逐渐加快。为了节省时间和提高工作效率&#xff0c;越来越多的人选择利用互联网进行线上打理各种事务&#xff0c;通过线上物业管理系统也就相继涌现。与此同时&#xff0c;人们开始接受方便的生活…

软件压力测试怎么做

随着信息技术的迅猛发展&#xff0c;软件在各行各业的应用越来越广泛&#xff0c;其稳定性、可靠性和性能表现也受到了越来越多的关注。在这样的背景下&#xff0c;软件压力测试显得尤为重要。本文将详细介绍软件压力测试的概念、目的、方法以及实施步骤&#xff0c;帮助读者更…

「JavaEE」多线程案例1:单例模式阻塞队列

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;JavaEE &#x1f387;欢迎点赞收藏加关注哦&#xff01; 多线程案例分析 &#x1f349;单例模式&#x1f34c;饿汉模式&#x1f34c;懒汉模式&#x1f34c;指令重排序 &#x1f349;阻塞队列&a…

eMMC和SD模式速率介绍

概述 在实际项目开发中我们常见的问题是有人会问,“当前项目eMMC、SD所使用模式是什么? 速率是多少?”。这些和eMMC、SD的协议中要求的,要符合协议。接下来整理几张图来介绍。 eMMC 模式介绍 一般情况下我们项目中都是会支持到HS400 8bit 1.8V,最大时钟频率为200MHZ,通…

Idea入门:一分钟创建一个Java工程

一&#xff0c;新建一个Java工程 1&#xff0c;启动Idea后&#xff0c;选择 [New Project] 2&#xff0c;完善工程信息 填写工程名称&#xff0c;根据实际用途取有意义的英文名称选择Java语言&#xff0c;可以看到还支持Kotlin、Javascript等语言选择包管理和项目构建工具Mav…

十款开源数据集成工具

在大数据作业开发中&#xff0c;数据集成工具是非常重要的一个环节&#xff0c;一个好的数据集成系统从可用性、架构扩展性、底层引擎选型、数据源支持能力等方面都需要一定的考量&#xff0c;在本文中汇总了十款开源的数据集成系统&#xff0c;作者本人在过往的开发过程中&…

【记录】docker笔记(五):Docker网络-Network Namespace

Docker 网络理论基础 要了解docker网络&#xff0c;先了解如下基础概念。 Network Namespace Docker 网络的底层原理是 Linux 的 Network Namespace &#xff0c;所以对于 Linux Network Namespace 的理解对 Docker 网络底层原理的理解非常重要。 简介 Network Name…

LeetCode328奇偶链表

题目描述 给定单链表的头节点 head &#xff0c;将所有索引为奇数的节点和索引为偶数的节点分别组合在一起&#xff0c;然后返回重新排序的列表。第一个节点的索引被认为是 奇数 &#xff0c; 第二个节点的索引为 偶数 &#xff0c;以此类推。请注意&#xff0c;偶数组和奇数组…

node.js的Express框架的介绍 与 安装详细教程

一、Express框架介绍 &#xff08;1&#xff09;Express定义&#xff1a; Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用&#xff0c;和丰富的 HTTP 工具。 使用 Express 可以快速地搭建一个完整功能的网站。 &#xff08…

DDoS防护的市场需求将不断增长,DDoS高防IP显得各位重要

分布式拒绝服务&#xff08;DDoS&#xff09;攻击是一种恶意攻击&#xff0c;它借助于客户/服务器技术&#xff0c;将多个计算机联合起来作为攻击平台&#xff0c;对一个或多个目标发动DDoS攻击&#xff0c;从而成倍地提高拒绝服务攻击的为例。DDoS攻击通过大量合法的请求占用大…

19个测试⽤例⽣成的AI⼯具!卷起来!

在不断发展的软件开发领域中&#xff0c;确保应⽤程序的可靠性和功能性⾄关重要。 随着软件系统复杂性的增加&#xff0c;有效测试⽅法的需求也在上升。 传统的测试⽤例⽣成⽅法通常⽆法满⾜快速开发周期和复杂代码库的需求。 随着进⼊⼈⼯智能&#xff08;AI&#xff09;时…

treejs 3D+echart实现三维旋转炫酷导航网页

treejs 3Dechart实现三维旋转炫酷导航网页https://www.bilibili.com/video/BV1SM4m1C7ki/

行为驱动开源免费接口测试框架:karate

什么是行为驱动测试&#xff1a; 行为驱动测试&#xff08;Behavior-Driven Testing&#xff0c;简称 BDT&#xff09;是一种测试方法&#xff0c;旨在通过描述系统行为和功能来编写测试用例。BDT的重点是从用户的角度出发&#xff0c;描述系统应该如何行为&#xff0c;而不是专…

Python代码:四、读入整数数字

1、题目 在学会读入字符串以后&#xff0c;小白还想要读入整数&#xff0c;请你帮他使用input函数读入数字并输出数字与变量类型。 2、代码 import sysa int(input()) print(a, type(a), sep"\n") 3、在sublime运行结果

亚阈值电流镜

相同电流情况下,由于亚阈值区的gm较大,造成由于阈值电压Vth的失配造成的失配会更大,所以要规避过大的gm,选取较大的过驱动电压。 相同电流情况下,W/L的尺寸选的较小一点,或者说L一定时,W不要取得过大。 Q:Vgs一定的情况下,特别小,几乎小于Vth,一定是亚阈值电流镜吗。…