stm32定时器中断和外部中断

news2024/11/25 16:56:56

一,中断系统的介绍

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

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

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回

中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设

使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级

具体串口通道需要查看手册

二,NVIC(嵌套中断向量控制器)

1,框架介绍

在stm32中,用来统一分配中断优先级和管理中断的

2,NVIC优先级分组

NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级

抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队

三,EXTI(外部中断)介绍

1,介绍

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

2,EXTI基本结构

3,EXTI框图

4,AFIO复用IO口

AFIO主要用于引脚复用功能的选择和重定义

在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择

5,库函数介绍

1,配置外部中断的流程:

  • 1,配置RCC,把涉及的外设时钟都打开
  • 2,配置GPIO,选择端口的输入模式
  • 3,配置AFIO
  • 4,配置EXTI,选择边沿的触发方式(比如:上升沿,下降沿或者双边沿),还有选择中断响应和事件响应
  • 5,配置NVIC,给中断选择一个合适的优先级,通过NVIC,外部中断信号就能进入CPU

2,中断初始化的配置示例

/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOB的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟,外部中断必须开启AFIO的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						//将PB14引脚初始化为上拉输入
	
	/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚
	
	/*EXTI初始化*/
	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);								//将结构体变量交给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 = EXTI15_10_IRQn;		//选择配置NVIC的EXTI15_10线
	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外设

 以下是外部中断的中断函数,相当于C51的外部中断服务号

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定时器介绍

1,定时器类型介绍

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

注意:每个不同单片机的型号是不同的,在使用某个外设之前,一定要查看一下是不是有这个外设 

2,基本定时器

  • 解释:
  • 首先,预分频器,计数器,自动重装载寄存器,它们三个构成了最基本的计数计时电路,这一块也成为时基单元
  •  基本定时器只能选择内部时钟,其中内部时钟的来源是RCC的TIMxCLK,这里的频率值一般都是系统的主频72MHz,所有通向时基单元的计数基准主频就是72MHz
  • 实际分频系数==预分频系数的值+1,其中这个预分频器是16位的,所有最大值可以写65535,也就是65536,就是对输入的基准频率提前进行一个分频的操作
  • 计数器可以对预分频后的计数时钟进行计数(比如计数时钟每来一个上升沿,计数器的值+1),计数器运行时会自增运行,当自增运行到目标值,产生中断,就完成了定时的任务
  • 自动重装载寄存器,就是写入一个计数目标,当计数器自增到该目标,就会产生中断信号,并且清零计数器,计数器自动开始下一次的计数计时。
  • 基本定时器仅支持向上计数

3,通用定时器框图

通用定时器和高级定时器支持向上计数,向下计数和中央对齐这三种模式 

通用定时器可以使用外部时钟(TIMx_ETR)

五,代码展示

1,定时器中断的基本结构

下面来看几个时序图,这对于代码的编写也十分重要

 

 

2,定时器定时中断代码

2.1 定时器初始化配置流程

  • 1,打开RCC开启时钟,定时器的基准时钟和整个外设的工作时钟都会被同时打开
  • 2,选择时基单元的时钟源,对于定时中断,我们选择内部时钟源
  • 3,配置时基单元,包括预分频器,自动重装器,计数模式等等,可以直接使用一个结构体来配置
  • 4,配置输出中断控制,允许更新中断输出到NVIC
  • 5,配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
  • 6,运行控制,整个模块配置完成后,需要驱动使能定时计数器
  • 当定时器使能之后,计数器开始计数,当计数器更新时,触发中断
  • 7,最后,我们再写一个定时器的中断函数,这样这个中断函数每隔一段时间就会自动执行一次了

2.2 定时器的相关库函数

2.2.1 定时器初始化相关函数
void TIM_DeInit(TIM_TypeDef* TIMx);//恢复缺省配置
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//时基单元初始化
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
void TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct);
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);
void TIM_BDTRStructInit(TIM_BDTRInitTypeDef* TIM_BDTRInitStruct);
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
void TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_EventSource);
void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength);
void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, FunctionalState NewState);
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
                                uint16_t TIM_ICPolarity, uint16_t ICFilter);

 2.2.2 定时器其他重要的相关函数
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//单独写预分频值的,
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);//自动重装器预装功能配置
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);//给计数值写值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);//给自动重装器写入一个值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);//返回当时计数器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);//返回当时预分频器的值
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//检查指定定时器(TIMx)的特定标志(TIM_FLAG)的状态。
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//作用:清除指定定时器(TIMx)的特定标志(TIM_FLAG)。
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);//检查指定定时器(TIMx)的特定中断(TIM_IT)的挂起状态。
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);//清除指定定时器(TIMx)的特定中断(TIM_IT)的挂起位。

2.3 定时器代码示例 

timer.c

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:定时中断初始化
  * 参    数:无
  * 返 回 值:无
  */
void Timer_Init(void)
{
	/*开启时钟*/
	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的值
	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,定时器开始运行
}

/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

 main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num;			//定义在定时器中断里自增的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Timer_Init();		//定时中断初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Num:");			//1行1列显示字符串Num:
	
	while (1)
	{
		OLED_ShowNum(1, 5, Num, 5);			//不断刷新显示Num变量
	}
}

/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		Num ++;												//Num变量自增,用于测试定时中断
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}

 3,定时器外部时钟

  • timer.c
#include "stm32f10x.h"                  // Device header

/**
  * 函    数:定时中断初始化
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数配置为外部时钟,定时器相当于计数器
  */
void Timer_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);						//将PA0引脚初始化为上拉输入
	
	/*外部时钟配置*/
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
																//选择外部时钟模式2,时钟从TIM_ETR引脚输入
																//注意TIM2的ETR引脚固定为PA0,无法随意更改
																//最后一个滤波器参数加到最大0x0F,可滤除时钟信号抖动
	
	/*时基单元初始化*/
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;					//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 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,定时器开始运行
}

/**
  * 函    数:返回定时器CNT的值
  * 参    数:无
  * 返 回 值:定时器CNT的值,范围:0~65535
  */
uint16_t Timer_GetCounter(void)
{
	return TIM_GetCounter(TIM2);	//返回定时器TIM2的CNT
}

/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
*/

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num;			//定义在定时器中断里自增的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Timer_Init();		//定时中断初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Num:");			//1行1列显示字符串Num:
	OLED_ShowString(2, 1, "CNT:");			//2行1列显示字符串CNT:
	
	while (1)
	{
		OLED_ShowNum(1, 5, Num, 5);			//不断刷新显示Num变量
		OLED_ShowNum(2, 5, Timer_GetCounter(), 5);		//不断刷新显示CNT的值
	}
}

/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)		//判断是否是TIM2的更新事件触发的中断
	{
		Num ++;												//Num变量自增,用于测试定时中断
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);			//清除TIM2更新事件的中断标志位
															//中断标志位必须清除
															//否则中断将连续不断地触发,导致主程序卡死
	}
}

四,总结

1,定时器定时中断

  • 触发来源:定时器定时中断是由STM32内部的定时器产生的。当定时器的计数值达到预设的重装载值时,定时器溢出并触发中断。

  • 应用场景:定时器定时中断常用于需要周期性执行的任务,如定时测量、延时控制、PWM输出等。它允许微控制器在固定的时间间隔执行特定的操作。

  • 功能特点

    • 可编程性:定时器的计数值和重装载值可以通过软件编程进行灵活设置,从而实现不同的定时周期。
    • 高精度:STM32的定时器通常具有较高的精度,能够满足对定时要求较高的应用场景。
    • 自动重装载:许多STM32定时器支持自动重装载功能,即在触发中断后自动将计数值重置为预设的重装载值,从而实现连续定时。

2,定时器外部中断

  • 触发来源:定时器外部中断通常指的是由外部事件(如外部输入引脚状态的变化)触发的中断,而不是由定时器本身产生的中断。这里的“定时器外部中断”可能是一个误导性的表述,因为标准的STM32外部中断是由外部中断/事件控制器(EXTI)管理的,而不是由定时器直接管理的。然而,为了回答这个问题,我们可以将其理解为一种通过定时器与外部事件结合来触发的中断机制(尽管这不是标准的STM32术语)。

  • 应用场景:定时器外部中断(如果理解为通过定时器与外部事件结合触发的中断)可能用于在特定时间窗口内检测外部事件,或者在外部事件发生时启动定时器以测量事件持续时间等。

  • 功能特点

    • 外部事件触发:与定时器定时中断不同,定时器外部中断的触发依赖于外部事件。
    • 时间窗口控制:通过结合定时器和外部中断,可以实现仅在特定时间窗口内响应外部事件的功能。
    • 灵活性:定时器和外部中断的结合使用提供了更高的灵活性,可以满足更复杂的定时和外部事件检测需求。

3,总结

  • 触发来源:定时器定时中断由定时器内部溢出触发,而定时器外部中断(如果理解为一种结合机制)则由外部事件触发。
  • 应用场景:定时器定时中断适用于周期性任务,而定时器外部中断(结合机制)适用于需要在特定时间窗口内检测外部事件的应用场景。
  • 功能特点:两者在可编程性、精度和灵活性方面各有优势,具体选择取决于应用需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

平衡二叉树——AVl树

AVL树 AVl树的概念AVL树的实现AVL树的结构AVl树的插入AVL树的旋转左单旋右单旋左右双旋右左双旋 AVl树以高度递归实现完整代码 AVl树的概念 AVL树是一种自平衡的二叉搜索树(Binary Search Tree, BST),由两位苏联数学家 Georgy Adelson-Velsk…

jQuery——事件处理

1、事件绑定(2种) ① eventName(function(){ }) 绑定对应事件名的监听,例如:$(‘#div’). click(function(){ }&#xf…

【复习】CSS中的选择器

文章目录 东西有点多 以实战为主选择器盒子模型 东西有点多 以实战为主 选择器 CSS选择器(CSS Selectors)是用于在HTML或XML文档中查找和选择元素,以便应用CSS样式的一种方式。 元素选择器(Type Selector) 选择所有…

在谷歌colab运行YOLO系列(重要比在云服务器搭建运行快)

在谷歌colab运行YOLO系列(重要比在云服务器搭建运行快) 一、谷歌云硬盘二、克隆 YOLOV5进行运行测试1,修改prepare文件中的参数2,修改voc.yaml3,修改yolov5s.yaml4,防止colab自动断开的方式(必须…

今日指数项目个股描述功能实现

个股描述功能实现 1 个股描述功能实现说明 1)原型示意 2)接口说明 功能描述:个股主营业务查询接口 服务路径:/api/quot/stock/describe 服务方法:GET 请求参数:code #股票编码 响应参数: {…

Koa2项目实战3 (koa-body,用于处理 HTTP 请求中的请求体)

以用户注册接口为例,需要在请求里携带2个参数:用户名(user_name)和密码(password)。 开发者需要在接口端,解析出user_name 、password。 在使用Koa开发的接口中,如何解析出请求携带…

八、Drf解析器

八、解析器 8.1概念 解析用户请求发送过来的数据(常用的是JSON) 请求类型: get: ​ 方式1: http://127.0.0.1/web/?arg1v1&arg2v2 ​ 方式2:通过请求头发送 post: ​ 请求头: ​ content-typ…

数据库管理-第247期 23ai:全球分布式数据库-Schema对象(20241004)

数据库管理247期 2024-10-04 数据库管理-第247期 23ai:全球分布式数据库-Schema对象(20241004)1 分区、表空间和Chunk(块)2 表空间组3 分片表4 分片表族5 复制表6 在所有分片上创建的非表对象总结 数据库管理-第247期 …

C++——模板进阶、继承

文章目录 一、模板1. 非类型模板参数2. 模板的特化函数模板特化类模板特化1. 全特化2. 偏特化部分特化参数更进一步的限制 二、继承1. 概念2. 定义定义格式 3. 继承基类成员访问⽅式的变化4. 继承类模板5.基类和派⽣类间的转换6. 继承中的作⽤域隐藏规则: 7. 派⽣类…

LinuxO(1)调度算法

概念 在Linux中,O(1)调度算法是一种进程调度算法。O(1)表示算法的时间复杂度是常数级别的,与系统中的进程数量无关。 运行队列结构 他采用了两个运行队列,一个活动队列和一个过期队列。活动队列中的进程是有资格获取CPU时间片的进程&#x…

阳台山足球营地的停车位探寻

阳台山足球营地的环境是真好哈。停车场名称:阳台山森林公园配套停车场。应该很多爬山的人车子也停在这里。而且我没想到的,阳台山的山泉水还有不少居民每天提着空桶去山上装。看来环境是真的很好哈 停车场有地面和地下停车场,停车位个数查不…

Linux驱动开发(速记版)--设备模型

第八十章 设备模型基本框架-kobject 和 kset 80.1 什么是设备模型 设备模型使Linux内核处理复杂设备更高效。 字符设备驱动适用于简单设备,但对于电源管理和热插拔,不够灵活。 设备模型允许开发人员以高级方式描述硬件及关系,提供API处理设备…

若依使用(二次开发)

RouYi-MT RouYi-MT下载: 下载地址 RouYi-MT的使用(修改若依代码中文件夹得统一包名) 将对应的Springboot文件压缩成压缩包。 填写对应的参数,生成修改后的文件。 开发步骤 1.创建子项目到RouYi-springboot中,添加…

简单易懂的springboot整合Camunda 7工作流入门教程

简单易懂的Spring Boot整合Camunda7入门教程 因为关于Spring Boot结合Camunda7的教程在网上比较少,而且很多都写得有点乱,很多概念写得太散乱,讲解不清晰,导致看不懂,本人通过研究学习之后就写出了这篇教学文档。 介…

我的创作纪念日一年

目录 机缘 收获 日常 成就 憧憬 机缘 我之所以开始写CSDN博客,源于一段特殊的时光。去年此时,我独自待在实验室,周围的世界仿佛与我无关。没有旅游,没有与朋友的欢聚,情感的挫折和学业的压力如潮水般袭来。在这样的…

2025舜宇招聘【内推码】

【2025内推码】 DSwNQ9yu DSJXN8Mr 舜宇集团2025届全球校园招聘正式启动!!! 专业需求:机械、自动化、电子、电气、通信、控制、测控、计算机、软件、物理、光学等专业; 工作地点:宁波余姚、浙江杭州、广东…

97. UE5 GAS RPG 实现闪电链技能(二)

书接上回,如果没有查看上一篇文章的同学推荐先看上一章,我们接着实现闪电链技能。 在上一章最后,我们实现了闪电链的第一条链,能够正确显示特效,接下来,我们先实现它的音效和一些bug修复。 我们在多端网络里…

(9)MATLAB瑞利衰落信道仿真2

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、瑞利衰落信道二、瑞利衰落信道建模三、仿真结果二、高斯随机变量和瑞利随机变量后续 前言 本文首先给出瑞利衰落信道模型,并根据瑞利衰落变量估…

乌班图基础设施安装之Mysql8.0+Redis6.X安装

简介:云服务器基础设施安装之 Mysql8.0Redis6.X 安装 Docker安装 # 按照依赖 yum install -y yum-utils device-mapper-persistent data lvm2 Docker Mirror 从去年开始. hub.docker.com[1] 在国内的访问速度极慢. 当时大家主要还是依赖国内的一些镜像源: 如中科…

【JNI】数组的基本使用

在上一期讲了基本类型的基本使用,这期来说一说数组的基本使用 HelloJNI.java:实现myArray函数,把一个整型数组转换为双精度型数组 public class HelloJNI { static {System.loadLibrary("hello"); }private native String HelloW…