中断系统与外部中断EXTI

中断系统与外部中断EXTI
1、中断的概念中断在主程序运行过程中出现了特定的中断触发条件中断源使得CPU暂停当前正在运行的程序转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行。它基于ARM Cortex-M内核的NVIC嵌套向量中断控制器支持复杂的中断嵌套和灵活的优先级管理。中断优先级当有多个中断源同时申请中断时CPU会根据中断源的轻重缓急进行裁决优先响应更加紧急的中断源。中断嵌套当一个中断程序正在运行时又有新的更高优先级的中断源申请中断CPU再次暂停当前中断程序转而去处理新的中断程序处理完成后依次进行返回。中断的作用提高系统运行的实时性。2、中断的执行流程3、NVIC中断优先级分组GD32F303支持配置抢占优先级和子优先级各中断都有自己的优先级IP寄存器CUP内部共240个4位5组优先级只使用了优先级寄存器IP的高四位4 ~ 7位由两部分构成分别对应高位的抢占优先级和低位的子优先级。Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0使用未使用两部分各占几位统一由CPU里的AIRCR寄存器来设置优先级分组抢占优先级子优先级高四位描述0(7)0级0 ~ 15级0bit用于抢占优先级4bit用于子优先级1(6)0 ~ 1级0 ~ 7级1bit用于抢占优先级3bit用于子优先级2(5)0 ~ 3级0 ~ 3级2bit用于抢占优先级2bit用于子优先级3(4)0 ~ 7级0 ~ 1级3bit用于抢占优先级1bit用于子优先级4(3)0 ~ 15级0级4bit用于抢占优先级0bit用于子优先级寄存器名称寄存器描述ISER中断使能寄存器每一位对应一个中断ICER中断禁能寄存器每一位对应一个中断ISPR中断挂起寄存器每一位对应一个中断ICPR中断清除寄存器每一位对应一个中断IABR中断活动状态寄存器IP中断优先级寄存器8位宽,240个STIR软触发中断寄存器CPUIDCPUID寄存器ICSR中断控制及状态寄存器VTOR向量表偏移量寄存器AIRCR应用程序中断及复位控制寄存器......CPACR协处理器访问控制寄存器NVIC硬件结构抢占优先级高的可以中断嵌套子优先级高的可以优先排队抢占优先级和子优先级均相同的按中断号排队。数值越小优先级越高。设计抢占优先级目的是当前中断服务函数还未执行完又产生了新的中断需要判断是否暂停当前中断去执行新的中断服务函数。设计子优先级目的是①只有在两个中断同时发生抢占优先级相同时才起作用数值越小优先执行。②如果两个中断的抢占优先级相同子优先级高的中断不能打断子优先级低的中断。编号是硬件定义好的不可改变。4、EXTI外部中断①EXTI简介EXTI可以监测指定GPIO口的电平信号当其指定的GPIO口产生电平变化时EXTI将立即向NVIC发出中断申请经过NVIC裁决后即可中断CPU主程序使CPU执行EXTI对应的中断程序。EXTI提供3种触发类型上升沿触发下降沿触发和任意沿触发。所有GPIO口都可以但相同的Pin不能同时触发中断。②EXTI硬件结构③EXTI触发源④硬件触发硬件触发被用来检测外部或内部信号的电压变化。软件需要按如下步骤配置来使用这项功能1. 根据应用需要配置 AFIO模块中的EXTI 触发源2. 配置EXTI_RTEN寄存器和EXTI_FTEN寄存器以使能相应引脚的上升沿或下降沿检测软件应当同时配置引脚对应的 RTENx和FTENx位以检测该引脚上升沿和下降沿的变化3. 通过配置引脚对应的 EXTI_INTEN 或 EXTI_EVEN位使能中断或事件4. EXTI 开始检测被配置的引脚上的电平变化当这些引脚上期望的变化被检测到时使能的中断或事件将被触发。如果为中断触发则对应的PD位将立刻被置1如果为事件触发则对应的 PD位不被置1。软件需要响应该中断或事件并清除相应PDx位。⑤软件触发按照如下步骤软件也可以触发 EXTI中断或事件1. 配置对应的 EXTI_INTEN 或 EXTI_EVEN位使能中断或事件配置EXTI_SWIEV寄存器的对应SWIEVx位使能的中断或事件将被立即触发。如果为中断触发则对应的PD位将立刻被置1如果为事件触发则对应的PD位不被置1。软件需要响应该中断或事件并清除相应PDx位。⑥代码编写1.初始化GPIO:①使能GPIO时钟;②输入模式;2.初始化EXTI:①使能EXTI时钟;②配置I/O连接到EXTI线;③配置上升/下降沿;④清除标志;⑤使能中断。#include stdint.h #include gd32f30x.h #include led_driver.h #include key_exti.h static void GpioInit(void) { /*使能GPIO的时钟*/ rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_GPIOG); /*配置按键的IO为浮空输入模式*/ gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, GPIO_PIN_0); //KEY1 gpio_init(GPIOG, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, GPIO_PIN_13); //KEY2 gpio_init(GPIOG, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, GPIO_PIN_14); //KEY3 gpio_init(GPIOG, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, GPIO_PIN_15); //KEY4 } static void ExtiInit(void) { /* 使能EXTI时钟 */ rcu_periph_clock_enable(RCU_AF); /* 配置EXTI0 */ /* 配置I/O连接到EXTI0线 */ gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0); /* 配置上升/下降沿 */ exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING); /* 清除标志 */ exti_interrupt_flag_clear(EXTI_0); /* 使能中断 */ nvic_irq_enable(EXTI0_IRQn, 1, 1); /* 配置EXTI13 - EXTI15 */ /* 配置I/O连接到EXTI13 - EXTI15线 */ gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOG, GPIO_PIN_SOURCE_13); gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOG, GPIO_PIN_SOURCE_14); gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOG, GPIO_PIN_SOURCE_15); /* 配置上升/下降沿 */ exti_init(EXTI_13, EXTI_INTERRUPT, EXTI_TRIG_FALLING); exti_init(EXTI_14, EXTI_INTERRUPT, EXTI_TRIG_FALLING); exti_init(EXTI_15, EXTI_INTERRUPT, EXTI_TRIG_FALLING); /* 清除标志 */ exti_interrupt_flag_clear(EXTI_13); exti_interrupt_flag_clear(EXTI_14); exti_interrupt_flag_clear(EXTI_15); /* 使能中断 */ nvic_irq_enable(EXTI10_15_IRQn, 1, 1); } void KeyExtiInit(void) { GpioInit(); ExtiInit(); } void EXTI0_IRQHandler(void) { /* 清除标志 */ exti_interrupt_flag_clear(EXTI_0); TurnOnLed(LED1); } void EXTI10_15_IRQHandler(void) { if(SET exti_interrupt_flag_get(EXTI_13)) { /* 清除标志 */ exti_interrupt_flag_clear(EXTI_13); TurnOnLed(LED2); } if(SET exti_interrupt_flag_get(EXTI_14)) { /* 清除标志 */ exti_interrupt_flag_clear(EXTI_14); TurnOnLed(LED3); } if(SET exti_interrupt_flag_get(EXTI_15)) { /* 清除标志 */ exti_interrupt_flag_clear(EXTI_15); TurnOffLed(LED1); TurnOffLed(LED2); TurnOffLed(LED3); } } #ifndef _KEY_EXTI_H_ #define _KEY_EXTI_H_ void KeyExtiInit(void); #endif /* __KEY_EXTI_H__ */5、启动流程按键如何触发进入到中断中单片机上电以后首先从Reset_Handler开始执行Reset_Handler也是一种中断属于内核的一种异常。CPU执行时会用到一些内部寄存器特别重要的一个寄存器就是R15又叫PC寄存器在CPU执行过程中该32位寄存器始终保存着下一条要执行机器码的存储地址。使用查看编译生成的.map文件该文件内有很多编译信息在编译信息中可以找到Reset_Handler的起始地址。该部分代码作用是分配中断服务函数的起始地址DCD是告诉编译器编译时预留四字节的固定空间用于存放中断函数的起始地址。每一个中断都有一个唯一中断号。6、bin文件bin文件是最终烧录进单片机的程序。①生成bin文件设置输出文件的名字为ARM。设置编译后生成bin文件fromelf --bin --output .\Objects\ARM.bin .\Objects\ARM.axf·生成的文件可以在Objects文件夹中②解析bin文件找到JLINK安装路径打开J-Flash V7.58a打开后点击叉号生成的bin文件拖进J-Flash V7.58a中起始地址设置为0x08000000设置4字节对齐可以看到Reset_Handler的起始地址0x0800015f是B.对应的起始地址结合.map文件同样可以找到其他中断函数的入口地址比如EXTI0_IRQHandler中断向量表可查看数据手册160页有详细的向量编号、向量地址说明7、中断常见BUG①使能了中断未实现中断服务函数会怎么样所有的中断如果没有实现函数代码都会在发生中断时进入执行到.s文件的335行 B .代码其实这个代码也是中断服务函数上面的就是函数的名字所有中断函数代码都是B .这些函数是弱函数如果我们自己没有实现就会使用自带的这些函数。②中断标志不清除会怎么样如果不清除中断标志位就会一直触发中断执行这个中断服务函数。③中断抢占void EXTI0_IRQHandler(void) { /* 清除标志 */ exti_interrupt_flag_clear(EXTI_0); ToggleLed(LED1); //while (1); // 如果此时KEY1又再次按下是不会再次进入这个函数的因为自己不能抢占自己优先级是一样的 DelayNms(5000); // 如果在此期间KEY1又再次按下会等延时函数执行完会再次进入到本函数执行第二次对应的硬件中断 }