| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2020-07-03 | gingko | 初次建立 | ===== 实验三:EXTI外部中断输入实验——读取ARM按键状态 ===== ==== 一、 实验目的与意义 ==== - 了解STM32 GPIO结构。 - 了解STM32 GPIO 特征。 - 掌握EXTI中断的使用方法。 - 掌握STM32 HAL库中EXTI属性的配置方法。 - 掌握KEIL MDK 集成开发环境使用方法。 ==== 二、 实验设备及平台 ==== - iCore4 双核心板[[https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22598974120.15.5923532fsFrHiE&id=551864196684|点击购买]]。 - JLINK(或相同功能)仿真器[[https://item.taobao.com/item.htm?id=554869837940|点击购买]]。 - Micro USB线缆。 - Keil MDK 开发平台。 - STM32CubeMX开发平台。 - 装有WIN XP(及更高版本)系统的计算机。 ==== 三、 实验原理 ==== === 1、中断简介 === * 中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。 * 中断优先权: * 在某一时刻有几个中断源同时发出中断请求时,处理器只响应其中优先权最高的中断源。当处理机正在运行某个中断服务程序期间出现另一个中断源的请求时,如果后者的优先权低于前者,处理机不予理睬,反之,处理机立即响应后者,进入所谓的“嵌套中断”。中断优先权的排序按其性质、重要性以及处理的方便性决定,由硬件的优先权仲裁逻辑或软件的顺序询问程序来实现。 * 中断过程: * (1)中断源发出中断请求; * (2)判断当前处理机是否允许中断和该中断源是否被屏蔽; * (3)优先权排队; * (4)处理机执行完当前指令或当前指令无法执行完,则立即停止当前程序保护断点地址和处理机当前状态,转入相应的中断服务程序。 * (5)执行中断服务程序; * (6)恢复被保护的状态,执行“中断返回”指令回到被中断的程序或转入其他程序。 === 2、STM32 NVIC中断简介 === * CM7内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。但STM32F767并没有使用CM7内核的全部东西,而是只用了它的一部分。STM32F767xx总共有118个中断,其中包括10个内核中断和108个可屏蔽中断,具有16级可编程的中断优先级,而我们常用的就是这108个可屏蔽中断。 * STM32F767的中断分组:STM32F767将中断分为5个组,组0~4。该分组的设置是由SCB->AIRCR寄存器的 bit10~8 来定义的。具体的分配关系如下表所示: {{ :icore4:icore4_arm_hal_3_1.png?direct&700 |AIRCR 中断分组设置表}} * 通过这个表,我们就可以清楚的看到组0~4对应的配置关系,例如组设置为3,那么此时所有的108个中断,每个中断的中断优先寄存器的高四位中的最高3位是抢占优先级,低1位是响应优先级。每个中断,你可以设置抢占优先级为0~7,响应优先级为1或0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。 * **这里需要注意两点**:第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。 * 结合实例说明一下:假定设置中断优先级组为2,然后设置中断3(RTC_WKUP中断)的抢占优先级为2,响应优先级为1。中断6(外部中断0)的抢占优先级为3,响应优先级为0。中断7(外部中断1)的抢占优先级为2,响应优先级为0。那么这3个中断的优先级顺序为:中断7>中断3>中断6。 * 上面例子中的中断3和中断7都可以打断中断6的中断。而中断7和中断3却不可以相互打断! === 3、STM32F7 外部中断简介 === * STM32F7的每个IO都可以作为外部中断的中断输入口,这点也是STM32F7的强大之处。STM32F7的中断控制器支持22个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。STM32F7的23个外部中断为: * EXTI线0~15:对应外部IO口的输入中断。 * EXTI线16:连接到PVD输出。 * EXTI线17:连接到RTC闹钟事件。 * EXTI线18:连接到USBOTGFS唤醒事件。 * EXTI线19:连接到以太网唤醒事件。 * EXTI线20:连接到USBOTGHS(在FS中配置)唤醒事件。 * EXTI线21:连接到RTC入侵和时间戳事件。 * EXTI线22:连接到RTC唤醒事件。 * EXTI线23:连接到LPTIM1异步事件。 * 从上面可以看出,中断线0-15对应外部IO口的输入中断,一共是16个外部中断线。STM32F7供IO口使用的中断线只有16个,但是STM32F7的IO口却远远不止16个,那么STM32F7是怎么把16个中断线和IO口一一对应起来的呢?于是STM32就这样设计,GPIO的引脚GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线0~15。这样每个中断线对应了最多9个IO口,以线0为例:它对应了GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0、GPIOH.0、GPIOI.0。而中断线每次只能连接到1个IO口上,这样就需要通过配置来决定对应的中断线配置到哪个GPIO上了。下面我们看看GPIO跟中断线的映射关系图: {{ :icore4:icore4_arm_hal_3_2.png?direct |映射关系图}} * 配置IO口外部中断的一般步骤: * (1)使能IO口时钟。 * (2)调用函数HAL_GPIO_Init设置IO口模式,触发条件,使能SYSCFG时钟以及设置IO口与中断线的映射关系。 * (3)配置中断优先级(NVIC),并使能中断。 * (4)在中断服务函数中调用外部中断共用入口函数HAL_GPIO_EXTI_IRQHandler。 * (5)编写外部中断回调函数HAL_GPIO_EXTI_Callback实现控制逻辑。 * 通过以上几个步骤的设置,我们就可以正常使用外部中断了。 * 实验中,按键的一端与STM32的GPIO(PB9)相连,且PB9外接一个1k大小的限流上接电阻。初始化时把PB9设置成输入模式,当按键弹起时,PB9由于上拉电阻的作用呈高电平(3.3V);当按键按下时,PB9直接被按键短接到GND,呈低电平,因此PB9的电平变化产生下降沿,从而进入中断函数,进入中断回调。原理图如下图所示。 {{ :icore4:icore4_arm_hal_3_3.png?direct&500 |原理图}} ==== 四、 实验程序 ==== === 1、主函数 === int main(void) { /* MCU 配置*/ /* 重置所有外围设备,初始化Flash接口和Systick */ HAL_Init(); /* 配置系统时钟 */ SystemClock_Config(); /* 初始化所有已配置的外围设备 */ MX_GPIO_Init(); LED_RED_ON;//初始化LED状态,红灯亮 while (1) { } } === 2、ARM_KEY引脚初始化 === /*配置ARM_KEY引脚: PB9 */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;//下降沿触发检测的外部中断模式 GPIO_InitStruct.Pull = GPIO_PULLUP;// HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* 外部中断初始化*/ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 15, 0); //设置中断的优先级。 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);// 在NVIC中断控制器中启用设备特定的中断。 === 3、中断回调函数 === void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { static int led_work_status = 0; HAL_Delay(10); if(ARM_KEY_STATE == KEY_DOWN){ led_work_status += 1; if(led_work_status > 2)led_work_status = 0; } switch(led_work_status){ case 0: LED_RED_ON; LED_GREEN_OFF; LED_BLUE_OFF; break; case 1: LED_RED_OFF; LED_GREEN_ON; LED_BLUE_OFF; break; case 2: LED_RED_OFF; LED_GREEN_OFF; LED_BLUE_ON; break; default: break; } __HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_9); //清除EXTI的行挂起标志。 ==== 五、 实验步骤 ==== - 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore4通过Micro USB线与计算机相连,为iCore4供电; - 打开Keil MDK 开发环境,并打开本实验工程; - 烧写程序到iCore4上; - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 ==== 六、 实验现象 ==== * 按键被按下一次,切换一个LED的状态。