stm32的中断功能比较丰富,首先要了解下NVIC(嵌套向量中断控制器),在core_CM3.h中有定义NVIC_Type。关键使用这三个寄存器,ISER 中断使能寄存器、ICER中断清除(失能)寄存器、IP优先级寄存器8位。
NVIC有个专用的寄存器来配置外部中断的优先级,NVIC_IPRx。F103使用了高4位,低四位没有使用。注意:
(1)这四位有分成了抢占优先级和子优先级。
1)多个中断同时来临时,抢占优先级高的会比抢占优先级低的先得到执行。
2)抢占优先级相同的,比较子优先级,子优先级高的先执行。
3)如果抢占、子优先级都相同的话,比较硬件中断号,编号越小,优先级越高。
4)要注意,优先级号越低,优先级越高。
在STM32 中进行了分组:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)函数进行配置分组。
NVIC_PriorityGroup_0: 0bit for 抢占优先级 4 bits for 子优先级;(优先级抢占不存在,有子优先级控制。)
NVIC_PriorityGroup_1: 1 bit for 抢占优先级 3 bits for 子优先级;
NVIC_PriorityGroup_2: 2 bit for 抢占优先级 2 bits for 子优先级;
共有0~4 五组。
如何进行中断编程呢?
(1)先使能外设某个中断
(2)初始化NVIC_InitTypeDef 结构体。这个结构体包含中断源、抢占优先级、子优先级和使能或失能中断。
1)NVIC_IROChannel在stm32f10x.h 中IRQn_Type 中定义。
2)NVIC_IRQChannelPreemptionPriority:抢占优先级
3)NVIC_IRQChannelSubPriority:子优先级
4)NVIC_IRQChannelCmd;中断使能(ENABLE)或者失能(DISABLE)
(3)编写中断服务函数
在启动文件中预先为每一个中断都写了中断服务函数,都是空的,用来初始化中断向量表。重新在stm32f10x_it.c 编写中断服务函数。
(4)EXTI(External interrupt/event controller)—外部中断/事件控制器
看这幅图(来源野火)
EXTI0 至EXTI15 用于GPIO。EXTI0 可以通过AFIO的外部中断配置寄存器1(AFIO_EXTICR1)的EXTI0[3:0]位选择配置为PA0、PB0、PC0、PD0、PE0、PF0、PG0、PH0 或者PI0。
结构体:typedef struct {
uint32_t EXTI_Line; // 中断/事件线
EXTIMode_TypeDef EXTI_Mode; // EXTI 模式
EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
FunctionalState EXTI_LineCmd; // EXTI 使能
} EXTI_InitTypeDef;
NVIC配置:
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
//优先组1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// 中断源key1
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
//子优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
//中能中断
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//初始化NVIC
NVIC_Init(&NVIC_InitStructure);
// 中断源KEY2
NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
//初始化NVIC
NVIC_Init(&NVIC_InitStructure);
}
EXITI 配置:
void EXIT_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
// 配置中断优先级
NVIC_Configuration();
// 初始化GPIO
RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK, ENABLE);
GPIO_InitStruct.GPIO_Pin = KEY1_INT_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStruct);
// 初始化EXTI
RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK, ENABLE); // 时钟
GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, KEY1_INT_EXTI_PINSOURCE);
EXTI_InitStruct.EXTI_Line = KEY1_INT_EXTI_LINE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿中断
EXTI_InitStruct.EXTI_LineCmd = ENABLE; //中断使能
EXTI_Init(&EXTI_InitStruct);
// 初始化GPIO
RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK, ENABLE);
GPIO_InitStruct.GPIO_Pin = KEY2_INT_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStruct);
// 初始化EXTI
RCC_APB2PeriphClockCmd(KEY2_INT_GPIO_CLK, ENABLE); // 时钟
GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, KEY2_INT_EXTI_PINSOURCE);
EXTI_InitStruct.EXTI_Line = KEY2_INT_EXTI_LINE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; //下升沿中断
EXTI_InitStruct.EXTI_LineCmd = ENABLE; //中断使能
EXTI_Init(&EXTI_InitStruct);
}
我们在stm32f10x_it.c 中写中断服务函数
void EXTI0_IRQHandler (void)
{
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) //读是否产生了中断,
{
LED1_TOGGLE; //LED1翻转
}
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE); // 清除中断标志位
}
void KEY2_IRQHandler (void)
{
if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) //读是否产生了中断,
{
LED2_TOGGLE; //LED1翻转
}
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE); // 清除中断标志位
}
main.c 中包含相关头文件后,
while(1){;}
循环就可以了。
注意:(1)初始化GPIO时钟 GPIO ,(2)配置NVIC (3)初始化EXITI 时钟,信号源、边沿触发、使能中断 EXITI_Init() (4)编写中断服务函数;(5)EXTI_GetITStatus()中断检测 ,EXTI_ClearITPendingBit(); 中断标志位清除。
(6)EXITI10~EXITI15 公用一个处理函数。
当MDK注释出现乱码:处理如下