一、与STM32中断有关的寄存器:(通过结构体设置)
1 、ISER[2]:中断使能寄存器组,CM3内核含有256个中断,由8个32位寄存器控制,STM32_F103可屏蔽中断只有60个,只用了ISER[0];ISER[1];
ISER[0]的bit0~bit31对应中断0~31,ISER[1]的bit0~bit27对应中断32~59. 写1有效
2、ICER[2]:中断除能寄存器组,STM32的清除中断并非向ISER写0来清除,而是设置一个ICER来清除。 写1有效
3、ISPR[2]:中断挂起寄存器组,将正在执行的中断挂起,而执行同级或更高级别的中断,写0无效。 写1有效
4、ICPR[2]:中断解挂寄存器组,与ICER作用一样,置1解挂。 写1有效
5、IABR[2]:激活标志位寄存器组,同ISER一样,如果为1,表示该位正在被执行,通过它可知道当前在执行的中断时哪一位,中断执行完,硬件请0。
6、IP[240:中断优先级控制寄存器组,(十分重要!)240个8位寄存器组成,STM32只有60个,IP[59]~IP[0],每个中断的8位中,只占用高4位bit[7:4],这4位又分为抢占优先级和响应优先级,而这两个优先级各占几个字节,又要根据SCB->AIRCR寄存器的bit[10:8]位来定义:具体分配关系如下
假如:设定中断优先级为组2:(那么他就有2位抢占优先级和2位响应优先级,即4个抢占,4个响应)设置第一个中断:2抢占 1响应。第二个中断:3抢占 1响应
第三个中断:2抢占 0响应 、那么这三个中断优先级为:3>1>2。有三个注意点如下
1、如果两个中断抢占与响应一样,则那个先发生执行哪个 (数值越小,优先级越高)
2、优先级高的抢占可以打断优先级低的,但是响应优先级高的响应不可以打断低的。(上例中1和3均可以打断2,但是1和3不可以相互打断)
3、写代码的时候中断分组都要统一
二、外部I/O中断的一般步骤
1、初始化I/O输入。
2、开启I/O口复用时钟,设置I/O口与中短线的映射关系
3、初始化线上中断,设置触发条件
4、配置中断分组(NVIC),并使能中断
5、编写中断服务函数
三、程序深解
//设置NVIC分组
//NVIC_Group:NVIC分组0~4 共5组
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)
{
u32 temp,temp1;
temp1=(~NVIC_Group)&0x07; //取后三位 、(~NVIC_Group)取反的意思是中断分组设置表中组0对应111,取反后对应000,即0组
temp1<<=8; //STM32的中断分组由SCB->AIRCR寄存器的bit[10:8]位来定义 所以左移8位
temp=SCB->AIRCR; //读取先前的设置
temp&=0X0000F8FF; //清空先前分组
temp|=0X05FA0000; //写入钥匙,修改SCB->AIRCR寄存器需要先写入0x05FA这个密匙后才可以修改
temp|=temp1;
SCB->AIRCR=temp; //设置分组
}
//设置NVIC
//NVIC_PreemptionPriority //抢占优先级
//NVIC_SubPriority //响应优先级
//NVIC_Channel //中断编号(范围0~59)
//NVIC_Group //中断分组(0~4)
//NVIC_SubPriorit和ÍNVIC_PreemptionPriority的原则是:数值越小越优先
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)
{
u32 temp;
MY_NVIC_PriorityGroupConfig(NVIC_Group); //设置分组
temp=NVIC_PreemptionPriority<<(4-NVIC_Group);
temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
temp&=0xf; // 取低4位
if(NVIC_Channel<32)NVIC->ISER[0]|=1<
NVIC->IP[NVIC_Channel]|=temp<<4; //将计算结果付给IP设置响应优先级和抢占优先级
}
EXTI外部中断寄存器结构体
//外部中断配置函数
//只针对GPIOA~G
//GPIOx:0~6代表A~G BITx:使能位 TRIM:触发模式 1:下降沿 2:上升沿 3:任意
//该函数一次只能配置一个I/O口,多个I/O口需要多次调用
//自动开启对应中断,以及屏蔽线
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)
{
u8 EXTADDR;
u8 EXTOFFSET;
EXTADDR=BITx/4; //得到中段寄存器组 EXTICR[0]代表了GPIOx.0~4位 所以对4取整得到寄存器组
EXTOFFSET=(BITx%4)*4; //假如BIT为3 则EXTADDR=0;EXTOFFSET=12 即EXTI[3] 下面会有介绍
RCC->APB2ENR|=0x01; //使能I/O口复用时钟
AFIO->EXTICR[EXTADDR]&=~(0x000F<
EXTI->IMR|=1<
EXTICR[0]~EXTICR[3] 这4个寄存器组用来配置中短线到哪个I/O上,每个寄存器只用了低16位。
EXTICR[0]的[3:0]位对应EXTI0,这4位从0000~0110对应GPIOA~G.0;EXTICR[0]的[4:7]位对应EXTI1,这4位从0000~0110对应GPIOA~G.1
EXTICR[0]的[8:11]位对应EXTI2,这4位从0000~0110对应GPIOA~G.2;EXTICR[0]的[12:15]位对应EXTI3,这4位从0000~0110对应GPIOA~G.3
EXTICR[1]的[3:0]位对应EXTI4,这4位从0000~0110对应GPIOA~G.4;EXTICR[1]的[4:7]位对应EXTI5,这4位从0000~0110对应GPIOA~G.5
EXTICR[1]的[8:11]位对应EXTI6,这4位从0000~0110对应GPIOA~G.6;EXTICR[1]的[12:15]位对应EXTI7,这4位从0000~0110对应GPIOA~G.7
EXTICR[2]的[3:0]位对应EXTI8,这4位从0000~0110对应GPIOA~G.8;EXTICR[2]的[4:7]位对应EXTI9,这4位从0000~0110对应GPIOA~G.9
EXTICR[2]的[8:11]位对应EXTI10,这4位从0000~0110对应GPIOA~G.10;EXTICR[2]的[12:15]位对应EXTI11,这4位从0000~0110对应GPIOA~G.11
EXTICR[3]的[3:0]位对应EXTI12,这4位从0000~0110对应GPIOA~G.12;EXTICR[3]的[4:7]位对应EXTI13,这4位从0000~0110对应GPIOA~G.13
EXTICR[3]的[8:11]位对应EXTI14,这4位从0000~0110对应GPIOA~G.14;EXTICR[3]的[12:15]位对应EXTI15,这4位从0000~0110对应GPIOA~G.15
下面看一下STM32处理中断的映射图
STM32的每个I/O口均可作为外部中断输入,支持19个外部中断/事件请求。每个中断有状态位,每个事件/中断都有独立的触发和评比设置。STM32F103有19个外部中断:
分别为: 线0~15:对应外部I/O口的输入中断
线16 : 连接到PVD输出。(电源电压过低,产生中断)
线17 :连接RTC闹钟事件。
线18 :连接到USB唤醒事件。
STM32中短线有16个,但是I/O口却不止16个,它把GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线0~15,这样就可以解决问题了,比如线0,可以映射DA到GPIOA.0,
GPIOB.0,~,GPIOG.0。
接下来就是应用
//外部中断0服务程序
void EXTI0_IRQHandler(void)
{
delay_ms(10);
if(KEY3==1)
{
LED0=0;
}
EXTI->PR=1<<0; //PR:挂起寄存器。当外部中断发生了选择的边沿事件,该寄存器的对应为会被置1。0表示对应线上没有触发请求,写1来清除中断请求
}
//外部中断2服务程序
void EXTI2_IRQHandler(void)
{
delay_ms(10);
if(KEY2==0)
{
LED0=!LED0;
}
EXTI->PR=1<<2;
}
void EXTIX_Init(void)
{
KEY_Init();
Ex_NVIC_Config(GPIO_A,0,RTIR);
Ex_NVIC_Config(GPIO_E,2,FTIR);
MY_NVIC_Init(2,3,EXTI0_IRQn,2);
MY_NVIC_Init(2,2,EXTI2_IRQn,2);
}
以上为STM32_外部中断(寄存器版)_笔记 初学者,有不完善的,待修改