文章目录
- 一、外部引脚中断
- 二、中断过程
- 三、按键外部中断
一、外部引脚中断
1. ICU框图
根据ICU的功能框图可以知道,首先需要配置IRQCR寄存器(IRQ Control Register,IRQ英文全称:Interrupt ReQuest,中文名:中断请求)。之后配置IELSR寄存器(英文全称:ICU Event Link Setting Register,中文名:中断控制单元事件链接设置寄存器)。之后使能IR寄存器,最后配置NVIC。
2. 相应寄存器介绍
① IRQCR介绍
Interrupt Request Control Register(IRQCR) — 中断请求控制寄存器,这个寄存器拥有0-15个通道,有三个标志位: (1) IRQMD[1:0]检测感知选择 (2) FCLKSEL[1:0]数字滤波采样时钟选择 (3) FLTEN数字滤波器使能
IRQ控制寄存器:
二、中断过程
当中断来临的时候会最先经过IRQ寄存器,IRQ寄存器检测到中断的时候,会向中央处理嵌套向量中断控制器NVIC发送中断信号, 当NVIC检测到中断请求的时候,会将相应的中断服务函数进行挂起。之后将运行的八个寄存器进行压栈,压栈完成之后将中断服务程序进行激活。 之后将原先压栈的寄存器取出,继续运行之前的程序。
中断抢占的过程:
当中断来临的时候会最先经过IRQ寄存器,IRQ寄存器检测到中断的时候,会向中央处理嵌套向量中断控制器NVIC发送中断信号, 当NVIC检测到中断请求的时候,会将相应的中断服务函数进行挂起。之后将运行的八个寄存器进行压栈,堆栈完成之后将中断服务程序进行激活。 此时当另一个优先级更高的中断源发生请求的时候,会将相应的中断服务函数进行挂起。之后将当前运行的八个寄存器进行压栈,压栈完成之后将中断服务程序进行激活。 当中断服务程序运行完之后会将原先压栈的寄存器取出,之后继续运行之前中断服务的程序。中断服务程序运行完成之后之后将原先压栈的寄存器取出,继续运行之前的程序。
三、按键外部中断
中断在嵌入式应用中的地位不言而喻,几乎每个控制器都有中断功能。中断对事件得到第一时间处理是非常重要的。 我们设计使用按键来作为触发源,使得控制器产生中断,并在中断服务函数中实现控制LED灯的任务。
1. 硬件设计
轻触按键在按下时会使得按键的两个引脚接通,通过电路设计可以使得在按键按下时引脚产生电平变化。
野火启明6M5开发板的按键电路设计如下:
其中,RES 按键是开发板的芯片复位按键,用于复位MCU芯片。 另外两个按键为用户可自定义的按键,可用于实现用户所需的功能。
在按键的电路设计中,与按键相并联的电容属于硬件滤波电容,可以在一定程度上防止按键抖动带来的误触发。 其实,用户也可以使用瑞萨RA MCU的IO引脚内部自带的数字滤波功能,这样可以去掉该电容,从而减少电路板的硬件成本。
开发板按键引脚分配和中断号:
KEY_1SW2:P004(IRQ9-DS)
KEY_2SW3:P005(IRQ10-DS)
2. 软件设计
① FSP配置
首先打开 “16_ICU_External_IRQ” 项目的 FSP 配置界面,接下来在这个界面里配置芯片的引脚及其相应的功能。
首先配置引脚连接到 ICU 的中断通道。
然后,依次点击 “Stacks” -> “New Stack” -> “Input”-> “External IRQ” 来加入外部中断模块, 如下图所示。由于使用两个按键,需要两个外部中断,所以这里需要加入2个外部中断模块。
第一个外部中断模块设置的是按键1的外部中断配置,按如下图所示进行设置:
第二个外部中断模块设置的是按键2的外部中断配置,按如下图所示进行设置:
外部中断模块(r_icu)的属性介绍如下表所示
配置完成之后可以按下快捷键“Ctrl + S”保存, 最后点右上角的 “Generate Project Content” 按钮,让软件自动生成配置代码即可。
② 按键外部中断初始化函数
/* KEY 外部中断初始化函数 */
void Key_IRQ_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
/* Open ICU module */
err = R_ICU_ExternalIrqOpen(&g_external_irq9_ctrl, &g_external_irq9_cfg);
err = R_ICU_ExternalIrqOpen(&g_external_irq10_ctrl, &g_external_irq10_cfg);
/* 允许中断 */
err = R_ICU_ExternalIrqEnable(&g_external_irq9_ctrl);
err = R_ICU_ExternalIrqEnable(&g_external_irq10_ctrl);
}
-
R_ICU_ExternalIrqOpen() 用于打开一个外部中断模块实例。
-
R_ICU_ExternalIrqEnable() 用于使能外部中断,使能后即可触发产生外部中断。
③ 按键中断回调函数
因为之前的 FSP 配置里面 Callback 属性配置的都是同一个中断回调函数, 因此,我们仅需实现一个中断回调函数即可。当然,中断回调函数也可设置为不同的两个函数,由用户定义。
两个按键共用 key_external_irq_callback 中断回调函数, 并通过 p_args->channel 参数来判断是哪个中断通道产生了中断从而判断是哪个按键按下,该函数如下:
/* 按键按下标志 */
volatile bool key1_sw2_press = false;
volatile bool key2_sw3_press = false;
/* 按键中断回调函数 */
void key_external_irq_callback(external_irq_callback_args_t *p_args)
{
/* 判断中断通道 */
if (9 == p_args->channel)
{
key1_sw2_press = true; // 按键KEY1_SW2按下
}
else if (10 == p_args->channel)
{
key2_sw3_press = true; // 按键KEY2_SW3按下
}
}
④ hal_entry入口函数
/* 用户头文件包含 */
#include "led/bsp_led.h"
#include "key/bsp_key_irq.h"
extern volatile bool key1_sw2_press;
extern volatile bool key2_sw3_press;
void hal_entry(void)
{
/* TODO: add your own code here */
LED_Init(); // LED 初始化
Key_IRQ_Init(); // KEY 外部中断初始化
while(1)
{
/* 判断按键 KEY1_SW2 是否被按下 */
if (key1_sw2_press)
{
key1_sw2_press = false; //标志位清零
LED2_TOGGLE; //LED2 翻转
}
/* 判断按键 KEY2_SW3 是否被按下 */
if (key2_sw3_press)
{
key2_sw3_press = false; //标志位清零
LED3_TOGGLE; //LED3 翻转
}
// LED1 闪烁指示程序正在运行
LED1_TOGGLE;
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS); //延时1秒
// 按键被按下触发中断后,在主循环中LED2或LED3最长会被推迟1秒翻转
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}