1、中断
中断类型:
- 系统异常,体现在内核上
- 外部中断,体现在外设上
中断寄存器
嵌套向量中断控制器(NVIC:Nested vectored interrupt controller)和处理器核的接口紧密相连,可以实现低延迟的中断处理和高效地处理晚到的中断。属于内核外设,管理者包括内核和片上所有外设的中断相关的功能。
与之相关的两个重要库文件:内核——core_cm4.h和misc.c,而外设寄存器都在stm32f1xx.h中描述,具体定义在各种c文件中。
和中断相关的寄存器在官方内核手册中都有包含。
中断优先级
优先级设定:NVIC->IPRx (Interrupt priority registers 中断优先级寄存器)
每个中断优先级期存器都有一个值:0-255(8位),优先级数字越低,逻辑优先级越高。
bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 |
用于表达优先级 | 未使用,读回为0 |
该寄存器默认复位值是: 0xFA05 0000,即8,9,10位是000,而在优先级分组里边没有这个,所以分组不确定
优先级分组 | 主优先级位 | 主优先级取值 | 子优先级取值 | 描述 |
NVIC_Priority_0 | 没有主优先级位 | 0 | 0-15 | 主-0bit,子-4bit |
NVIC_Priority_1 | bit 7 | 0-1 | 0-7 | 主-1bit,子-4bit |
NVIC_Priority_2 | bit 7,6 | 0-3 | 0-3 | 主-2bit,子-2bit |
NVIC_Priority_3 | bit 7,6,5 | 0-7 | 0-1 | 主-3bit,子-1bit |
NVIC_Priority_4 | bit 7,6,5,4 | 0-15 | 0 | 主-4bit,子-0bit |
当多个中断同时到来时,会逐级比较比较:主优先级->子优先级->硬件中断编号
中断设置
如果要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置两个触发器,同时在中断屏蔽寄存器的相应位写“1”允许中断请求。当外部中断先上发生了期待的边沿时,将产生一个中断请求,对应的挂起位随之被置为“1”。在挂起寄存器的对应位写“1”,将清除该中断请求。
如果要产生事件,不需要先配置好并使能事件线。根据需要的边沿检测通过设置2个触发寄存器,同时在事件屏蔽寄存器的相应位写“1”允许事件请求。当时间线上发生了需要的边沿时,将产生一个事件请求脉冲,对应的挂起位不被值“1”。
通过在软件中断/请求寄存器写“1”,也可以通过软件产生中断/事件请求。
除了配置好中断之外,中断信号输入端口,如GPIO口也需要初始化配置好:
AFIO寄存器描述:对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作前,应当首先打开AFIO的时钟。参考第6.3.7节APB2外设时钟使能寄存器(RCC_APB2ENR)。
必须以字(32位)的方式操作这些外设寄存器。
- 初始化GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_EXTI_GPIO_PORT, &GPIO_InitStructure);
- 设置中断优先级
NVIC_InitTypeDef NVIC_InitStructure;
/*第一步:配置中断优先级的分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/*第二步:配置NVIC初始化结构体*/
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/*第三步:调用NVIC初始化函数把配置好的结构体成员写到寄存器里*/
NVIC_Init(&NVIC_InitStructure);
- 初始化EXTI
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //打开AFIO的时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = KEY1_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //触发选择
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
- 编写中断服务程序
这个程序要写在stm32f10x_it.c
中,函数名称必须和启动文件startup_stm32f10x_hd.s
中中断向量表中预定义的函数名称相同,否则不能识别该函数。
void KEY1_EXTI_IRQHANDLER(void)
{
if(EXTI_GetITStatus(KEY1_EXTI_LINE) != RESET)
{
LED1_TOGGLE; //灯0-1反转
}
EXTI_ClearITPendingBit(KEY1_EXTI_LINE);
}
- 主函数
主函数只需要调用GPIO初始化,NVIC中断优先级、EXTI函数即可。