stm32定时器中断和外部中断

一,中断系统的介绍

中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得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线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_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线路的抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_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线路的抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_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.mzph.cn/bicheng/56113.shtml

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

相关文章

Github 优质项目推荐(第七期):涵盖免费服务、API、低代码、安卓root、深度学习

文章目录 Github优质项目推荐 - 第七期一、【LangGPT】,5.7k stars - 让每个人都成为提示专家二、【awesome-selfhosted】,198k stars - 免费软件网络服务和 Web 应用程序列表三、【public-apis】,315k stars - 免费 API四、【JeecgBoot】&am…

No.3 笔记 | Web安全基础:Web1.0 - 3.0 发展史

大家好!作为一个喜欢探索本质的INTP,我整理了一份简明易懂的Web安全笔记。希望能帮助你轻松掌握这个领域的核心知识。 这份笔记涵盖了Web发展的历程,从静态的Web 1.0到智能化的Web 3.0。我们将探讨URL和HTTP协议,揭示它们在网络中…

新书速览|你好,C++

《你好,C》 本书内容 《你好,C》主要介绍C开发环境的搭建、基础语法知识、面向对象编程思想以及标准模板库的应用,特别针对初学者在学习C过程中可能遇到的难点提供了解决方案。全书共分13章,以一个工资程序的不断优化和完善为线索…

Windows 下 cocos2d-x-3.17.2 VS2017开发环境搭建

1.下载cocos2d-x-3.17.2 源码: Cocos2d-x - 成熟、轻量、开放的跨平台解决方案 2.下载Python2 Python 2.7.0 Release | Python.org 加入环境变量: 测试版本

构建高效作业管理平台:Spring Boot师生协作评审系统

1系统概述 1.1 研究背景 如今互联网高速发展,网络遍布全球,通过互联网发布的消息能快而方便的传播到世界每个角落,并且互联网上能传播的信息也很广,比如文字、图片、声音、视频等。从而,这种种好处使得互联网成了信息传…

Zigbee2MQTT多控网关开发专题:【第一篇】系统配置与初始化

01 前言 本文章原文发表于我的微信公众号,请大家关注阅读,涉及的源代码等都在公众号,请搜索公众号: 智能家居NodeRed和HomeAssistant 即可关注。 02 概述 基于NodeRed的Zigbee2MQTT多功能多控网关开发专题正式开贴,…

Linux shellcheck工具

安装工具 通过linux yum源下载,可能因为yum源的问题找不到软件包,或者下载的软件包版本太旧。 ShellCheck的源代码托管在GitHub上(推荐下载方式): GitHub - koalaman/shellcheck: ShellCheck, a static analysis tool for shell scripts 对下…

VSCode搭建C/C++开发环境【Windows】

VSCode搭建C/C开发环境 1. 配置C/C开发环境1.1 下载和配置MinGW-w64编译器套件1.2 安装C/C插件 2. 在VSCode上编写C语言代码,并编译执行2.1 先打开一个文件夹,写一份C语言代码2.2 设置C/C编译的选项:c_cpp_properties.json2.3 创建执行任务&a…

Unity MVC框架1-2 实战分析

该课程资源来源于唐老狮,吃水不忘打井人,不胜感激 Unity MVC框架演示 1-1 理论分析-CSDN博客 首先你需要知道什么mvc框架,并且对三个层级有个比较清晰的认识,当然不清楚也好,下面例子中将会十分细心地让你理解&#x…

光控资本:牛市一般维持多长时间?牛市的轮涨顺序是什么?

牛市继续多长时间没有一个统一标准,我们是无法判断牛市什么时候到来,什么时候结束的。以A股牛市前史为例,继续时间从几十天到几年的情况都有,是没有规则可循的,现在A股继续最久的一次牛市是862天。 纵观A股前史&#…

【路径规划】创建末端执行器的路径,导入URDF模型,使用逆向运动学进行路径规划

摘要 本文通过路径规划为机器人末端执行器生成运动路径,采用URDF(Unified Robot Description Format)导入机器人模型,并结合逆向运动学进行路径规划和控制。使用Matlab进行建模和仿真,以确保执行器沿预定路径顺利运动…

API调用comfyui工作流,做一个自己的app,chatgpt给我写的前端,一键创建自己的卡通形象,附源码

前言 工具介绍 首先 comfyui你是少不了的,这个是工作流的后端支持,用这个去调试工作流和生成API可调用文件 前端我们就用很流行的gradio吧,什么你一时半会没有学gradio的计划,没事,笔者也没系统学过,我干…

Ubuntu18.04安装cuda11.1(出现c++版本问题)

一、概述 需要使用到ubuntu18.04进行cuda的配置,最新版本的cuda跟pytorch的版本不太适配,所以为了能够复现,我选择了一些老版本的cuda11,其使用的范围更加广泛。将自己 二、具体操作 (一)安装流程 1.官网…

[Linux#62][TCP] 首位长度:封装与分用 | 序号:可靠性原理 | 滑动窗口:流量控制

目录 一. 认识TCP协议的报头 1.TCP头部格式 2. TCP协议的特点 二. TCP如何封装与分用 TCP 报文封装与解包 如何封装解包,如何分用 分离有效载荷 隐含问题:TCP 与 UDP 报头的区别 封装和解包的逆向过程 如何分用 TCP 报文 如何通过端口号找到绑…

帝国CMS系统开启https后,无法登陆后台的原因和解决方法

今天本地配置好了帝国CMS7.5,传去服务器后,使用http访问一切正常。但是当开启了https(SSL)后,后台竟然无法登陆进去了。 输入账号密码后,点击登陆,跳转到/e/admin/ecmsadmin.php就变成页面一片…

多线程会在一个事务里面吗?

目录 多线程会在一个事务里面吗? 多线程、数据库事务以及数据库连接之间的关系 Spring的事务管理​​​​​​​ 声明式事务Transactional的实现原理 声明式事务Transactional的失效场景 Transactional注解的方法不是public为什么会失效 Spring AOP的代理机制…

【C++】——继承(下)

【C】——继承(下) 5 继承与友元6 继承与静态成员7 多继承7.1 继承模型7.2 菱形继承的问题7.3 虚继承7.4 多继承中的指针偏移问题 8 组合与继承 5 继承与友元 友元关系不能被继承。即一个函数是父类的友元函数,但不是子类的友元函数。也就是说…

【C++】用红黑树模拟实现set与map

目录 一、红黑树的完善: 1、红黑树节点模版的修改: 2、仿函数在模拟实现中的应用: 3、新增迭代器: 4、红黑树中的迭代器实现: 二、set与map的模拟实现: 1、insert: 2、map的[ ]: 三、测…

HTML的介绍

HTML HTML是一种超文本标记语言,超文本是指,除了文本之外,还可能包含图片,音频,或者评注等的 文本形式,比文本强大,通过链接和交互方式来组织和呈现信息.标记语言是指,由标签构成的语言.HTML定义了多种不同的标签,用来表示不同的内容. 标签的介绍: 1.<h3> 三级 </h3&…

如何彻底掌握 JavaScript 23种设计模式

设计模式是解决特定问题的常用解决方案&#xff0c;它们可以帮助开发者编写更清晰、可维护、可扩展的代码。在 JavaScript 中&#xff0c;常见的设计模式可以分为三大类&#xff1a;创建型模式、结构型模式 和 行为型模式。本文将全面介绍 JavaScript 中常见的设计模式&#xf…