深入理解嵌出式系统中的外部中断机制

中断:在主程序运行过程中,出现特定的中断触发条件也就是中断源,使得CPU暂停当前正在运行的程序转而去处理中断程序处理完成又返回执行原来被暂停的位置继续执行。

中断优先级:当多个中断源同时申请中断的时候,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源

中断嵌套:当一个中断程序正在执行,又有新的更高优先级的中断源申请中断,此时CPU再次暂停当前中断程序转而执行优先级更高的程序

EXTI外部中断
EXTI可以检测指定GPIO的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁定后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
支持的触发方式:上升沿/下降沿/双边沿/软件触发
支持的GPIO口:所有的GPIO口,但相同的PIN不能同时触发中断
通道数:16个GPIO_Pin 外加PVD输出,RTC时钟,USB唤醒 以太网唤醒
触发响应方式:中断响应/事件响应

中断主要应用于想要获取的是外部驱动的很快的突发信号

NVIC:嵌套中断向量控制器,是一个内核外设是CPU的小助手,负责分配和管理中断。

NVIC的中断优先级分组由优先级寄存器4位组成,这四位可以进行切分,分为高N位和低4-N位的响应优先级,抢占优先级高的可以嵌套中断,响应优先级高可以优先排队,抢占优先级和响应优先级相同的可以按中断号排队

AFIO主要用于引脚的复用功能的选择和重定义,在STM32中AFIO主要完成两个任务:复用功能引脚重映射,中断引脚的选择。

中断函数初始化代码

/*1.开启时钟
2.GPIO初始化
3.AFIO选择中断引脚
4.EXTI配置
5.NVIC配置*/

/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟

//内核外设不需要开启时钟,RCC的均需要开启时钟
/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	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);						//将PB0和PB1引脚初始化为上拉输入
	
	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//将外部中断的0号线映射到GPIOB,即选择PB0为外部中断引脚
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//将外部中断的1号线映射到GPIOB,即选择PB1为外部中断引脚
	
	/*EXTI初始化*/
	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);								//将结构体变量交给EXTI_Init,配置EXTI外设
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			//选择配置NVIC的EXTI0线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设

	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;			//选择配置NVIC的EXTI1线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;	//指定NVIC线路的抢占优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;			//指定NVIC线路的响应优先级为2
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设




/**
  * 函    数:EXTI15_10外部中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void EXTI15_10_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line14) == SET)		//判断是否是外部中断14号线触发的中断
	{
		/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
		{
			CountSensor_Count ++;					//计数值自增一次
		}
		EXTI_ClearITPendingBit(EXTI_Line14);		//清除外部中断14号线的中断标志位
													//中断标志位必须清除,为了跳出中断
													//否则中断将连续不断地触发,导致主程序卡死
	}
}

======中断函数的名字是固定的,为了避免写错应该去启动文件直接复制名字=======


========================
定时器本质上就是一个计数器
TIM定时器可以对输入的时钟进行计数,并在计数值达到设定值的时候触发中断。
16位计数器,预分频器,自动重装给=寄存器的时基单元,在72Mhz计数时钟下可以实现最大59.65s的定时
不仅具备基本的定时中断功能,而且还包含内外时钟源选择,输入捕获,输出比较,编码器接口。主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器,通用定时器,基本定时器三种类型

定时器基本功能,定一个时间,让定时器每隔一个时间产生中断,来实现每隔一个固定时间执行一段程序的目的,例如制作一个时钟,秒表,或者使用一些程序算法的时候

第二个功能定时器输出比较功能用于产生PWM波形,用于驱动电机设备

第三个定时器输入捕获的功能
第四个定时器的编码接口

通用定时器
STM32F103C8T6定时器资源:TIM1,TIM2,TIM3,TIM4
一个高级TIM1 三个通用定时器

高级定时器使用的是性能更高的APB2总线,用于通用定时器全部功能,并额外有重复计数器,死区生成,互补输出,刹车输入功能
通用定时器拥有基本定时器全部功能,并额外具有内外时钟源选择,输入捕获,输出比较,编码器接口,主从触发等模式
基本定时器:拥有定时中断,主从模式触发DAC功能

实际分频系数等于预分频器的值+1

	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;				//计数周期,即ARR的值 预分频和计数器周期都有一个1的偏差,因此需要减1
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	
	
	/*中断输出配置*/
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位
																//TIM_TimeBaseInit函数末尾,手动产生了更新事件
																//若不清除此标志位,则开启中断后,会立刻进入一次中断
																//如果不介意此问题,则不清除此标志位也可
	
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断
	
	/*NVIC中断分组*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2
																//即抢占优先级范围:0~3,响应优先级范围:0~3
																//此分组配置在整个工程中仅需调用一次
																//若有多个中断,可以把此代码放在main函数内,while循环之前
																//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
	
	/*NVIC配置*/
	NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1
	NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}
/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		Num ++;												//Num变量自增,用于测试定时中断
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}

浮空输入当外部输入信号的功率很小,内部的这个上拉电阻可能会影响到这个输入信号,这个时候就可以使用浮空输入,防止影响外部输入的电平。

OC输出比较
输出比较可以通过比较CNT与CCR寄存器的关系,来对输出电平进行置1,置0,或翻转的操作,用于输出一定频率和占空比的PWM波形,每个高级定时器和通用定时器都拥有四个输出比较通道,高级定时器的前三个通道额外拥有死区生成和互补输出功能

PWM:脉冲宽度调制
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,阿里等效获得所需要的模拟参量,常用于电机控速度等领域
PWM参数
频率 占空比 分辨率=占空比变化步距:占空比变化的细腻程度

直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作,TB6612是一款双路H桥的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向

作者:一只有情调猪

物联沃分享整理
物联沃-IOTWORD物联网 » 深入理解嵌出式系统中的外部中断机制

发表评论