上一篇:STM32-(20):I2C通信(实验:读写EEPROM) | 下一篇:STM32-(22):定时器TIM |
---|
NVIC:提供中断控制器,用于总体管理异常,称之为“内嵌向量中断控制器:Nested Vectored Interrupt Controller (NVIC)”。NVIC和处理器内核紧密相连.
中断的概念:
1、为什么需要中断?
有很重要的事件需要处理
2、中断来之之后,CPU需要做什么?
首先保护现场,处理中断,恢复现场
3、中断完了之后,怎么办?
继续处理原来的事件
1.编写一个数码管不断刷新和显示的程序:
当用户按下键盘时,数码管停止更新;当用户再次按下键盘时,数码管继续更新。
按键电路:
Main()
{
while(1)
{
//数码管的值的更新函数
//数码管刷新函数
//按键判断函数
}
}
STM32的中断机制
1.Cortex------>NVIC:内嵌中断进入内核
①:这个中断反应速度快
②:标准化
2.所有I/O可以连接到中断源
STM32的中断向量表
Cortex 内核的中断
其中重要的是 “名称”和“地址”,为每一个不同的中断分配一个唯一的中断服务程序的地址,中断服务程序的地址用于保存跳转指令,即执行完中断程序之后如何跳转回来。
STM32 芯片的中断
NVIC中断优先级
中断优先级高的中断可以抢占中断优先级低的中断,从而实现了中断嵌套。
STM 32( Cortex - M 3)中有两个优先级的概念——抢占式优先级(主优先级)和响应优先级(从优先级),每个中断源都需要被指定这两种优先级。具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。
当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。
Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位由8位减少到4位,这4个寄存器位的分组方式如下:
第0组:所有4位用于指定响应优先级
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
第4组:所有4位用于指定抢占式优先级
可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:
NVIC_PriorityGroup_0 => 选择第0组
NVIC_PriorityGroup_1 => 选择第 1 组
NVIC_PriorityGroup_2 => 选择第 2组
NVIC_PriorityGroup_3 => 选择第 3组
NVIC_PriorityGroup_4 => 选择第4组
typedef struct
{
u8 NVIC_IRQChannel; //中断通道
u8 NVIC_IRQChanneIPreemptionPriority; //主优先级
u8 NVIC_lRQChannelSubPriority; //从优先级
FunctionalState NVIC_IRQChannelCmd; //中断是否使能
} NVIC_InitTypeDef;
外部中断映像
STM32外部中断:所有的 I/O 口都可以做中断使用
STM32的外部中断
外部中断/事件控制器由19个产生亊件/中断要求的边沿检测器组成。每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以被独立的屏蔽。挂起寄存器保持着状态线的中断要求。
硬件中断选择
通过下面的过程来配置19个线路做为中断源:
• 配置19个中断线的屏蔽位( EXTI_IMR )
• 配置所选中断线的触发选择位( EXTI_RTSR 和 EXTI _ FTSR );
• 配置那些控制映像到外部中断控制器( EXTI )的 NVIC 中断通道的使能和屏蔽位,使得19个中断线中的请求可以被正确地响应。
硬件事件选择
通过下面的过程.可以配置19个线路为事件源
• 配置19个事件线的屏蔽位( EXTI_EMR )
• 配置事件线的触发选择位( EXTI_RTSR and EXTI _ FTSR )
软件中断/事件的选择
19个线路可以被配置成软件中断/事件线。下面是产生软件中断的过程:
• 配置19个中断/事件线屏蔽位( EXTI_IMR,EXTI_EMR )
•设置软件中断寄存器的请求位( EXTI_SWIER )
中断原理图
简析:peripheral interface (外围接口)下方一排从左到右分别是:中断屏蔽寄存器、挂起请求寄存器、软件中断事件寄存器、上升沿选择寄存器、下降沿选择寄存器,当右侧 Input Line 输入信号,经过 标号4处的edge detect circuit(边缘检测电路),满足上升或者下降沿的要求,则继续向左,到达3处,同 软件中断事件寄存器 是“或”的关系,即软件也可以触发一个外部中断事件(模拟外部中断事件), 经过3之后,如果有挂起请求的操作,则经过处理与上 interrupt mask register (中断掩码寄存器)再到达内核处1,若没有挂起请求,则到达2处,同 event mask register(事件掩码寄存器)是“与的关系”,判断当前中断是否被屏蔽(事件线屏蔽位),如果没有屏蔽,则 pluse generator (脉冲发生器),即产生中断。
中断屏蔽寄存器
事件屏蔽寄存器
上升沿触发选择寄存器
下降沿触发选择寄存器
软件中断事件寄存器
挂起寄存器
中断相关设置
一、STM32中断编程的规定动作
1.开启时钟
2.GPIO设置
3.中断源设置(选择中断源、清除原有的中断标志、触发模式……)
4.外部中断寄存器的设置(NVIC配置Group、指定信息)
5.中断服务子程序
二、源码分析
继续用按键电路分析:
底板上的按键的中断最终连接的是核心板上的 GPIO口的 PB6
代码
EXTI.c
/********************************************************************
* 文件 :EXTI.c
* 描述 :STM32f103VCT6的中断配置
* 说明 :外部中断线6产生中断时,进入中断服务程序后让蜂鸣器响
********************************************************************/
#include"stm32f10x_lib.h"
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* =======================开启时钟================*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); // 使能APB2外设GPIOC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* =======================GPIO口配置================*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //配置PB6为外部中断
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);
//函数功能:选择GPIO管脚用作外部中断线路;第一个参数是 端口源,第二个参数是 引脚源,这里是PB端口,第6个引脚
EXTI_DeInit(); //将EXIT寄存器重设置为缺省值
EXTI_InitStructure.EXTI_Line = EXTI_Line6 ; //中断线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt ; //中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //双边沿
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure); //初始化
EXTI_ClearITpendingBit(EXTI_Line6); //清除 EXTI线路挂起位
}
main.c
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h" //包含了所有的头文件 它是唯一一个用户需要包括在自己应用中的文件,起到应用和库之间界面的作用。
#include <stdio.h>
//-----------------函数的声明-------------
void Delay_MS(u16 dly);
void RCC_Configuration(void);
void GPIO_Configuration(void);
//----------------外部函数的声明=-----------
extern void EXTI_Configuration(void);
void NVIC_Configuration(void);
int main(void)
{
#ifdef DEBUG
debug();
#endif
RCC_Configuration();
GPIO_Configuration();
EXTI_Configuration();
NVIC_Configuration();
while(1)
{
GPIO_SetBits(GPIOA, GPIO_Pin_3); //刚开始设置为1,此时蜂鸣器不发声
Delay_MS(1000);
// GPIO_ResetBits(GPIOA, GPIO_Pin_3);
// Delay_MS(1000);
}
}
/*******************************************************************************
* Function Name : Delay_Ms
* Description : delay 1 ms.
* Input : dly (ms)
* Output : None
* Return : None
*******************************************************************************/
void Delay_MS(u16 dly)
{
u16 i,j;
for(i=0;i<dly;i++)
for(j=1000;j>0;j--);
}
/*******************************************************************************
* Function Name : RCC_Configuration
* Description : Configures the different system clocks.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void RCC_Configuration(void)
{
//----------使用外部RC晶振-----------
RCC_DeInit(); //初始化为缺省值
RCC_HSEConfig(RCC_HSE_ON); //使能外部的高速时钟
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等待外部高速时钟使能就绪
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer
FLASH_SetLatency(FLASH_Latency_2); //Flash 2 wait state
RCC_HCLKConfig(RCC_SYSCLK_Div1); //HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); //PCLK2 = HCLK
RCC_PCLK1Config(RCC_HCLK_Div2); //PCLK1 = HCLK/2
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
RCC_PLLCmd(ENABLE); //Enable PLLCLK
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock
while(RCC_GetSYSCLKSource()!=0x08); //Wait till PLL is used as system clock source
//---------打开相应外设时钟--------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能APB2外设的GPIOA的时钟
}
/*******************************************************************************
* Function Name : GPIO_Configuration
* Description : 初始化GPIO外设
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //选择PA.3
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化GPIOA寄存器
}
void NVIC_Configuration(void) //中断配置
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //中断6属于5-9这个通道范围,具体可参照手册
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 只有一个中断,不存在抢占啥的,所以这两项配置为0即可
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure);
}
stm32f10x_it.c (中断服务子程序)
void EXTI9_5_IRQHandler(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_3); //中断来了,设置为0,蜂鸣器发声
Delay_MS(1000);
EXTI_ClearITPendingBit(EXTI_Line6); //响应一次中断后,立马清除本次相关中断标志
}
上一篇:STM32-(20):I2C通信(实验:读写EEPROM) | 下一篇:STM32-(22):定时器TIM |
---|