当前位置: 首页 > news >正文

8.【NXP 号令者RT1052】开发——实战-外部中断

8.【NXP 号令者RT1052】开发——实战-外部中断

在前面几章的学习中,我们掌握了 RT1052 的 IO 口最基本的操作。本章我们将介绍如何将 RT1052 的 IO 口作为外部中断输入,在本章中,我们将以中断的方式,实现我们在第六章所实现的功能。

8.1 RT1052 外部中断简介

我们在第六章详细讲解过IO,那么这一章就使用外部中断来实现之前的效果——通过按键实现LED的亮灭,也会同时介绍外部中断。

RT1052 的每个 IO 口都可以作为中断输入,这点很好很强大。要把 IO 口作为外部中断输入,有以下几个步骤:

8.1.1 初始化 IO 口为输入

这一步设置你要作为外部中断输入的 IO 口的状态,可以设置为上拉/下拉输入,也可以设置为浮空输入(PKE=0),但浮空的时候外部一定要带上拉,或者下拉电阻。否则可能导致中断不停的触发。这一步通过两个函数实现:IOMUXC_SetPinMux 和 IOMUXC_SetPinConfig。以KEY_UP 对应的 IOMUXC_SNVS_WAKEUP 为例,先将其设置为 GPIO 功能,并且上拉输入:

IOMUXC_SetPinMux(IOMUXC_SNVS_WAKEUP_GPIO5_IO00,0);
IOMUXC_SetPinConfig(IOMUXC_SNVS_WAKEUP_GPIO5_IO00,0xF080); 

可以看出和之前按键输入实验是一样的,所以我们也可以直接调用一次按键初始化函数KEY_Init()来完成按键对应的 IO 的复用功能设置。

8.1.2 开启对应 IO 口的中断功能

RT1052 的 IO 口,在设置成输入模式下,如果要使能某个 IO 口的中断功能,则需要设置GPIOx→IMR 对应位为 1,才可以触发中断。这一步通过 GPIO_PinInit 函数实现。同样以 KEY按键为例,KEY_UP 按键对应 GPIO5_IO00,设置此 IO 为中断功能的代码如下:

gpio_pin_config_t int_config;int_config.direction=kGPIO_DigitalInput; /输入
int_config.interruptMode=kGPIO_IntFallingEdge; //下降沿触发中断
int_config.outputLogic=1; //默认高电平
GPIO_PinInit(GPIO5,0,&int_config); //初始化 GPIO5_00

通过上述代码设置 GPIO5_IO00 为下降沿触发中断,默认为高电平,其他 IO 同理设置即

8.1.3 设置中断触发条件

这一步,我们要配置中断的触发条件,RT1052 可以配置成:低电平触发、高电平触发、上升沿触发、下降沿触发和任意边沿触发。号令者四个按键都是低电平有效,所以,我们设置为下降沿触发即可。这一步也是通过 GPIO_PinInit 函数设置(设置 GPIO 为输入模式,以及中断触发条件,都是通过 GPIO_PinInit 函数实现的)

8.1.4 开启并配置中断优先级

这一步,我们就是配置中断中断优先级,以及使能,对 RT1052 的中断来说,只有配置了NVIC 的设置,并开启才能被执行,否则是不会执行到中断服务函数里面去的,以 KEY_UP 为例:

//抢占优先级位 3,0 位子优先级
RT1052_NVIC_SetPriority(GPIO5_Combined_0_15_IRQn, 3, 0);
EnableIRQ(GPIO5_Combined_0_15_IRQn); //使能 GPIO5_0~15IO 的中断

上述代码中实验函数 RT1052_NVIC_SetPriority 来设置中断优先级,然后调用函数EnableIRQ 来开启相应的中断.

8.1.5 编写中断服务函数

这是中断设置的最后一步,中断服务函数,是必不可少的,如果在代码里面开启了中断,但是**没编写中断服务函数,就可能引起硬件错误,从而导致程序崩溃!**所以在开启了某个中断后,一定要记得为该中断编写服务函数。在中断服务函数里面编写你要执行的中断后的操作。通过以上几个步骤的设置,我们就可以正常使用外部中断了。

KEY_UP 控制 DS0,DS1 互斥点亮;KEY2 控制 DS0,按一次亮,再按一次灭;KEY1 控制 DS1,效果同 KEY2;KEY0 则同时控制 DS0 和 DS1,按一次,他们的状态就翻转一次。

8.2 硬件设计

和第六章一样

8.3 软件设计

软件设计我们还是在之前的工程上面增加,本章我们要用到按键,所以要先将 key.c 添加到HARDWARE 组下,然后在 HARDWARE 文件夹下新建 EXTI 的文件夹。然后打开 USER 文件夹下的工程,新建一个 exti.c 的文件和 exti.h 的头文件,保存在 EXTI 文件夹下,并将 EXTI 文件夹加入头文件包含路径(即设定编译器包含路径)。
在这里插入图片描述
在这里插入图片描述

我们在 exti.c 里输入如下代码:

#include "exti.h"
#include "led.h"
#include "delay.h"
#include "key.h"//外部中断初始化
void EXTIX_Init(void)
{gpio_pin_config_t int_config;KEY_Init();                                     //初始化按键//KEY_UPint_config.direction=kGPIO_DigitalInput;		//输入int_config.interruptMode=kGPIO_IntFallingEdge;	//下降沿触发中断int_config.outputLogic=1;						//默认高电平GPIO_PinInit(GPIO5,0,&int_config); 				//初始化GPIO5_00 //KEY1int_config.direction=kGPIO_DigitalInput;		//输入int_config.interruptMode=kGPIO_IntFallingEdge;	//下降沿触发中断int_config.outputLogic=1;						//默认高电平GPIO_PinInit(GPIO5,1,&int_config); 				//初始化GPIO5_01//KEY0int_config.direction=kGPIO_DigitalInput;		//输入int_config.interruptMode=kGPIO_IntFallingEdge;	//下降沿触发中断int_config.outputLogic=1;						//默认高电平GPIO_PinInit(GPIO1,5,&int_config); 				//初始化GPIO1_05//KEY2int_config.direction=kGPIO_DigitalInput;		//输入int_config.interruptMode=kGPIO_IntFallingEdge;	//下降沿触发中断int_config.outputLogic=1;						//默认高电平GPIO_PinInit(GPIO3,26,&int_config);             //初始化GPIO3_26//使能WKUP(GPIO5_00)和KEY1(GPIO5_01)中断GPIO_PortEnableInterrupts(GPIO5,1<<0);			//GPIO5_00中断使能GPIO_PortEnableInterrupts(GPIO5,1<<1);			//GPIO5_01中断使能RT1052_NVIC_SetPriority(GPIO5_Combined_0_15_IRQn,3,0);//抢占优先级位3,0位子优先级EnableIRQ(GPIO5_Combined_0_15_IRQn);			//使能GPIO5_0~15IO的中断//使能KEY0(GPIO1_05)中断GPIO_PortEnableInterrupts(GPIO1,1<<5);			//GPIO1_05中断使能RT1052_NVIC_SetPriority(GPIO1_Combined_0_15_IRQn,4,0);//抢占优先级位3,0位子优先级EnableIRQ(GPIO1_Combined_0_15_IRQn);			//使能GPIO1_0~15IO的中断//使能KEY2(GPIO3_26)中断GPIO_PortEnableInterrupts(GPIO3,1<<26);			//GPIO3_26中断使能RT1052_NVIC_SetPriority(GPIO3_Combined_16_31_IRQn,5,0);//抢占优先级位5,0位子优先级EnableIRQ(GPIO3_Combined_16_31_IRQn);			//使能GPIO3_16~31 IO的中断
}//GPIO1_0~15共用的中断服务函数
void GPIO1_Combined_0_15_IRQHandler(void)
{static u8 led0sta=1,led1sta=1;if(GPIO_GetPinsInterruptFlags(GPIO1)&(1<<5))  //判断是否为GPIO1_5中断{  //消抖延时,这里为了方便演示例程所以在中断中使用了延时函数来做消抖,//在实际的项目中绝对禁止在中断中使用延时函数!!!!!!!delay_ms(10);         if(GPIO_PinRead(GPIO1,5)==0) //KEY0(GPIO1_5)是否保持按下状态{led1sta=!led1sta;led0sta=!led0sta;LED1(led1sta);LED0(led0sta); }}GPIO_PortClearInterruptFlags(GPIO1,1<<5);		//清除中断标志位__DSB();				//数据同步屏蔽指令 
}//GPIO3_16~31共用的中断服务函数
void GPIO3_Combined_16_31_IRQHandler(void)
{if(GPIO_GetPinsInterruptFlags(GPIO3)&(1<<26))    //判断是否为GPIO3_26中断{//消抖延时,这里为了方便演示例程所以在中断中使用了延时函数来做消抖,//在实际的项目中绝对禁止在中断中使用延时函数!!!!!!!delay_ms(10); if(GPIO_PinRead(GPIO3,26)==0)   //KEY2(GPIO3_25)是否保持按下状态{LED0_Toggle;}}GPIO_PortClearInterruptFlags(GPIO3,1<<26);		//清除中断标志位__DSB();				//数据同步屏蔽指令  
}//GPIO5_0~15共用的中断服务函数
void GPIO5_Combined_0_15_IRQHandler(void)
{static u8 led0sta=1,led1sta=1;if(GPIO_GetPinsInterruptFlags(GPIO5)&(1<<0))    //判断是否为GPIO5_0中断{delay_ms(10); if(GPIO_PinRead(GPIO5,0)==0) //KEYUP(GPIO5_00)是否保持按下状态{led1sta=!led1sta;led0sta=!led1sta;LED1(led1sta);LED0(led0sta);}}if(GPIO_GetPinsInterruptFlags(GPIO5)&(1<<1))   //判断是否为GPIO5_1中断  {delay_ms(10); if(GPIO_PinRead(GPIO5,1)==0)  //(KEY1)GPIO5_01是否保持按下状态 {LED1_Toggle;}}GPIO_PortClearInterruptFlags(GPIO5,1<<0);		//清除中断标志位GPIO_PortClearInterruptFlags(GPIO5,1<<1);		//清除中断标志位__DSB();				//数据同步屏蔽指令
}

exit.h

#ifndef _EXTI_H
#define _EXTI_H
#include "sys.h"void EXTIX_Init(void);
#endif

exti.c 文件总共包含 4 个函数。一个是外部中断初始化函数 void EXTIX_Init(void),另外 3个都是中断服务函数,接下来我们分别介绍这 4 个函数。

EXTIX_Init 函数说明

EXTIX_Init 用于外部中断初始化,步骤如下:

  1. 调用 KEY_Init,将按键 IO 配置为 GPIO(ALT5 功能)。

  2. 使用 GPIO_PinInit 设置中断触发条件(下降沿触发),并配置为输入模式。

    注意:虽然 KEY_Init 已经调用过 GPIO_PinInit,但该函数可多次调用,以最后一次配置为准。

  3. 再次调用 GPIO_PinInit,使能对应 IO 的中断功能。

  4. 通过 RT1052_NVIC_SetPriority 设置中断优先级。

相关中断号宏(如 GPIO1_Combined_0_15_IRQnGPIO3_Combined_16_31_IRQn)定义在 MIMXRT1052.h 头文件中。

中断服务函数说明

1. GPIO1_Combined_0_15_IRQHandler
  • 对应 GPIO1_IO00 ~ GPIO1_IO15 共用的中断服务函数。
  • 本实验使用 GPIO1_IO05 (KEY0)
  • 处理流程:
    1. 调用 GPIO_GetPinsInterruptFlags 判断是否由 KEY0 触发。
    2. 延时 10ms 消抖(仅用于演示,实际项目中禁止在中断中使用延时)。
    3. 再次读取 KEY0 电平,若仍为低电平则确认按下,执行操作(如点灯)。
    4. 清除中断标志,退出中断。
2. GPIO3_Combined_16_31_IRQHandler
  • 对应 GPIO3_IO16 ~ GPIO3_IO31 共用的中断服务函数。
  • 本实验用于检测 KEY2 是否按下。
  • 处理逻辑与 GPIO1_Combined_0_15_IRQHandler 类似。
3. GPIO5_Combined_0_15_IRQHandler
  • 对应 GPIO5_IO00 ~ GPIO5_IO03(仅 3 个 IO)。
  • 本实验用于检测 KEY0 和 KEY_UP
  • 处理逻辑与 GPIO1_Combined_0_15_IRQHandler 相同,只是需要同时判断两个 IO。

注意!!!

  • 中断函数共用:多个 IO 口共享同一个中断服务函数,需要在 ISR 内部判断具体触发源。
  • 消抖处理:示例中使用延时函数消抖仅为演示,实际工程中应采用 定时器消抖状态机,避免在中断中阻塞。

这里给大家说明一下:RT1052 的 5 组 IO 口,每组 IO 口的低 16 位占用一个中断,高 16 位占用一个中断,这样,每组 IO 口使用 2 个中断服务函数即可搞定。当每组 IO 口有多个中断的时候,需要在中断服务函数里面判断中断来源(ISR 寄存器),然后再执行相关处理。另外,RT1052 所有中断服务函数的名字,都已经在 startup_MIMXRT1052.s 里面定义好了,如果有不知道的,去这个文件里面找就可以了。

这部分代码就很简单了,我们这里不多废话,保存就可以了。接着我们在 main.c 里面写入如下内容:

#include "sys.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"int main(void)
{u8 key=0;u8 led0sta=1,led1sta=1;     //LED0,LED1的当前状态u8 len;					//接收数据长度u16 times=0;            //延时计数器MPU_Memory_Protection();    //初始化MPURT1052_Clock_Init();	    //配置系统时钟DELAY_Init(600);		    //延时函数初始化LPUART1_Init(115200);       //初始化串口1RT1052_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//优先级分组4LED_Init();				    //初始化LED
#ifdef KEY_DEBUGKEY_Init();                 //初始化KEY
#endif
#ifdef LPUART_DEBUGLED0(0);					//先点亮红灯 
#endifEXTIX_Init();			    //初始化外部中断while(1){printf("Int example driver!\r\n");delay_ms(1000);
#ifdef KEY_DEBUGkey=KEY_Scan(0); 		    //得到键值if(key){	switch(key){				 case WKUP_PRES:	//控制LED0,LED1互斥点亮led1sta=!led1sta;led0sta=!led1sta;break;case KEY2_PRES:	//控制LED0翻转led0sta=!led0sta;break;case KEY1_PRES:	//控制LED1翻转	 led1sta=!led1sta;break;case KEY0_PRES:	//同时控制LED0,LED1翻转 led0sta=!led0sta;led1sta=!led1sta;break;}LED0(led0sta);		//控制LED0状态LED1(led1sta);		//控制LED1状态}else delay_ms(10);
#endif // KEY_DEBUG
#ifdef LPUART_DEBUGif(LPUART_RX_STA&0x8000){					   len=LPUART_RX_STA&0x3fff;//得到此次接收到的数据长度printf("\r\n发送的消息为:\r\n");LPUART_WriteBlocking(LPUART1,LPUART_RX_BUF,len);//发送接收到的数据printf("\r\n\r\n");//插入换行LPUART_RX_STA=0;}else{times++;if(times%5000==0){printf("\r\nALIENTEK RT1052开发板 串口实验\r\n");}if(times%200==0)printf("请输入数据,以回车键结束\r\n");  if(times%30==0)LED0_Toggle;//闪烁LED,提示系统正在运行.delay_ms(10);   }
#endif // LPUART_DEBUG}
}

该部分代码很简单,在初始化完中断后,点亮 LED0,就进入死循环等待了,这里死循环里面通过一个 printf 函数来告诉我们系统正在运行,在中断发生后,就执行相应的处理。


编译,下载验证一下
在这里插入图片描述
在这里插入图片描述

总结

相比之前写的在while(1)中轮询的方式,这种方式显然更方便以及响应更快,在实际应用中需要注意的是中断等级和中断处理部分。
OK!谢谢大家!

http://www.dtcms.com/a/574929.html

相关文章:

  • 国内出名的设计网站有哪些老网站做seo能不能重新注册
  • ETL 清洗在某平台中的概念与实践解析
  • obsidian1.9.14_win中文_Markdown编辑器_安装教程
  • 网站建设财务怎么入账的wordpress主题
  • yaml配置文件和语法说明
  • 成都网站建设 天空在线wordpress机械模板下载
  • 广州公司制作网站小型网站建设步骤
  • 致同研究:附有质量保证条款的销售的披露示例
  • 建设部网站官网景德镇建设网站
  • 网站建设制作设计惠州七牛云wordpress缓存配置
  • 外贸网站建设制作Windows怎么建设网站
  • 虹桥做网站公司网站制作手机
  • 网站ww正能量嘉兴网站制作厂家
  • 面向强化学习的状态空间建模:RSSM的介绍和PyTorch实现
  • 10.2 一种融合深度空间特征增强与注意力去噪的新型 3D 室内定位方法研究总结
  • 理解PostgreSQL中的CMIN和CMAX
  • 使用 PostgreSQL 时间点恢复(Point-In-Time Recovery)的多种数据恢复技术
  • 营销网站制作教程微信表情开放平台官网
  • 调控大肠杆菌胞内ATP和NADH水平促进琥珀酸生产--文献精读172
  • Spring-cloud 主键Nacos
  • 网站开发尺寸外贸做的亚马逊网站是哪个
  • Spring Boot OAuth2 GitHub登录的9大坑与终极避坑指南
  • 手机制作表白网站河北建设集团有限公司网站
  • 三门峡网站开发邹城有做网站的吗
  • 4成都网站建设网站开发后期维护更新
  • 关于ICG (integrate clock gating)
  • 关于socket网络通信的大小端转换
  • Kubernetes Service与Ingress全方位解析
  • 有哪些好的网站深圳网络推广专员
  • 苏州网站开发公司兴田德润简介建网站需要钱吗