目录
2)开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。
main.c中完整代码
这章的代码主要分布在固件库的 stm32f10x_exti.h 和 stm32f10x_exti.c 文件中,但中断线及中断初始化配置文件在stm32f10x_gpio.h 和 stm32f10x_gpio.c中 。
外部中断实现的功能:
利用key按键,中断控制led灯。
KEY1对LED1取反
KEY0对LED0取反
WK UP对LED1和LED0同时取反
建立工程文件
工程文件如下:
编写外部中断初始化函数
1)初始化 IO 口为输入。
void EXTIX_Init(void)
{
KEY_Init();//初始化io口
}
2)开启 IO 口复用时钟,设置 IO 口与中断线的映射关系。
例如我们要用的WK UP对应串口为PA0,则函数中对应变量填(GPIO_PortSourceGPIOA,GPIO_PinSource0)
当我们要利用其他key时,这行代码只需更改红色部分即可。
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//中断线0
3)初始化线上中断,设置触发条件等。
EXTI_InitTypeDef EXTI_InitStructure;//定义结构体变量
EXTI_InitStructure.EXTI_Line=EXTI_Line0; //中断线0,与GPIO中相同
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器
4)配置中断分组(NVIC),并使能中断。
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //中断优先级分组初始化
外部中断初始化函数完整代码
void EXTIX_Init(void)
{
KEY_Init();//初始化io口
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource0);//中断线0
EXTI_InitTypeDef EXTI_InitStructure;//定义结构体变量
EXTI_InitStructure.EXTI_Line=EXTI_Line0; //中断线0,与GPIO中相同
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //中断优先级分组初始化
}
编写服务函数
void EXTI0_IRQHandler(void)
{
delay_ms(10); //延时函数
if(WK_UP==1)
{
LED0=!LED0;
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line0); //手动清除挂起位
}
这里需要说明一下,中断服务函数的名字是 在 MDK 中事先有定义的。STM32 的 IO 口外部中断函数只有 6 个,分别为:
EXPORT EXTI0_IRQHandler
EXPORT EXTI1_IRQHandler
EXPORT EXTI2_IRQHandler
EXPORT EXTI3_IRQHandler
EXPORT EXTI4_IRQHandler
EXPORT EXTI9_5_IRQHandler
EXPORT EXTI15_10_IRQHandler
中断线 0-4 每个中断线对应一个中断函数,中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中 断线 10-15 共用中断函数 EXTI15_10_IRQHandler。
此时,我们的exti.c文件中的代码为:
#include "exti.h"
void EXTIX_Init(void)
{
KEY_Init();//初始化io口
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//中断线0
EXTI_InitTypeDef EXTI_InitStructure;//定义结构体变量
EXTI_InitStructure.EXTI_Line=EXTI_Line0; //中断线0,与GPIO中相同
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //中断优先级分组初始化
}
void EXTI0_IRQHandler(void)
{
delay_ms(10); //延时函数
if(WK_UP==1)
{
LED0=!LED0;
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line0); //手动清除,确保下次能进入中断服务函数
}
按照以上方法,只需更改gpio口和中断线序号,就可以设置其他的服务函数;
exti.c中完整代码为:
#include "exti.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
//外部中断初始化函数
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;//定义结构体变量,一遍即可
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断使能AFIO时钟
KEY_Init();//初始化io口
//GPIOC.5 中断及中断初始化设置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
EXTI_InitStructure.EXTI_Line=EXTI_Line5;//中断线5,与GPIO中相同
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
//GPIOA.15 中断及中断初始化设置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);
EXTI_InitStructure.EXTI_Line=EXTI_Line15; //中断线15,与GPIO中相同
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级 0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //GPIOA.0中断及中断初始化设置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的参数初始化外设 EXTI 寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据参数设置寄存器
}
void EXTI0_IRQHandler(void)
{
delay_ms(10); //消抖
if(WK_UP==1)
{
LED0=!LED0;
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line0); //手动清除,确保下次能进入中断服务函数
}
void EXTI9_5_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY0==0) {
LED0=!LED0;
}
EXTI_ClearITPendingBit(EXTI_Line5); //手动清除,确保下次能进入中断服务函数
}
void EXTI15_10_IRQHandler(void)
{
delay_ms(10); //消抖
if(KEY1==0) {
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line15); //手动清除,确保下次能进入中断服务函数
}
接下来编写主函数
main.c中完整代码
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "key.h"
#include "usart.h"
#include "exti.h"
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 中断优先级2
uart_init(9600); //设置波特率为9600
LED_Init(); //led串口初始化
EXTIX_Init(); //中断初始化
LED0=0; //点亮LED
while(1)
{
printf("OK\n");
delay_ms(1000);
}
}