萌新学习日志使用的单片机为stm407zet6欢迎各位rape me。想三分钟速通直接看第三大标题。一、概念中断指的是CPU来处理和响应外部发生的异常中断也就意味着打断比如打断正在做的事然后去处理一个紧急的事处理完成后在继续做刚才没做完的事。人话aho哥我正在给小美辅导作业但是小美的男同学振文哥突然叫她一起去逛美食街逛完后再找aho哥我辅导作业。这个突然去逛美食街的一瞬间叫做中断。1.中断源分析中断源指的是中断发生的源头中断源在内核中已经定义好了中断源也称为向量表向量表在STM32F4中文参考手册参考。人话小美桑的备胎表专门用来打断aho哥我给小美辅导作业。(产生中断的硬件)图 1.1.1Cortex-M4内核一共支持256个中断其中有16个内核中断240个外部中断只不过对于STM32F407系列来说只用到了一部分包含了10个内核中断不可屏蔽中断无法通过软件进行控制、82个外部中断可屏蔽中断可以通过软件进行控制。2.中断的管理NVIC指的是嵌套向量中断控制器属于内核中的外设作用是管理所有的中断比如中断的使能或失能、中断的优先级.....人话小美在aho哥我辅导写作业过程中突然执行吃饭、睡觉、逛美食街、去博物馆、租旅馆、去游乐园、爬山等事件的计划。图示说明图 1.2.1NVIC管理中断通道的打开与关闭可以把NVIC理解为负责管理所有中断的开关想要使用中断发送中断请求就必须提前打开中断的通道。3.中断的顺序NVIC利用4bit的优先级来管理所有的中断通道STM32中断的优先级分为两种抢占式优先级主优先级 响应式优先级子优先级每种都有16个优先级0~15数字越小优先级越高。优先级抢占响应硬件抢占优先级主优先级抢占优先级高的中断可以打断正在执行的抢占优先级低的中断响应优先级子优先级抢占优先级一样在同时发生多个中断的情况下响应优先级高的中断可先执行但注意当相同抢占优先级的中断A发生即使响应优先级比A高的中断B也不能抢占中断A的执行。规律(1) 抢占优先级高的中断可以打断正在执行的抢占优先级低的中断(2) 抢占优先级相同的中断同时发生响应优先级高的中断先执行(3) 抢占优先级相同的多个中断发生响应优先级高的中断不能打断响应优先级低的中断(4) 抢占优先级和响应优先级相同的多个中断同时发生则按照向量表的中断编号硬件优先级来执行人话如图所示图 1.3.14.中断分组豆包解释在 ARM Cortex-M 内核的 NVIC 中中断分组Interrupt Grouping是对普通 IRQ 中断优先级的精细化管理机制 —— 核心是把中断优先级寄存器的二进制位拆分为「抢占优先级Preemption Priority」和「子优先级Subpriority」两部分以此控制中断的嵌套规则和同优先级中断的响应顺序。分组号抢占优先级位数子优先级位数抢占优先级范围子优先级范围示例场景00 位4 位仅 0 级0~15无嵌套需求仅需排序11 位3 位0~10~7简单嵌套2 级抢占22 位2 位0~30~3中等嵌套4 级抢占33 位1 位0~70~1多嵌套8 级抢占44 位0 位0~15仅 0 级最大化嵌套层级无需子优先级一般stm32f4系列使用分组号2较多即NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);5.实践1. 把EXTI外设的源文件以及SYSCFG外设的源文件添加到项目工程中具体操作如下所示2. 参考ST公司提供的外设的源文件的开头的注释以及参数ST公司提供的关于外设的例程3. 打开GPIOA端口时钟因为KEY0按键对应的引脚PA0以及SYSCFG外设时钟映射4. 配置GPIOA端口PA0引脚的模式为输入模式因为需要利用该引脚检测外部事件如下5. 利用SYSCFG外设的寄存器对GPIOA端口的引脚PA0以及EXTI0建立映射关系自动建立6. 定义EXTI外设的结构体变量对结构体成员进行初始化编号模式边沿状态如下7. 配置EXTI外设的中断需要使用NVIC外设管理中断的通道以及中断的优先级如下图8. 对EXTI中断通道配置完成后需要编写对应的中断服务函数中断服务函数的格式固定废话太长不看然后添油加醋版示例代码如下#include stm32f4xx.h // 你提供的NVIC配置函数补充EXTI中断配置 void NVIC_EXTI_Config(void) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // 1. 配置全局中断分组分组22位抢占2位子优先级 // 危险函数只需要使用一次即可否则会出现未知bug建议将它放到main函数下 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 2、将GPIO引脚连接到相应的EXTI中EXTI被PA0口使用对应芯片为STM32F407ZET6 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // 使用SYSCFG硬件使用 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);// EXTI线被PA0使用了 // 3、配置外部中断 EXTI_InitStructure.EXTI_Line EXTI_Line0; // 外部中断0线 EXTI_InitStructure.EXTI_Mode EXTI_Mode_Interrupt; // 模式中断模式 EXTI_InitStructure.EXTI_Trigger EXTI_Trigger_Falling; // 触发方式下降沿触发 EXTI_InitStructure.EXTI_LineCmd ENABLE; // 使能外部中断 EXTI_Init(EXTI_InitStructure); // 使用该函数将配置的信息写入到相应的寄存器中 // 4. 配置EXTI0中断 NVIC_InitStructure.NVIC_IRQChannel EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; // 抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; // 子优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); } // GPIO配置 void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; // 使能GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // PA0配置浮空输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN; // 模式输入模式 GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; // 上下拉不拉 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); } // -------------------------- 中断服务函数ISR -------------------------- void EXTI0_IRQHandler(void) // 小美被振文哥叫去逛美食街了 { if( EXTI_GetITStatus(EXTI_Line0) SET) // 判断是否触发了外部中断0线 { // ... EXTI_ClearITPendingBit(EXTI_Line0); // 清除外部中断0线的中断挂起标志位 }小结中断服务函数要求1、没有返回值没有形参2、进行中断标志判断3、清除中断标志4、中断服务函数名称系统已经规定但需要自己编写功能代码但不需要调用必须精简5、不能加入过长的延时6、不能调用printf二、其他1.粗略延时函数STM32F407ZET6void DELAY_MyNms(uint16_t nms) { uint32_t i 0; while(nms--) { i 12000; while(i--); } }2.开关灯宏#define LED1(X) (X)?(PFout(9)0) : (PFout(9)1) // 使用位带操作 #define LED2(X) (X)?(PFout(10)0): (PFout(10)1) #define LED3(X) (X)?(PEout(13)0): (PEout(13)1) #define LED4(X) (X)?(PEout(14)0): (PEout(14)1)三、太长不看直接上代码exti.c#include exti.h #include key.h #include buzzer.h #include delay.h /** * brief 初始化按键触发的外部中断 * note GEC-M4板子 * S1(丝印层)-KEY0(网络标号)-PA0(引脚标号)-EXTI0线 * S2(丝印层)-KEY1(网络标号)-PE2(引脚标号)-EXTI2线 * S3(丝印层)-KEY2(网络标号)-PE3(引脚标号)-EXTI3线 * S4(丝印层)-KEY3(网络标号)-PE4(引脚标号)-EXTI4线 * param None * retval None */ void EXTI0234_Init(void) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // 1、配置引脚为输入浮动模式 KEY_Init(); // 2、将GPIO引脚连接到相应的EXTI中 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // 使用SYSCFG硬件使用 SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0); // EXTI线被PA0使用了 // 3、配置外部中断 EXTI_InitStructure.EXTI_Line EXTI_Line0; // 外部中断0线 EXTI_InitStructure.EXTI_Mode EXTI_Mode_Interrupt; // 模式中断模式 EXTI_InitStructure.EXTI_Trigger EXTI_Trigger_Falling; // 触发方式下降沿触发 EXTI_InitStructure.EXTI_LineCmd ENABLE; // 使能外部中断 EXTI_Init(EXTI_InitStructure); // 使用该函数将配置的信息写入到相应的寄存器中 // 4、配置时间的优先等级 NVIC_InitStructure.NVIC_IRQChannel EXTI0_IRQn; // 中断请求通道外部中断0通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0x00; // 抢占式优先级0x00(0) NVIC_InitStructure.NVIC_IRQChannelSubPriority 0x00; // 响应式优先级0x00(0) NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; // 使能NVIC相应的中断请求通道 NVIC_Init(NVIC_InitStructure); // 使用该函数将配置的信息写入到相应的寄存器中 } /** * brief 外部中断0的中断服务函数 * note S1(丝印层)-KEY0(网络标号)-PA0(引脚标号)-EXTI0线 * param None * retval None */ void EXTI0_IRQHandler(void) // 坤坤被温工叫去篮球场打篮球了 { static int flag 0; if(KEY1 0) // 消除按键抖动(不必要的情况下在中断服务函数中不要使用延时尤其是大延时) { DELAY_MyNms(50); if(KEY1 0) { if( EXTI_GetITStatus(EXTI_Line0) SET) // 判断是否触发了外部中断0线 { flag !flag; BUZZER(flag); } } } EXTI_ClearITPendingBit(EXTI_Line0); // 清除外部中断0线的中断挂起标志位 }key.c#include key.h /** * brief 初始化key按键 * note GEC-M4板子 * S1(丝印层)-KEY0(网络标号)-PA0(引脚标号) * S2(丝印层)-KEY1(网络标号)-PE2(引脚标号) * S3(丝印层)-KEY2(网络标号)-PE3(引脚标号) * S4(丝印层)-KEY3(网络标号)-PE4(引脚标号) * param None * retval None */ void KEY_Init(void) { // 0、GPIO片内外设信息初始化结构体 GPIO_InitTypeDef GPIO_InitStructure; // 1、使能GPIO片内外设的硬件时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); // 2、配置GPIO片内外设的引脚 GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; // 引脚第0根引脚 GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN; // 模式输入模式 GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; // 上下拉不拉 GPIO_Init(GPIOA, GPIO_InitStructure); // 使用该函数将配置的信息写入到相应的寄存器中 GPIO_InitStructure.GPIO_Pin GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; // 引脚第2、3、4根引脚 GPIO_Init(GPIOE, GPIO_InitStructure); // 使用该函数将配置的信息写入到相应的寄存器中 }buzzer.c#include buzzer.h #include delay.h #define BUZZER(X) (X)?(PFout(8)1): (PFout(8)0) /** * brief 初始化buzzer蜂鸣器模块 * note GEC-M4板子 * LS2(丝印层)-BEEP网络标号)-PF8 (引脚标号) * param None * retval None */ void BUZZER_Init(void) { // 0、GPIO片内外设信息初始化结构体 GPIO_InitTypeDef GPIO_InitStructure; // 1、使能GPIO片内外设的硬件时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); // 2、配置GPIO片内外设的引脚 GPIO_InitStructure.GPIO_Pin GPIO_Pin_8; // 引脚第8根引脚 GPIO_InitStructure.GPIO_Mode GPIO_Mode_OUT; // 模式输出模式 GPIO_InitStructure.GPIO_Speed GPIO_High_Speed; // 速度高速(100MHz) GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; // 上下拉不拉 GPIO_InitStructure.GPIO_OType GPIO_OType_PP; // 输出类型推挽输出 GPIO_Init(GPIOF, GPIO_InitStructure); // 使用该函数将配置的信息写入到相应的寄存器中 // 3、设置GPIO片内外设引脚的高低电平值 BUZZER(OFF); } /** * brief 蜂鸣器提示音 * note None * param speed提示音的长度 * retval None */ void BUZZER_TipVoice(uint16_t speed) { BUZZER(ON); DELAY_MyNms(speed); BUZZER(OFF); } /** * brief 蜂鸣器警报音 * note None * param speed提示音的长度 * count警报的次数 * retval None */ void BUZZER_WarnVoice(uint16_t speed, uint16_t count) { uint16_t i 0; for(i0; icount; i) { BUZZER(ON); DELAY_MyNms(speed); BUZZER(OFF); DELAY_MyNms(speed); } }delay.c#include delay.h /** * brief 自写延时函数 * note 利用执行语句时产生的时间进行多个语句的调用即可实现粗延时 * param nms延时多少个毫秒 * retval None */ void DELAY_MyNms(uint16_t nms) { uint32_t i 0; while(nms--) { i 12000; while(i--); } }终于结束了。。。≡(▔﹏▔)≡