中断服务程序与IRQ(中断请求)、中断向量表、中断向量地址 的联系
时间: 2023-04-01 15:02:25 浏览: 287
中断服务程序是用来响应中断请求的程序,IRQ是中断请求,当外部设备需要处理时,会向CPU发送中断请求,CPU会根据中断号在中断向量表中查找对应的中断向量地址,然后跳转到该地址执行中断服务程序。因此,中断向量表和中断向量地址是用来存储中断服务程序入口地址的数据结构。
相关问题
基于ARM开发板,编写一个外设为LED灯的中断服务程序,根据选择的外设,修改系统启动代码中断入口向量表,编写初始化中断函数,编写中断服务程序
好的,这是一个嵌入式系统的问题,需要一定的底层知识。我会尽力解释清楚。
首先,ARM开发板的中断服务程序需要根据硬件平台的不同进行编写。假设我们的ARM开发板上有8个LED灯,我们需要编写一个中断服务程序,当外设触发中断时,中断服务程序能够控制LED灯的闪烁。
修改系统启动代码中断入口向量表:
中断服务程序需要嵌入到ARM开发板的中断向量表中,才能在中断时被正确地调用。因此,我们需要修改系统启动代码中的中断入口向量表。
首先,我们需要知道ARM开发板中的向量表的地址。一般来说,向量表的地址在0x00000000到0x00000FFF之间。对于ARM Cortex-M系列芯片,它们的向量表是固定的,因此我们可以直接使用芯片手册中提供的向量表地址。
然后,我们需要在系统启动代码中修改向量表中的中断向量,将其指向我们编写的中断服务程序。具体来说,我们需要找到LED灯所对应的中断向量,然后将其指向我们编写的中断服务程序。假设LED灯所对应的中断向量为IRQ_LED,我们可以这样修改中断向量表:
```c
__attribute__((section(".isr_vectors"))) void (*isr_vectors[])(void) = {
// ...
[IRQ_LED] = led_isr_handler, // 修改LED灯对应的中断向量
// ...
};
```
其中,led_isr_handler是我们编写的中断服务程序的函数名。
编写初始化中断函数:
在系统启动时,我们需要初始化中断控制器,使其能够响应外设的中断请求。具体来说,我们需要完成以下工作:
1. 使能中断控制器;
2. 配置中断触发方式;
3. 设置中断优先级。
以ARM Cortex-M系列芯片为例,我们可以使用CMSIS库提供的函数来完成初始化工作。具体来说,我们可以这样写初始化函数:
```c
#include "stm32f4xx.h"
#include "stm32f4xx_nvic.h"
void led_irq_init(void)
{
// 使能中断控制器
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置LED灯对应的GPIO口为输出模式
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStruct);
// 配置LED灯对应的中断触发方式为边沿触发
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line = EXTI_Line0 | EXTI_Line1 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4 | EXTI_Line5 | EXTI_Line6 | EXTI_Line7;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 设置LED灯对应的中断优先级
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn | EXTI1_IRQn | EXTI2_IRQn | EXTI3_IRQn | EXTI4_IRQn | EXTI9_5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
```
其中,我们使用了GPIO_Init函数和EXTI_Init函数来配置LED灯对应的GPIO口和中断触发方式,使用NVIC_Init函数来设置中断优先级。
编写中断服务程序:
最后,我们需要编写中断服务程序,当LED灯所对应的中断向量被触发时,中断服务程序能够控制LED灯的闪烁。
我们可以这样编写中断服务程序:
```c
void led_isr_handler(void)
{
// 在中断服务程序中控制LED灯的闪烁
for (int i = 0; i < 8; i++) {
if (EXTI_GetITStatus(1 << i) != RESET) {
GPIO_WriteBit(GPIOD, 1 << i, (BitAction)!GPIO_ReadOutputDataBit(GPIOD, 1 << i));
EXTI_ClearITPendingBit(1 << i);
}
}
}
```
其中,我们使用了GPIO_WriteBit函数来控制LED灯的闪烁,并使用EXTI_GetITStatus函数和EXTI_ClearITPendingBit函数来清除中断标志位。
至此,我们完成了ARM开发板外设为LED灯的中断服务程序的编写。
IRQ号和中断向量号的区别
IRQ号和中断向量号都是用来标识中断的方式,但它们之间有一些区别。
IRQ号是指中断请求号,通常用来标识硬件设备所产生的中断。在计算机系统中,IRQ号通常是一个整数值,它唯一地标识一个硬件中断通道。它是由硬件设备发送给处理器的信号,告诉处理器有一个中断需要被处理。IRQ号通常是由操作系统内核分配的,并且每个硬件设备都有一个唯一的IRQ号。
中断向量号是一个与中断处理程序相关的编号。它是在系统启动时由操作系统内核初始化的,并且通常是一个指向中断处理程序代码的地址。当一个中断发生时,处理器会使用IRQ号来查找中断向量表中对应的中断向量号,并且跳转到该中断处理程序的代码地址执行中断处理程序。因此,中断向量号实际上是一个指针,它指向中断处理程序的代码。
总的来说,IRQ号是硬件设备产生中断的标识,而中断向量号是处理器使用IRQ号来查找中断处理程序的指针。
阅读全文