NVIC与EXTI

中断

基本概念

中断源:触发中断条件

断点:中断执行完之后,返回该断点;

中断服务函数:中断处理;快进快出;

中断可嵌套

image-20201217100646280

Cortex-M3的NVIC

NVIC是 内核的外设

Cortex-M3 支持 240 个优先级可动态配置的中断,每个中断的优先级有 256 个选择。 中断优先级的数目可配置为 1~8 位( 1~256 级)。

51单片机根据中断号,执行相应的中断服务;

NIVC:根据中断号,找对应的中断服务函数;(也就是将程序指针,指向对应 中断号 的 中断入口)

异常和中断

中断是一种我们可以操控的异常;

内核的异常:0~15是已经固化好的;16及以上是芯片厂商做的;

硬件优先级

​ 制定软件优先级后,硬件优先级(可调整)无效;

​ 如果两个或更多的中断指定了相同的优先级, 则由它们的硬件优先级来决定处理器对它们进行处理时的顺序。

image-20201217103654662

内核的外部中断:是相对于内核来说的 “外部”

a. 该异常的优先级可修改,见系统处理器优先级寄存器的位分配。可调整的范围为 NVIC 的 0~N 优先级, N 为能够实现的最高优先级。在内部,用户可设置的最高优先级( 0)被看作 4。
b. 您可以使能或禁止该故障。见系统处理器控制和状态寄存器的位分配。

内核的NVIC寄存器配置

参考手册:Cortex-M3内核编程手册

image-20201217113859611

优先级分组

  • 中断同时到来时先执行高优先级;
  • 分配优先级的 占先 和 次级;其实就是分配 NVIC 的 IPR寄存器 8位数据 中 小数点 的位置;

Cortex-M3的中断优先级分组

image-20201217104319845

  • 是内核支持的优先级分组;

  • STM32 只用了 4个位 来分配优先级分组;

    只有 16个 不同的 优先级分组

  • 如果使用小于 8 的位来配置处理器的优先级,则寄存器的低位始终为 0。例如,如果使用 4 个位来配置优先级,则 PRI_N[7:4]用来配置优先级,而 PRI_N[3:0]为 4`b0000。

STM32的内核中断优先级分组

[内核参考手册]

是由 image-20201217140734931这个寄存器的image-20201217140802175三个位控制的;

image-20201217140924707

从图上可以看出:STM32设置分组的时候:写入的数据大小是 3-7

内核提供的 “优先级分组” 函数:

void NVIC_SetPriorityGrouping(uint32_t priority_grouping);传参为 3~7

设置优先级

优先级的小数点位数是由 “优先级分组” 的时候就规定好的;

设置优先级:

  1. 抢占(占先)
  2. 次级

NIVC 的 IPR 寄存器的设置

翻译:

  1. 可以有0-255个优先级,值越小,优先级越高;
  2. STM32中 使用了 高4位 作为优先级的设置;第四位默认为0;
  3. 优先级设置的值范围:0~15;这个优先级包含了 “抢占” 和 “次级”
image-20201217141157225

内核提供的 “设置优先级” 函数:

void NVIC_SetPriority (IRQn_t IRQn, uint32_t priority)

​ 传入终端号;写入对应的 优先级 0~15

STM32的中断

image-20201217105725937

STM32的中断向量表

硬件的中断顺序

image-20201217110025846

image-20201217110057706

.....................

“位置“ 就是 “中断号“

启动程序中的中断向量表

启动程序的中断向量表:就是 “中断服务函数名”

​ ”函数名就是一个地址“

写 “中端服务函数” 的时候,直接去.s文件中找 “函数名”

中断向量表
; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size
__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler
                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
 

EXTI中断

控制方式

  1. “外部触发” 和 “软件触发” 是 “或” 关系;其中一个成立,就会将中断挂起;
  2. “请求挂起” 和 “中断屏蔽” 是 “与” 关系;两者同时成立,才会向NVIC申请中断请求;
image-20201217110650267

EXTI中断号

EXTI0 EXTI1 EXTI2 EXTI3 EXTI4 EXTI9-5 EXTI15-10

配置步骤

  1. AFIO 时钟
  2. IO口 映射 到 EXTI线 上
  3. 配置触发方式
  4. 清除中断标志
  5. 开启 EXTI 中断
  6. 配置 优先级
  7. 使能NVIC

外部中断的映射

映射:就是把 IO 口 接到 EXTI0 的中断源;

梯形:是一个选择开关;

每个 EXTI 中断源,只能选择一个;

IO 的 EXTI中断的选择 在 AFIO_EXTICR1 寄存器中配置;

image-20201217111018185 image-20201217111824463

选择 EXTI 的中断源

将寄存器的 位 设置成相应的 值 就行了;

image-20201217111854097

EXTI寄存器

  1. 中断屏蔽寄存器--使能EXTI中断
  2. 上升/下降沿 沿触发寄存器--设置EXTI中断源的触发方式
  3. 挂起寄存器--中断的状态
image-20201217111346715

中断屏蔽寄存器

中断开启

image-20201217111507890

中断触发条件

上升沿触发 / 下降沿触发

image-20201217111534485

中断挂起

DCD     EXTI0_IRQHandler           ; EXTI Line 0
DCD     EXTI1_IRQHandler           ; EXTI Line 1
DCD     EXTI2_IRQHandler           ; EXTI Line 2
DCD     EXTI3_IRQHandler           ; EXTI Line 3
DCD     EXTI4_IRQHandler           ; EXTI Line 4
DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5

像 5~9 的 外部中断 需要 在 “中断同一个服务函数” 中判断具体的 “状态寄存器”;

为了方便,每个中断都可以检查一下对应的 “状态位”;

一个 “服务函数” 对应 多个 “中断源” 的时候,要判断中断源对应的 “状态”

image-20201217111628773

EXTI的寄存器配置

选择中断源

配置 PA0 为 EXTI0 的中断源

配置寄存器的 4个位 为 0000

image-20201217113256779

image-20201217113039959

EXTICR在 结构体 中使用 数组来定义的;

image-20201217113220493

EXTI中断方式

上升沿触发、下降沿触发、上升沿和下降沿触发

EXTI->RTSR |= (1<<0);

打开EXTI中断

PA0 对应中断屏蔽位 置1

EXTI->IMR |= (1<<0);

中断优先级分组

只需要配置一次,在主函数开头使用

传参 3 ~ 7 => 5

NVIC_SetPriorityGrouping(5);

优先级配置

0~16;

如果中断分组为 5;

中断优先级为 “4”; // 4 = 01 00 (抢占:1;次级:0)

NVIC_SetPriority(EXTI0_IRQn, 3);

使能NVIC中对应的中断

内核提供了函数:

void NVIC_EnableIRQ(IRQn_t IRQn)

void NVIC_DisableIRQ(IRQn_t IRQn)

中断服务函数

中断服务函数名

查看.s文件的 向量表;

判断中断源

有些 “中断服务函数” 对应着 ”多个中断源“ ;

所以都判断中断源;

清除中断标志

有些中断标志被清除,是通过读取DR寄存器;不需要写寄存器清除中断标志;

  • 寄存器方式清中断:查看手册,找到清除中断标志的方式;
  • 库函数:直接调用一个函数就行了;

中断服务函数内容

在中断中想要干的事;

//EXTI5 6的中断服务函数
void EXTI9_5_IRQHandler(void)
{
	//EXTI5
	if((EXTI->PR & (1<<5)) != 0)
	{
		//清标志
		EXTI->PR |= (1<<5);
		BEEP_Toggle();
	}
	//EXTI6
	if((EXTI->PR & (1<<6)) != 0)
	{
		//清标志
		EXTI->PR |= (1<<6);
		Relay_Toggle();
	}	
}

库函数的获取标志

获取标志位

标志位 = 中断标志 + 其他标志

常用在 “非中断” 时 获取 标志位;

获取中断标志

常用在 “中断” 时, 获取中断标志

中断标志状态

1或者0

参考手册,找到对应的状态寄存器,查看对应的 状态

NVIC代码

NVIC分组代码

/* ##########################   NVIC functions  #################################### */

/**
 * @brief  Set the Priority Grouping in NVIC Interrupt Controller
 *
 * @param  PriorityGroup is priority grouping field
 *
 * Set the priority grouping field using the required unlock sequence.
 * The parameter priority_grouping is assigned to the field 
 * SCB->AIRCR [10:8] PRIGROUP field. Only values from 0..7 are used.
 * In case of a conflict between priority grouping and available
 * priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set.
 */
static __INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
  uint32_t reg_value;
   //只取出 “低三位”
  uint32_t PriorityGroupTmp = (PriorityGroup & 0x07);                         /* only values 0..7 are used          */
  //读 寄存器
  reg_value  =  SCB->AIRCR;                                                   /* read old register configuration    */
  //清零	” &=~ “
  reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk);             /* clear bits to change               */
  //写内容	“ |= ”
  reg_value  =  (reg_value                       |
                (0x5FA << SCB_AIRCR_VECTKEY_Pos) | 
                (PriorityGroupTmp << 8));                                     /* Insert write key and priorty group */
  //写入寄存器
  SCB->AIRCR =  reg_value;
}
posted @ 2020-12-17 14:36  啊振不坏  阅读(849)  评论(0)    收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css