企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
啊啊啊,先叫两声,释放释放今天的压抑。。搞了一天终于把中断给搞定。 中断寄存器怎么说呢,两个字,复杂,三个字,好复杂,四个字,真的很发展 好吧,开始进入正题。。。 其实中断也不是很复杂了,归纳下,分为以下几个步骤: (1)GPIO config (2)EXTI config (3)Set Group of Interrupt vector (4)Set Preemting & SubPriority (5)Function of Interrupt 好,先附上代码,现在我来给大家一步一步解析: ~~~ void inter_sw5_config(void) { GPIO_TypeDef *sw5 = GPIOE; u32 aircr = 0; RCC->APB2ENR |= 1<<6; sw5->CRH &= ~(0xf<<(4*6)); //Clear PE14 Register sw5->CRH |= 8<<(4*6); //Set PE14 Register [TO:pull up / down] sw5->ODR |= GPIO_Pin_14; //Enable PIN14 /* EXTI CONFIG */ RCC->APB2ENR |= 1<<0; //Start clock of AFIO AFIO->EXTICR[3] |= 0x04<<8; //Set PE14 //GPIOE 0100b = 0x4 //3 = (int)(14 / 4) //8 = (14 % 4) * 4 EXTI->IMR |= GPIO_Pin_14; //enable interrupt of PE14 EXTI->EMR |= GPIO_Pin_14; //enable interrupt of PE14 EXTI->RTSR |= GPIO_Pin_14; //Set Rising along the trigger /* Set Group :2 */ aircr = SCB->AIRCR; //Get AIRCR register aircr &= 0x0000f8ff; //Clear Password & PriGroup aircr |= 0x05fa0000; //Set Password aircr |= (0x5<<8); //Set PriGroup Group:2 [5 = 0101b]<<8 SCB->AIRCR = aircr; //Set AIRCR /* * Group 2 2:2 * 0~3 : 0~3 * Set Preempting = 0 Subpriority = 0 * 1001 0000b = 0x00; */ NVIC->ISER[1] = 1<<(40-32); //EXIT15_10 vector:40 NVIC->IP[40] = 0x90; } ~~~ 1、GPIO config 前面两个博客已经进行了解释,我觉得不用再多说了,说多了浪费时间。 不过我们来解析下APB2ENR寄存器,APB2ENR即外部时钟寄存器,无论选择选择哪个GPIOx或者是特殊功能寄存器,都需要来给他驱动时钟; ![](https://box.kancloud.cn/2016-06-21_576915b2036f7.jpg) 设置对应位为1则打开时钟,设置对应位为0则关闭 这里我们用的是GPIOE,bit6,所以我们要RCC->APB2ENR |= 1<<6; 后面我们还要用到中断寄存器,所以我们后面在初始化中断的时候要RCC->APB2ENR |= 1<<0; 2、EXTI config 在配置EXTI的时候我们要使用特殊功能寄存器AFIO,所以我们先来看下AFIO的结构体(上面关于AFIO的时钟已经说了,这都不说了) ~~~ typedef struct { __IO uint32_t EVCR; __IO uint32_t MAPR; __IO uint32_t EXTICR[4]; uint32_t RESERVED0; __IO uint32_t MAPR2; } AFIO_TypeDef; ~~~ 这里的EXTICR是个长度为4的数组; 这里我举个例子,我们来研究下EXTICR2寄存器 ![](https://box.kancloud.cn/2016-06-21_576915b2193b2.jpg) 可以看出EXTICR2管理了4个PIN,即x=4,5,6,7,这里我们用的是PE,所以,在设置的时候设置为0100b=0x4;今天我在搞这个的时候,就是把这个地方的0100b看错了才让我纠结了一下午;所以大家在配置寄存器的时候,一定要小心小心再小心; 其实这里就像当于一个坐标,至于为啥,傻子都能看的出来。 由于我们用的是PE14 所以我们要选用EXTICR4【4 = 14/4】寄存器,在结构体中是数组的最后一个,所以我们要配置EXTICR[3] 这样我们已经选定了PE14,如果还不懂的话,请看datasheet中 8.4 AFIO寄存器的描述 然后我们下面来配置EXTI的寄存,同样,想看详细的请看9.3 EXTI寄存器的描述 EXTI->IMR |= GPIO_Pin_14;//enable interrupt of PE14 EXTI->EMR |= GPIO_Pin_14;//enable interrupt of PE14 EXTI->RTSR |= GPIO_Pin_14;//Set Rising along the trigger 从注释中不难明白,每一句的作用,我没就来分析其中的一个 ![](https://box.kancloud.cn/2016-06-21_576915b233431.jpg) bit 31:20是木有用的,主要是19:0,为什么是19呢?看中断向量表,具体在9.1.2 中断和异常向量 9.2.5  外部中断/事件线路映像 3、Set Group of Interrupt vector 可能这个AIRCR寄存器不是很好找,我看了好多资料,才找到这个寄存器的map。 ![](https://box.kancloud.cn/2016-06-21_576915b24fb48.jpg) 看到这里,为来配置中断寄存器我们只需了解 PRIGROUP,和KEYSTAT, KEYSTAT上面已经给出了,0x05fa PRIGROUP看下面的表: ![](https://box.kancloud.cn/2016-06-21_576915b26c5d2.jpg) 看了这个表,比如我选择group 2 :那么我们就看划过红线的部分,0b101 = 0x5,这样就不难理解了吧。 4、Set Preemting & SubPriority 在我的设置中,可能有些人会说看不懂,或者说我的错,可能是咱们的软件不一样,我用的是keil 4,库给我提供的头文件关于NVIC的结构体如下: ~~~ typedef struct { __IO uint32_t ISER[8]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[24]; __IO uint32_t ICER[8]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ uint32_t RSERVED1[24]; __IO uint32_t ISPR[8]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[24]; __IO uint32_t ICPR[8]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ uint32_t RESERVED3[24]; __IO uint32_t IABR[8]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ uint32_t RESERVED4[56]; __IO uint8_t IP[240]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ uint32_t RESERVED5[644]; __O uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ } NVIC_Type; ~~~ ![](https://box.kancloud.cn/2016-06-21_576915b2884cb.jpg) NVIC->ISER[1] = 1<<(40-32);//EXIT15_10 vector:40 NVIC->IP[40] = 0x90; 这里我只说下为什么是ISER[1]和40; ISER[0]为u32类型,40已经超过32,所以用ISER[1],ISER[1]从32开始来对中断进行使能。 为什么是40呢,还是看中断向量表,因为我用的是PE14,EXTI有 ![](https://box.kancloud.cn/2016-06-21_576915b2b0b54.jpg) ![](https://box.kancloud.cn/2016-06-21_576915b2c5504.jpg) ![](https://box.kancloud.cn/2016-06-21_576915b2d788d.jpg) 看了这个中断向量表,还有疑问吗?  5、Function of Interrupt Function Name 一定要跟中断向量名一致,这里我举个例子就算了,不过在函数结束的时候一定要清空中断向量标志。 ~~~ void EXTI15_10_IRQHandler(void) { static u8 flag = 0; if((EXTI->PR & GPIO_Pin_14) != RESET) { flag = ~flag; delay_ms(20); if(flag) GPIOE->BRR |= GPIO_Pin_0; //LED ON else GPIOE->BSRR |= GPIO_Pin_0;//LED OFF } EXTI->PR |= GPIO_Pin_14; //clear flag of interrupt } ~~~ PR寄存器只要写入1即可清0. OK,今天到此结束,明天继续。请大家多多指点!!