首页 > 其他分享 >【江协STM32】6-1/2 TIM定时中断、定时器定时中断&定时器外部时钟

【江协STM32】6-1/2 TIM定时中断、定时器定时中断&定时器外部时钟

时间:2024-12-28 17:28:48浏览次数:5  
标签:TIM2 定时器 中断 NVIC TIM 定时 时钟

1. TIM定时中断

1.1 TIM简介

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

1.2 定时器类型

STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4

1.2.1 基本定时器

  • 内部时钟的来源是RCC_TIMxCLK,频率值一般都是系统的主频72MHz,所以通向时基单元的计数基准频率就是72MHz
  • 时基单元—预分频器(PSC):对72MHz的计数时钟进行预分频。
    实际分频系数 = 预分频器的值 + 1。比如预分频器写0,就表示不分频,或者说是1分频,输出频率=输入频率=72MHz;如果预分频器写1,就表示2分频,输出频率=输出频率/2=36MHz;如果预分频器写2,就表示3分频...
  • 时基单元—计数器(CNT):对预分频后的计数时钟进行计数。计数时钟每来一个上升沿,计数器的值就加1。计数器是16位的,所以里面的值可以从0一直加到65535。计数器的值在计时过程中会不断地自增运行,当自增运行到目标值时,产生中断,那就完成了定时的任务
  • 时基单元—自动重装寄存器(ARR):保存计数目标。16位
  • 框图右下角向上的折线箭头UI,代表这里会产生中断信号。由计数值等于自动重装值产生的中断,称为更新中断。这个更新中断之后就会通往NVIC。
  • 框图右下角向下的拆线箭头U,代表这里会产生一个事件。由计数值等于自动重装值产生的事件,称为更新事件。更新事件不会触发中断,但可以触发内部其他电路的工作。
  • 主模式触发DAC:使用DAC时,可能会用DAC输出一段波形,这就需要每隔一段时间来触发一次DAC,使其输出下一个电压点。如果用正常思路来实现,就是先设置一个定时器产生中断,每隔一段时间在中断程序中调用代码手动触发一次DAC转换,然后DAC输出。这种思路没有问题,但是这样会使主程序处于频繁被中断的状态,影响主程序的运行和其他中断的响应,所以定时器就设计了一个主模式,使用这个主模式可以把这个定时器的更新事件映射到触发输出TRGO(Trigger Out)的位置,然后TRGO直接接到DAC的触发转换引脚上,这样定时器的更新就不需要再通过中断来触发DAC转换了。整个过程不需要软件的参与,实现了硬件的自动化,这就是主模式的作用。
  • 计数模式为向上计数,也就是计数器从0开始,向上自增,计到重装值,清零同时申请中断。然后开始下一轮,依次循环。

1.2.2 通用定时器

通用定时器的计数模式:

  • 支持的计数模式有向上计数模式、向下计数模式和中央对齐模式。
  • 向下计数模式就是从重装值开始,向下自减,减到0之后,回到重装值同时申请中断。然后继续下一轮,依次循环。
  • 中央对齐模式就是从0开始,先向上自增,计到重装值,申请中断,然后再向下自减,减到0,再申请中断。然后继续下一轮,依次循环。

通用定时器的时钟源:

  • 时钟来源不仅有内部时钟(系统频率72MHz),还可以选择外部时钟。
  • TIMx_ETR引脚上的外部时钟:可以在TIM2的ETR引脚,也就是PA0上接一个外部方波时钟。然后配置一下内部的极性选择、边沿检测和预分频器电路,再配置一下输入滤波电路,这两块电路可以对外部时钟进行一定的整形,因为是外部引脚的时钟,所以存在毛刺,这此电路就可以对输入的波形进行滤波。最后,滤波后的信号分两路。
    上面一路ETRF进入触发控制器,紧跟着就可以选择作为时基单元的时钟了。如果你想在ETR外部引脚提供时钟,或者想对ETR时钟进行计数,把这个定时器当计数器来用的话,那就可以配置这一路的电路,在STM32中,这一路也叫做“外部时钟模式2”。
    下面一路也可以提供时钟,就是TRGI(Trigger In),它主要是用作触发输入来使用的,触发输入可以触发定时器的从模式。本小节讲的是触发输入作为外部时钟来使用的情况,暂且可以把TRGI当做外部时钟的输入来看。当这个TRGI当做外部时钟来使用的时候,这一路就叫做“外部时钟模式1”。
    通过下面一路的外部时钟有,第一,ETR引脚信号,ETR引脚既可以通过上面一路进入作为时钟,又可以通过下面一路进入作为时钟,这两种情况对于时钟输入而言是等价的,只不过下面一路的输入会占用触发输入的通道;第二,ITR信号,这一部分的时钟信号来自其他定时器,从右边可以看出,主模式的输出TRGO可以通向其他定时器,通向其他定时器的时候,就接到了其他定时器的ITR引脚上来了。ITR0到ITR3分别来自其他4个定时器的TRGO输出,具体连接方式如下表。通过这一路可以实现定时器级联的功能。比如可以先初始化TIM3,然后使用主模式把它的更新事件映射到TRGO上,接着再初始化TIM2,选择ITR2,对应的就是TIM3的TRGO,然后再选择时钟为外部时钟模式1,这样TIM3的更新事件就可以驱动TIM2的时基单元,也就实现了定时器的级联。
  • TI1F_ED:接连输入捕获单元的CH1引脚,也就是从CH1引脚的边沿获得时钟,后缀ED(Edge)是边沿的意思。通过这一路输入的时钟,上升沿和下降沿均有效。
  • TI1FP1TI1FP2:TI1FP1连接到了CH1引脚的时钟,TI1FP2连接到了CH2引脚的时钟。
  • 总结一下,外部时钟模式1的输入可以是ETR引脚、其他定时器、CH1引脚的边沿、CH1引脚和CH2引脚。

编码器接口:可以读取正交编码器的输出波形。

输出比较电路:右下角,从“捕获/比较1寄存器”到“TIMx_CH4”的矩形区域。总共有四个通道,可以用于输出PWM波形,驱动电机。

输入捕获电路:左下角,从“TIMx_CH1”到“捕获/比较4寄存器”的矩形区域。总共有四个通道,可以用于测量输入方波的频率等。

捕获/比较寄存器:输入捕获和输出比较电路共用。因为输入捕获和输出比较不能同时使用,所以这里寄存器是共用的,引脚也是共用的。

ITR和定时器的连接关系
(例:TIM2的ITR0是接在了TIM1的TRGO上的)

1.2.3 高级定时器

支持的计数模式有向上计数模式、向下计数模式和中央对齐模式。

重复次数计数器:可以实现每隔几个计数周期,才发生一次更新事件和更新中断

DTG:死区生成电路,右边的输出引脚,由一个变为了两个互补的输出,可以输出一对互补的PWM波。这些电路主要是为了驱动三相无刷电机的。为了防止互补输出的PWM驱动桥臂时,在开关切换的瞬间,由于器件的不理想,造成短暂的直通现象,所以在前面加上了死区生成电路。在开关切换的瞬间,产生一定时长的死区,让桥臂的上下管全都关断,防止直通现象。第四路输出没有DTG,因为三相电机只需要三路就可以了。

刹车输入:左下角,给电机驱动提供安全保障。如果外部引脚TIMx_BKIN产生了刹车信号,或者内部时钟失效产生了故障,那么控制电路就会自动切断电机的输出,防止意外的发生。

 1.3 定时中断基本结构

1.4 时序图

1.4.1 预分频器时序 

  • CK_PSC:预分频器的输入时钟
  • CNT_EN:计数器使能,高电平计数器正常运行,低电平计数器停止
  • CK_CNT:计数器时钟,它既是预分频器的时钟输出,也是计数器的时钟输入

计数器计数频率:CK_CNT = CK_PSC / (PSC + 1) 

1.4.2 计数器时序

计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
                                                    = CK_PSC / (PSC + 1) / (ARR + 1)

1.4.2.1 计数器无预装时序

就是没有缓冲寄存器的情况。通过设置ARPE位,可以选择是否使用预装功能。

计数器正在计数,突然更改了自动重装寄存器,由FF改成了36,那计数值的目标就由FF变成了36,所以计数器寄存器计到36之后,就直接更新,开始下一轮计数。

1.4.2.2 计数器有预装时序

就是有缓冲寄存器的情况。

在计数的中途,突然把计数目标由F5改成了36,但影子寄存器还是F5,所以现在计数的目标还是计到F5产生更新事件,同时,要更改的36才被传递到影子寄存器,在下一个计数周期这个更改的36才有效。所以引入影子寄存器的目的是同步,就是让值的变化和更新事件同步发生,防止在运行途中更改造成错误。

如果不使用影子寄存器,F5改到36立刻生效,但此时计数器数值已经到了F1,已经超过36了,F1只能增加到FFFF,再回到0,再加到36,才能产生更新。

1.5 RCC时钟树

STM32用来产生和配置时钟,并且把配置好的时钟发送到各个外设的系统。

程序中主函数之间会执行SystemInit函数,这个函数就是用来配置这个时钟树的。

中间AHB(不含)左边的都是时钟的产生电路,AHB(含)右边的都是时钟的分配电路。

在时钟产生电路,有四个震荡源,从上到下分别是内部的8MHz高速RC振荡器、外部的4-16MHz高速石英晶体振荡器(也就是晶振,一般接8MHz)、外部的32.768KHz低速晶振(一般给RTC提供时钟)、内部的40KHz低速RC振荡器(可以给看门狗提供时钟)。上面两个高速晶振是用来提供系统时钟的,AHB、APB2、APB1的时钟均来源于这两个高速晶振,外部的石英振荡器比内部的RC振荡器更加稳定,所以一般用外部晶振。

CSS:时钟安全系统,负责切换时钟。它可以监测外部时钟的运行状态,一旦外部时钟失效,它就会自动把外部时钟切换回内部时钟,保证系统时钟的运行,防止程序卡死。

2. 定时器定时中断

2.1 接线图

2.2 代码

初始化定时器的步骤:

  1. 初始化时钟RCC
  2. 选择时基单元的时钟源(对于定时中断,选择内部时钟源)
  3. 配置时基单元(包括PSC、CNT、ARR)
  4. 配置输出中断控制,允许更新中断输出到NVIC
  5. 配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
  6. 运行控制

     整个模块配置完成后,还需要使能一下计数器。当定时器使能后,计数器就会开始计数,当计数器更新时,触发中断。最后再写一个定时器的中断函数,这样中断函数每隔一段时间就能自动执行一次了。 

Timer.c

#include "stm32f10x.h"                  // Device header

//extern uint16_t Num;

void Timer_Init(void)
{
	//	1、初始化时钟RCC TIM2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//	TIM2是APB1总线的外设
	
	//	2、选择时基单元的时钟源
	TIM_InternalClockConfig(TIM2);//	因为定时器上电后默认就是使用内部时钟,所以此行可省略
	
	//	3、配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//	指定时钟分频,设置的是输入滤波的采样频率,与时基单元关系不大。这里随便选一个
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//	计数器模式,选择向上计数
	//	例如定时1s,计数器溢出频率:CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)=72M/(PSC+1)/(ARR+1)
	//	定时1s,也就是定时频率为1Hz。可以PSC给7200-1,ARR给10000-1
	//	注意:PSC和ARR的取值都要在0~65535之间
	TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//	自动重装器(ARR)的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;//	预分频器(PSC)的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//	重复计数器的值(高级定时器才有,不是CNT),不需要用,直接给0
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//	刚初始化完会生成一次更新事件,会使Num刚复位就显示1
	//	手动清除一次更新事件,避免Num从1开始
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);//	手动清除更新中断标志位,避免刚初始化完就进中断
	
	//	4、配置输出中断控制
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//	使能中断,选择更新中断
	
	//	5、配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//	抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//	响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	//	6、运行控制
	TIM_Cmd(TIM2, ENABLE);//	启动定时器
}

/*
//	定时器2中断函数
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//	检查中断标志位
	{
		//	主函数变量Num++。
		//	可以在本文档开头用extern;也可以直接将中断函数复制到主函数后面,Timer.c的中断函数需要注释掉。
		Num++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//	清除中断标志位
	}
}
*/

Timer.h

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

main.c

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

uint16_t Num;

//	每隔1s Num加1
int main(void)
{
		OLED_Init();
		Timer_Init();
		OLED_ShowString(1, 1, "Num:");
		OLED_ShowString(2, 1, "CNT:");
		while(1)
		{
				OLED_ShowNum(1, 5, Num, 5);
				OLED_ShowNum(2, 5, TIM_GetCounter(TIM2), 5);
		}
}

//	定时器2中断函数
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//	检查中断标志位
	{
		//	主函数变量Num++。
		//	可以在本文档开头用extern;也可以直接将中断函数复制到主函数后面,Timer.c的中断函数需要注释掉。
		Num++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//	清除中断标志位
	}
}

其他引用的头文件和c代码可在此处查阅:OLED.h(【江协STM32】4 OLED调试工具,第5节)、Delay.h(【江协STM32】3-2 LED闪烁&LED流水灯&蜂鸣器,第1.3节) 

3. 定时器外部时钟

3.1 接线图

3.2 代码 

与上一例代码基本相同,仅修改了Timer.c中的初始化时钟RCC、时基单元时钟源、ARR和PSC的取值,增加了GPIO初始化。

不需要使用内部时钟,修改初始化时钟第二步(选择时基单元的时钟源),改为通过ETR引脚的外部时钟模式2配置。

TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter)

  • 第一个参数是选择定时器,这里给TIM2。
  • 第二个参数是外部触发预分频器,这里不需要分频。
  • 第三个参数是外部触发的极性。TIM_ExtTRGPolarity_Inverted是反向,就是低电平或下降沿有效;TIM_ExtTRGPolarity_NonInverted是不反向,就是高电平或上升沿有效。
  • 第四个参数是外部触发滤波器,参数值为0x00~0x0F之间的一个值。就是以采样频率f采样N个点,如果N个点都一样,才会有效输出,这个值就是决定f和N的,具体对应关系如下图。
    (视频里写的0x00,但不滤波很容易造成在实际中挡一下光数跳好几次,所以这里改成了0x0f)

引脚要用到GPIO,所以配置时钟时还需要配置GPIO。

GPIO_Mode可以从“STM32F10xxx参考手册”中查询(8.1.11 外设的GPIO配置),推荐配置为浮空输入。但由于浮空输入电平会一直跳动,这里给上拉输入。浮空输入一般用于外部输入信号功率很小,内部如果有上拉电阻可能会影响到输入信号。

Timer.c

#include "stm32f10x.h"                  // Device header

//extern uint16_t Num;

void Timer_Init(void)
{
	//	1、初始化时钟RCC TIM2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//	TIM2是APB1总线的外设
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 配置GPIO
    //  初始化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(GPIOB, &GPIO_InitStructure);
	
	//	2、选择时基单元的时钟源
	TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0f);//	通过ETR引脚的外部时钟模式2配置
	
	//	3、配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//	指定时钟分频,设置的是输入滤波的采样频率,与时基单元关系不大。这里随便选一个
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//	计数器模式,选择向上计数
	//	计数器溢出频率:CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)=72M/(PSC+1)/(ARR+1)
	//	PSC给1-1,ARR给10-1,从0到9计数
	//	注意:PSC和ARR的取值都要在0~65535之间
	TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//	自动重装器(ARR)的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//	预分频器(PSC)的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//	重复计数器的值(高级定时器才有,不是CNT),不需要用,直接给0
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//	刚初始化完会生成一次更新事件,会使Num刚复位就显示1
	//	手动清除一次更新事件,避免Num从1开始
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);//	手动清除更新中断标志位,避免刚初始化完就进中断
	
	//	4、配置输出中断控制
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//	使能中断,选择更新中断
	
	//	5、配置NVIC
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//	抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//	响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	//	6、运行控制
	TIM_Cmd(TIM2, ENABLE);//	启动定时器
}

/*
//	定时器2中断函数
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//	检查中断标志位
	{
		//	主函数变量Num++。
		//	可以在本文档开头用extern;也可以直接将中断函数复制到主函数后面,Timer.c的中断函数需要注释掉。
		Num++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//	清除中断标志位
	}
}
*/

main.c

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

uint16_t Num;

//	遮光片挡一下,CNT加1(没有预分频。如果有预分频了,就是遮挡几次,才能增加一次)
//  加到9后,自动清零,同时申请中断,Num++
int main(void)
{
		OLED_Init();
		Timer_Init();
		OLED_ShowString(1, 1, "Num:");
		OLED_ShowString(2, 1, "CNT:");
		while(1)
		{
				OLED_ShowNum(1, 5, Num, 5);
				OLED_ShowNum(2, 5, TIM_GetCounter(TIM2), 5);
		}
}

//	定时器2中断函数
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)//	检查中断标志位
	{
		//	主函数变量Num++。
		//	可以在本文档开头用extern;也可以直接将中断函数复制到主函数后面,Timer.c的中断函数需要注释掉。
		Num++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//	清除中断标志位
	}
}

其他引用的头文件和c代码可在此处查阅:OLED.h(【江协STM32】4 OLED调试工具,第5节)、Delay.h(【江协STM32】3-2 LED闪烁&LED流水灯&蜂鸣器,第1.3节) 

标签:TIM2,定时器,中断,NVIC,TIM,定时,时钟
From: https://blog.csdn.net/qq_19395823/article/details/144678449

相关文章

  • 24.11.19 定时任务
    定时任务1、什么是定时任务? 闹钟/每天定时7点半8点 在固定的时间做什么事情2、定时任务作用 国定时间同步时间 数据备份(备份的服务器)重要的数据备份3份公司备份服务器笔记本移动硬盘网盘一份 先打包然后再备份(代码文件上百个上千个)占用磁盘io降低传输速度iin......
  • c# 实现一个简单的异常日志记录(异常迭代+分片+定时清理)+AOP Rougamo全局注入
    1.日志目录和文件管理日志目录:日志文件存储在./Exceptions目录下。日志文件命名:日志文件的命名格式为yyyy_MM_dd.log,表示当天的日期。如果当天的日志文件大小超过maxFileSizeBytes(3KB),则会创建新的日志文件,文件名格式为yyyy_MM_dd_P{cnt}.log,其中cnt是日志文件的编......
  • 如何中断事件的传播?
    在前端开发中,中断事件的传播通常涉及到阻止事件冒泡或取消事件的默认行为。以下是一些常见的方法和技巧来实现这一目标:使用event.stopPropagation()方法:当一个事件被触发时,它会在DOM树中逐级向上冒泡,直到达到最顶层的对象(通常是document对象)。stopPropagation()方法能够阻止......
  • 查询数据库开始时间和结束时间字段中包括了给定时间区间的数据
    表数据示例: 查询区间:2024-12-0310:00:00-2024-12-0618:00:00 mysql示例:SELECT*FROMtime_testWHERE((start_time>'2024-12-0310:00:00'AND('2024-12-0618:00:00'>end_timeOR('2024-12-0618:00:00'>start_time......
  • webflux版定时任务实现方案
    通常定时任务我们一般采用spring注解@EnableScheduling来启动,但如何与webflux响应式代码结合实现定时任务呢?下面给出了一个企业内使用的真实案例,希望能帮到你。@Component@EnableScheduling@Slf4jpublicclassTestTask{@ResourceprivateReactiveStringRedi......
  • C# 调用winmm.dll中的setTimeEvent来创建定时器,数量超过16次后出现异常
    在wpf项目中,为了使用毫秒级定时器,调用了windows提供的winmm.dll中的函数,成功实现了毫秒级定时器功能。但是用了一段时候后,在一个场景下,新建定时器超过16次后,程序抛出了异常。后来查询资料,发现该方法在一个进程内只允许创建最大16个定时器。由于这种场景较少,就没做修改。不过有......
  • 通过 PowerShell,你可以实现强大的安全监控和自动化响应。结合进程、模块、驱动程序、
    在PowerShell中,通过收集进程、模块和驱动程序信息,可以获取有关系统状态、潜在安全问题、恶意活动的指示等数据。这类信息对于安全防护、漏洞分析和系统审计非常重要。下面,我将详细说明如何通过PowerShell来收集这些数据,并加以分析。1. 收集进程信息进程是操作系统中运行的......
  • HAL库教程:串口+定时器接收不定长数据适用Modbus
    串口接收到的两组数据之间,通常会有一定的时间间隔。我们可以通过判断这个间隔来实现无结束符和无固定长度的串口数据接收功能。当串口在设定的时间内没有接收到新的数据时,认为一组数据已经接收完毕。在一些通信协议中,可能会指定数据之间的间隔时间。例如,Modbus协议要求两组数......
  • (九).NET6.0搭建基于Redis的Hangfire定时器
    1.首先创建新的类库项目Wsk.Core.Hangfire,然后在Wsk.Core.Package包项目下引用hangfire有关的组件,包括Hangfire、Hangfire.Core、Hangfire.Redis、Hangfire.Redis.StaskExchange2.在配置文件新增基于redis的hangfire的数据库连接3.在Wsk.Core.Hangfire项目下,新增Hangfire连......
  • (十).NET6.0 搭建基于Quartz组件的定时调度任务
    1.添加Quartz定时器组件2.新建类库项目Wsk.Core.QuartzNet,并且引用包类库项目。然后新建一个中间调度类,叫QuartzMiddleJob3.新建一个Job工厂类,叫YsqJobFactory,用来获取刚刚创建的中间调度类的服务4.新建一个通用执行计划类,叫YsqJobSchedule,用于每次任务都通过该计划进行......