实现了 IRQ 中断服务函数的汇编部分以后,接下来我们要使用C代码实现IRQ中断服务函数的具体逻辑,主要包含初始化和中断处理两部分。
- 全局中断初始化(全局中断使能、IRQ中断使能)
- 具体中断处理逻辑实现
我们这里的中断是由按键产生的,那我们要打开的就是按键引脚所关联的中断。
目录
一、外设引脚分析
二、外设中断初始化
1、基本流程
2、引脚使能(GPIO1_IMR)
3、设置触发方式(GPIO1_ICR2)
4、注册中断服务函数
三、总结
一、外设引脚分析
按键是对应的引脚是 UART1_CTS,我们需要将其复用为GPIO功能,我们找到 UART1 CTSB会发现,该引脚可以复用为 GPIO1_IO18
因此,要打开 GPIO1 的中断,就需要知道GPIO1 对应的中断ID。GPIO1_IO18 对应的中断ID就是67 + 32 = 99。注意还需要加上固有中断 SGI 和 PPI(一共32个)。
二、外设中断初始化
1、基本流程
外设中断初始化的整体流程如下,该过程中可能会用到如下寄存器:
- GPIO1_ICR2 —— 配置中断的触发模式,也可以直接设置 GPIOx_EDGE_SEL 寄存器
- GPIO1_IMR —— 设置 GPIO1 某个引脚中断使能
- GPIO_ISR —— 中断状态寄存器,记录中断的发生状态(处理完中断以后,要对中断相应的bit位 置为1)
① GPIO1中断使能:这一步我们已经放到了《全局中断初始化》了。这里的 99 就包含了 GPIO1 的16~31引脚。
② 引脚中断使能:虽然使能了一批引脚的,但还需要指定某个引脚的中断使能
③ 设置中断触发方式:中断触发方式包含低电平触发、高电平触发、上升沿触发、下降沿触发等。
④ 注册中断服务函数:《全局中断初始化》只是暂时给每一种中断配置了一个临时的中断服务函数,这里我们要替换成真正的中断处理函数。
2、引脚使能(GPIO1_IMR)
设置引脚使能使用的是 GPIOx_IMR 寄存器。IMR寄存器占32bit,每一bit对应 GPIO1 的0 ~ 31引脚,我们要设置的是第 18 引脚,那就要将第 18 个 bit 置 1 。
GPIO1_IMR |= (1 << 18);
3、设置触发方式(GPIO1_ICR2)
方式一:GPIO1_ICR2
GPIO1_ICR2 控制的是16~31 引脚的触发方式。四种触发方式分别是:低电平、高电平、上升沿、下降沿
// 配置 GPIO1_IO18 中断触发方式(下降沿触发)
GPIO1_EDGE_SEL &= ~(1 << 18);
GPIO1_ICR2 |= (3 << 4);
注意:这里的 GPIO1_EDGE_SEL 寄存器是第二种设置触发中断的方法,一旦设置了会覆盖 GPIO1_ICR2 或者 GPIO1_ICR1 的对应位置的触发方式。所以事先将 GPIO1_EDGE_SEL 的第 18 bit 置 0 以防干扰 ICR 寄存器。
方式二:GPIO1_EDGE_SEL
GPIO1_EDGE_SEL只能用于设置边缘触发,无法设置低电平或者高电平触发。一旦设置会覆盖ICR寄存器对应位置的触发方式。
// 设置第 18 bit边缘触发
GPIO1_EDGE_SEL |= (1 << 18);
4、注册中断服务函数
现在我们要注册中断服务函数,也就是我们希望按键被按下时,执行何种操作。假设这里就设置成,当按键按下时,切换LED灯的状态。
// 注册中断服务函数
register_irqhandler(99, key_irqhandler);
unsigned int status = 1;
/* 按键中断服务函数 */
void key_irqhandler(void* userParams)
{
switch_led(status);
status = !status;
GPIO1_ISR |= (1 << 18); // 清除中断标志位
}
提示:有一点需要注意的是,中断服务函数执行完毕以后,要将 ISR 寄存器对应 bit 位置1(清除中断标志位),以表示该中断已经处理完毕。(也可以通过 ISR 寄存器判断中断是否发生)
三、总结
unsigned int status = 1;
/* 按键中断服务函数 */
void key_irqhandler(void* userParams)
{
switch_led(status);
status = !status;
GPIO1_ISR |= (1 << 18); // 清除中断标志位
}
/* 按键中断初始化 */
void key_int_init()
{
// GPIO1 中断使能
GPIO1_IMR |= (1 << 18);
// 配置 GPIO1_IO18 中断触发方式(下降沿触发)
GPIO1_EDGE_SEL &= ~(1 << 18);
GPIO1_ICR2 |= (3 << 4);
// 注册中断服务函数
register_irqhandler(99, key_irqhandler);
}