外部中断适用场景:突发事件及一旦发生急需处理事件(如红外遥控,不及时处理容易丢失数据)
中断程序执行时间应尽量短:中断程序是打断主程序后执行,如果中断程序执行时间过长会对被打断的代码造成较大影响,因此中断程序执行时间越短越好。
中断程序与主程序应尽量避免使用同一个函数或外设避免造成冲突。
中断管家:
使用NVIC统一管理中 断,每个中断通道都拥有16个可编程的优 先等级可对优先级进行分组,进一步设 置抢占优先级和响应优先级。
相同的pin不能同时触发中断:GPIOA与GPIOB的相同引脚不能同时触发中断。
事件触发:引脚电平触发时,选择触发事件。用于控制其他外设而不进入中断。
• 在STM32中,AFIO主要完成 两个任务:复用功能引脚重 映射、中断引脚选择。此处完成中断引脚选择。
外部中断配置流程:
• 配置外设时钟。EXTI与NVIC(内核外设)时钟默认打开。
• 配置GPIOx,
•配置AFIO,选择中断引脚。
•配置EXTI,选择中断线路,中断方式(事件,中断),有效触发边沿。
• 配置NVIC,选择分组方式,中断通道,抢占优先级和响应优先级。
对射式红外传感器:感应部件受遮挡及遮挡消失,引脚电平会发生变化。
#include "stm32f10x.h" // Device header
uint16_t CountSensor_Count;
/**
* 函 数:对射式红外传感器初始化
* 参 数:无
* 返 回 值:无
*/
void CounterSensot_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//打开PIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//打开AFIO时钟
//EXYI与NVIC(内核外设)时钟默认开启
GPIO_InitTypeDef GPIO_InitStructure;//配置GPIO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//上拉输入
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14;//使用14号引脚
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//IO口翻转速度
GPIO_Init(GPIOB,&GPIO_InitStructure);//读取结构体数值
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);//配置AFIC,选择GPIOB14号引脚作为中断源
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line14;//选择14号中段线路
EXTI_InitStructure.EXTI_LineCmd=ENABLE;//使能
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//选择中断触发
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
EXTI_Init(&EXTI_InitStructure);//读取结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//指定分组方式
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;//指定通道10-15
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//指定抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//指定响应优先级
NVIC_Init(&NVIC_InitStructure);//读取结构体
}
/**
* 函 数:返回传感器计数值
* 参 数:无
* 返 回 值:CountSensor_Count
*/
uint16_t Get_CountSensor_Count(void)
{
return CountSensor_Count;
}
/**
* 函 数:中断函数,每遮挡一次传感器,计数加1
* 参 数:无
* 返 回 值:无
*/
void EXTI15_10_IRQHandler(void)
{
//触发中断才能进来中断函数,为什么还要进行标志位的判断
if(EXTI_GetITStatus(EXTI_Line14))//通过标志位判断是否触发中断
{
CountSensor_Count++;//计数加1
EXTI_ClearITPendingBit(EXTI_Line14);//清除标志位
}
}
由于旋转方向不同,两个开关的导通时间不同,A,B处的电压波形便会产生一定的相位差,通过分析波形可判断旋转方向。
旋转编码器计数:
#include "stm32f10x.h" // Device header
uint16_t Encoder_Count;
/**
* 函 数:旋转编码器初始化
* 参 数:无
* 返 回 值:无
*/
void CounterSensot_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//打开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//打开时钟
//EXYI与NVIC(内核外设)时钟默认开启
GPIO_InitTypeDef GPIO_InitStructure;//配置GPIO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);//配置AFIC
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);//配置AFIC
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line0|EXTI_Line1;//选择0和1号中断线
EXTI_InitStructure.EXTI_LineCmd=ENABLE;//使能
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断触发
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
EXTI_Init(&EXTI_InitStructure);//读取结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;//指定通道
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//指定抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//指定响应优先级
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;//指定通道
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//指定抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//指定响应优先级
NVIC_Init(&NVIC_InitStructure);
}
/**
* 函 数:获取计数值
* 参 数:无
* 返 回 值:编码器计数值
*/
int16_t Get_Encoder_Count(void)
{
uint16_t Temp;
Temp=Encoder_Count;
Encoder_Count=0;
return Temp;
}
/**
* 函 数:0号中断函数
* 参 数:无
* 返 回 值:无
*/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)==SET)//到达下降沿
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)//旋转到位
{
Encoder_Count--;
}
EXTI_ClearFlag(EXTI_Line0);//清楚标志位
}
}
/**
* 函 数:1号中断函数
* 参 数:无
* 返 回 值:无
*/
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1)==SET)//下降沿触发
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)//旋转到位
{
Encoder_Count++;
}
EXTI_ClearFlag(EXTI_Line1);//清除标志位
}
}