1、外部中断概述。
STM32F10X共有68个可屏蔽中断通道,16个可编程优先级(使用了4位中断优先级)。
互联型产品有20个事件/中断检测器。
其他产品有19个事件/中断检测器。
16个GPIO连接到EXIT0到EXIT15(16个中断线)。
EXIT16连接到PVD事件。
EXIT17连接到RTC闹钟事件。
EXIT18连接到USB唤醒事件。
EXIT19连接到以太网唤醒事件(只适用于互联型产品)。
2、寄存器。
IMR 中断可屏蔽寄存器,interrupt mast register。
EMR 事件可屏蔽寄存器,event masmast register。
RTSR 上升沿触发选择寄存器,rising trigger selection register。
FTSR 下降沿触发选择寄存器,falling trigger selection register。
SWIER 软件中断事件寄存器,software interrupt event register。
PR 挂起寄存器,pending register。
3、外部中断一般步骤。
①初始化IO口为输入。
RCC_APB2PeirphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_Init(GPIOB,&GPIO_InitStrucure);
②开启AFIO时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
③设置IO与中断线映射关系。
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource2);
④初始化线上中断,设置触发条件等。
EXTI_Init(&EXTI_InitStructure);
⑤配置中断分组(NVIC),并使能中断。
NVIC_Init(&NVIC_InitStructure);
⑥编写中断服务函数。
EXTI0_IRQHandler();
16个外部外部中断线共有6个中断处理函数,分别是EXTI0、EXTI1、EXTI2、EXTI3、EXTI4、EXTI9_5、EXTI15_10。
4、函数讲解。
①IO口与中断线映射。操作AFIO(复用功能IO)的EXTICR寄存器。
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
{
uint32_t tmp = 0x00;
/* 判断参数,portsource外部中断端口,pinsource引脚号 */
assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
//引脚号取低两位,乘以4,0x0F左移指定位数。乘以4时因为一个pin的控制占EXTICR的4bit
tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));
//EXTICR共有4个对应Pin0-Pin15,清零引脚号对应的寄存器位置
AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;
//引脚号对应的寄存器位置设置为外部中断端口,即设置为GPIOA.B.C.D.E.F.G其中的一个
AFIO->EXTICR[GPIO_PinSource >> 0x02] |=
(((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
}
②初始化外部中断参数。caoI操作断屏蔽、EMR事件屏蔽、RTSR上升沿触发、FTSR下降沿触发。
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
{
uint32_t tmp = 0;
/* 检查参数,MODE模式中断或事件,TRIGGER触发上升沿或下降沿,LINE中断线号,STATE状态使能与否 */
assert_param(IS_EXTI_MODE(EXTI_InitStruct->EXTI_Mode));
assert_param(IS_EXTI_TRIGGER(EXTI_InitStruct->EXTI_Trigger));
assert_param(IS_EXTI_LINE(EXTI_InitStruct->EXTI_Line));
assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->EXTI_LineCmd));
tmp = (uint32_t)EXTI_BASE; //tmp赋值外部中断基地址
if (EXTI_InitStruct->EXTI_LineCmd != DISABLE) //中断使能
{
/* 清零中断屏蔽对应中断线和事件屏蔽对应中断线 */
EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line; //中断屏蔽清零
EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line; //事件屏蔽清零
tmp += EXTI_InitStruct->EXTI_Mode; //通过模式选择是中断屏蔽寄存器还是事件屏蔽寄存器
*(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line; //选择的的寄存器执行对应屏蔽线的置位
/* 清零上升沿选择对应中断线和下降沿选择对应中断线 */
EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line; //上升沿触发寄存器清零对应中断线
EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line; //下降沿触发寄存器清零对应中断线
/* 选择触发方式 */
if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling) //上升沿和下降沿同时触发
{
/* 设置上升沿触发对应中断线和下降沿触发对应中断线 */
EXTI->RTSR |= EXTI_InitStruct->EXTI_Line; //置位中断线对应的上升沿触发寄存器
EXTI->FTSR |= EXTI_InitStruct->EXTI_Line; //置位中断线对应的下降沿触发寄存器
}
else
{
tmp = (uint32_t)EXTI_BASE; //tmp赋值外部中断基地址
tmp += EXTI_InitStruct->EXTI_Trigger; //通过触发边沿选择上升沿触发寄存器还是下降沿触发寄存器
*(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line; //选择的边沿触进行使能
}
}
else //中断失能
{
tmp += EXTI_InitStruct->EXTI_Mode; //模式选择中断屏蔽寄存器或者事件屏蔽寄存器
*(__IO uint32_t *) tmp &= ~EXTI_InitStruct->EXTI_Line; //对应的中断线,1取反为0,与0进行清零
}
}
③中断标志获取和中断标志清零。操作IMR中断屏蔽、PR挂起。
标志获取EXTI_GetFlagStatus(),只需要操作PR即可。
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)
{
ITStatus bitstatus = RESET;
uint32_t enablestatus = 0;
/* 判断参数exti_line为中断线 */
assert_param(IS_GET_EXTI_LINE(EXTI_Line));
enablestatus = EXTI->IMR & EXTI_Line; //取中断线对应中断屏蔽位
//挂起寄存器置位和中断屏蔽位置位,则此中断使能
if (((EXTI->PR & EXTI_Line) != (uint32_t)RESET) && (enablestatus != (uint32_t)RESET))
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
{
/* 确定参数,exti_line为中断线 */
assert_param(IS_EXTI_LINE(EXTI_Line));
EXTI->PR = EXTI_Line; //挂起寄存器置位进行挂起寄存器的清零
}
5、外部中断实验操作。
①外部中断初始化函数。
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
KEY_Init(); //GPIO初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //外部中断需要使能AFIO时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2); //GPIOE.2外部中断
EXTI_InitStructure.EXTI_Line = EXTI_Line2; //中断线2
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //上升沿
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断使能
EXTI_Init(&EXTI_InitStructure); //外部中断参数初始化
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3); //GPIOE.3外部中断
EXTI_InitStructure.EXTI_Line = EXTI_Line3; //中断线3,其他参数同中断线2
EXTI_Init(&EXTI_InitStructure); //外部中断参数初始化
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4); //GPIOE.4外部中断
EXTI_InitStructure.EXTI_Line = EXTI_Line4; //中断线4,其他参数同中断线2
EXTI_Init(&EXTI_InitStructure); //外部中断参数初始化
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //GPIOA.0外部中断
EXTI_InitStructure.EXTI_Line = EXTI_Line0; //中断线0
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿,其他参数同中断线2
EXTI_Init(&EXTI_InitStructure); //外部中断参数初始化
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //外部中断0优先级设置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //外部中断2优先级设置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //外部中断3优先级设置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //外部中断4优先级设置
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
②中断处理函数。
//外部中断0服务函数
void EXTI0_IRQHandler(void)
{
delay_ms(10);
if(WK_UP==1) //WK_UP按下
{
BEEP = !BEEP;
}
EXTI_ClearITPendingBit(EXTI_Line0); //清零中断标志
}
//外部中断2服务函数
void EXTI2_IRQHandler(void)
{
delay_ms(10);
if(KEY2==0) //KEY2按下
{
LED0 = !LED0;
LED1 = !LED1;
}
EXTI_ClearITPendingBit(EXTI_Line2); //清零中断标志
}
//外部中断3服务函数
void EXTI3_IRQHandler(void)
{
delay_ms(10);
if(KEY1==0) //KEY1按下
{
LED1 = !LED1;
}
EXTI_ClearITPendingBit(EXTI_Line3); //清零中断标志
}
//外部中断4服务函数
void EXTI4_IRQHandler(void)
{
delay_ms(10);
if(KEY0==0) //KEY0按下
{
LED0 = !LED0;
}
EXTI_ClearITPendingBit(EXTI_Line4); //清零中断标志
}
③主函数。
int main()
{
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
BEEP_Init();
KEY_Init();
EXTIX_Init();
while(1)
{
printf("hello world!\r\n");
delay_ms(1000);
}
}