步进电机中断函数解释
STM32 motor111.c
中 HAL_TIM_PeriodElapsedCallback
函数逐行解释
下面我们对 STM32 项目中 motor111.c
文件里的 HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
函数进行逐行解析,帮助初学者理解每一行代码的作用。此函数是在定时器产生更新中断时被调用的回调函数,用于控制两个步进电机的运动。解析过程中,我们还将解释 TIM5 定时器的作用、如何判断哪个电机在运行、GPIO 如何驱动电机步进,以及 HAL_TIM_PWM_Stop
、HAL_TIM_Base_Stop_IT
的作用,最后说明整个流程在系统控制逻辑中的作用。
1. 每一行代码的含义
以下是 HAL_TIM_PeriodElapsedCallback
函数的代码,并在每行添加中文注释说明其含义:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if (htim->Instance == TIM5) { // 如果触发中断的定时器实例是 TIM5,则处理电机逻辑uint8_t needStop = 1; // 标志是否需要停止定时器,初始值为1(假设需要停止)// 处理电机0 (如X轴电机)if (motor0_Running && stepCount[0] < targetSteps[0]) {HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2); // 翻转PA2引脚电平(给电机0的步进引脚产生一个脉冲)stepCount[0]++; // 电机0的已执行步数加一needStop = 0; // 还有剩余步数,暂时不停止定时器} else if (motor0_Running) {HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3); // 停止TIM5通道3的PWM输出(停止电机0的脉冲信号)HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET); // 将PE5引脚置高(关闭电机0的使能或刹车信号)motor0_Running = 0; // 标记电机0已停止运行}// 处理电机1 (如Y轴电机)if (motor1_Running && stepCount[1] < targetSteps[1]) {HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_3); // 翻转PA3引脚电平(给电机1的步进引脚产生一个脉冲)stepCount[1]++; // 电机1的已执行步数加一needStop = 0; // 还有剩余步数,暂时不停止定时器} else if (motor1_Running) {HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL _4); // 停止TIM5通道4的PWM输出(停止电机1的脉冲信号)HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET); // 将PE3引脚置高(关闭电机1的使能或刹车信号)motor1_Running = 0; // 标记电机1已停止运行}// 如果两个电机都已停止运行,则停止定时器中断if (needStop) {HAL_TIM_Base_Stop_IT(&htim5); // 停止TIM5基础定时器及其中断触发}}
}
逐行说明:
-
第1行:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
定义了一个回调函数,当定时器更新事件发生时(定时器溢出或达到设定周期),HAL库会调用此函数。参数htim
指向触发这个中断的定时器句柄。 -
第2行:
if (htim->Instance == TIM5) {
检查触发该回调的定时器是否为 TIM5。如果是 TIM5 更新中断,才执行后续电机控制代码。这样可以防止其他定时器的中断误触发此段逻辑(因为 HAL 的这个回调对所有定时器通用,需要自行判断来源)。 -
第3行:
uint8_t needStop = 1;
定义并初始化一个 8 位无符号变量needStop
为 1。needStop
用作标志位,指示是否需要停止定时器。初始假定需要停止(置1),如果发现任一电机仍需继续运行,则会将其置0,表示不停止。 -
第5行(注释):
// 处理电机0 (如X轴电机)
这是一个注释,说明接下来要处理电机0的逻辑(假设电机0对应 X 轴)。 -
第6行:
if (motor0_Running && stepCount[0] < targetSteps[0]) {
判断条件:如果电机0的“运行标志”motor0_Running
为真(表示电机0目前设定为在运行状态),且电机0已走的步数stepCount[0]
小于目标步数targetSteps[0]
(还没走完设定的总步数),则进入该分支,执行电机0的步进操作。 -
第7行:
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);
使用 HAL 库提供的函数翻转(Toggle)GPIOA端口的2号引脚的电平状态。由于 PA2 引脚连接到电机0的步进脉冲控制信号,每次翻转该引脚电平就产生一个上升沿或下降沿的脉冲。这相当于给步进电机的驱动器发送一个脉冲信号,让电机转动 一步(步进电机每接收一个脉冲信号就转动一个固定角度或前进一步 (STM32之步进电机 - Sakura_Ji - 博客园))。 -
第8行:
stepCount[0]++;
将电机0的步进计数值加一。stepCount[0]
用于记录电机0已经执行了多少步,每产生一次脉冲就累加1。这样可以跟踪电机是否已经走到目标步数。 -
第9行:
needStop = 0;
将needStop
置为0,表示目前不应停止定时器。之所以设置为0,是因为在这个定时器中断周期内,发现电机0还有剩余步数要走(刚执行了一步且未达到目标),因此需要继续让定时器触发后续中断来完成剩下的步数。 -
第10行:
} else if (motor0_Running) {
如果上一条if
不满足,但是motor0_Running
为真(表示电机0标记为正在运行)——也就是说电机0 正在运行但已没有剩余步数需要执行 (stepCount[0]
已达到或超过targetSteps[0]
),则进入此分支。这种情况表示电机0的运动已经完成目标步数。 -
第11行:
HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3);
调用了 HAL 库函数停止 TIM5 定时器的通道3上的 PWM输出。根据代码逻辑,TIM5通道3被用于电机0的脉冲产生。因此这行代码停止电机0的PWM信号输出,不再发出步进脉冲。换句话说,停止对电机0继续发脉冲,让它停下。提示: 在
Start_Motors
函数中,曾经通过HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_3)
启动了 TIM5 通道3 的 PWM,用于电机0脉冲输出。这里对应地将其关闭。 -
第12行:
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_5, GPIO_PIN_SET);
将 GPIOE 端口的 5 号引脚拉高(设置为高电平)。从上文Start_Motors
函数可知,在启动电机时曾经把 PE5 拉低(RESET)以使能电机0驱动。因此推测 PE5 引脚可能是电机0驱动器的“使能”(Enable)控制或制动信号(比如一些驱动模块需要拉低使能引脚才能运行)。在完成运动后,将该引脚置高,意味着关闭电机0的驱动输出(禁用电机或上电刹车),确保电机停止转动或锁定。 -
第13行:
motor0_Running = 0;
将电机0的运行标志置0,表示电机0不再运行。这样做不仅在内部记录电机状态,也会被主循环察觉,用于后续逻辑(例如主程序可能正等待该标志变为0,以判断运动完成)。 -
第14行:
}
结束电机0的处理分支。 -
第16行(注释):
// 处理电机1 (如Y轴电机)
注释:说明下面的代码块是处理电机1的逻辑(假设电机1对应 Y 轴)。 -
第17行:
if (motor1_Running && stepCount[1] < targetSteps[1]) {
判断电机1是否需要执行一步:条件与电机0类似,如果电机1标记为正在运行且尚未完成目标步数 (stepCount[1] < targetSteps[1]
),则进入该分支。 -
第18行:
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_3);
翻转 GPIOA 端口3号引脚的电平。PA3 引脚连接电机1的步进控制信号,因此每次翻转 PA3 电平,会给电机1发送一个脉冲信号,让电机1前进一步。 -
第19行:
stepCount[1]++;
电机1的步数计数加一,记录已经执行了一个步进脉冲。 -
第20行:
needStop = 0;
将needStop
置0,表示由于电机1仍有未完成的步数,定时器不应停止,还需继续中断以完成后续步数。 -
第21行:
} else if (motor1_Running) {
如果电机1正在运行但已没有剩余步数需要走(即目标步数已达到),则进入此分支,执行电机1停止运行的收尾工作。 -
第22行:
HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_4);
停止 TIM5 定时器通道4的 PWM输出。TIM5通道4对应电机1的脉冲输出通道,所以这将停止电机1的步进脉冲信号,终止电机1的运动。 -
第23行:
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
将 GPIOE 端口3号引脚置高电平。类似电机0的情况,PE3 在启动时被拉低使能电机1驱动,在运动结束时拉高以关闭电机1驱动输出。 -
第24行:
motor1_Running = 0;
清零电机1的运行标志,表示电机1已停止运行。 -
第25行:
}
结束电机1处理的分支。 -
第27行:
if (needStop) {
检查needStop
标志。如果仍然为1,表示在此次中断处理中并没有执行任何一步(即两个电机都没有进入运行步进的分支)。换言之,要么两个电机都不需要再运行(都已完成目标步数或根本未启动),要么定时器在一个周期内没有检测到需要继续的步数。 -
第28行:
HAL_TIM_Base_Stop_IT(&htim5);
调用 HAL 函数停止 TIM5 基础定时器的运行,并关闭其更新中断 (_IT
表示中断模式下停止)。当needStop == 1
时意味着两个电机都已经停止,因此可以安全地停止定时器,不再产生中断。一旦停止TIM5,中断回调将不再被调用,电机控制循环结束。这样做也避免了 CPU 继续进入中断浪费资源。 -
第29行:
}
结束if (needStop)
分支。 -
第30行:
}
结束if (htim->Instance == TIM5)
主分支。至此,TIM5定时器中断的处理逻辑结束。如果有其他定时器使用了这个回调函数,它们将被忽略(因为不在 TIM5 分支内)。 -
第31行:
}
回调函数结束。
通过上述逐行解释,可以看出该回调函数的主要作用是在 TIM5 定时器中断时,为两个步进电机(电机0和电机1)生成步进脉冲并计数步数,当达到目标步数时停止相应电机的脉冲输出,并在两个电机都停止后停止定时器中断。
接下来,我们针对题目要求的具体问题进行说明和拓展。
2. TIM5 定时器的作用及为何用它触发中断
TIM5 定时器的作用: 在这个项目中,TIM5 被用作步进电机控制的基础定时器。它的主要作用是按照设定的时间间隔周期性地产生中断(更新事件),从而触发上面的回调函数。在每次中断中,系统对电机的步数进行更新和脉冲输出。这实现了对步进电机运动速度和步数的精确控制。通过调节 TIM5 的定时周期,可以控制步进电机脉冲的频率,从而控制电机的转速。
具体来说,TIM5 配合其 PWM 通道一起使用:在 Start_Motors
函数中,调用了 HAL_TIM_Base_Start_IT(&htim5)
开启 TIM5 的基础定时器中断,并通过 HAL_TIM_PWM_Start
启动 TIM5 的通道3和通道4 PWM输出。这样TIM5就开始按照预先配置的频率计数,并在每次计数周期溢出时(即达到自动重装值ARR)触发更新中断,由回调函数输出一步脉冲。
为什么使用 TIM5 来触发中断:
-
精确定时与稳定脉冲: 硬件定时器能够提供精确且稳定的定时基准,比纯软件延时可靠得多。TIM5 定时器触发中断的周期决定了步进脉冲的频率,从而决定电机转动速度。使用 TIM5 硬件定时,可以确保每一步的时间间隔均匀,一致地控制电机运动。
-
多通道支持双电机: TIM5 在许多 STM32 微控制器上是一个拥有多通道的通用定时器。例如在 STM32F4 系列中,TIM5 有4个通道(并且是32位定时器)。在本代码中利用了通道3和通道4分别输出两个电机的PWM脉冲,一个定时器同时管理两个电机的步进信号,保证两电机脉冲同步在同一个时基下。这对于需要协调运动的轴来说很方便(虽然本例中未实现插补算法,但共用一个定时源可简化控制)。
-
资源独立且优先级控制: 使用单独的TIM5定时器来控制电机,不会干扰主CPU执行其他任务。定时器中断可以设置优先级,确保电机控制的实时性。当TIM5中断触发时,由回调函数执行关键的步数更新和GPIO切换,而主循环可以并行处理其他逻辑或等待完成信号。
-
触发中断的原因: 总结来说,TIM5用于触发中断是为了在硬件定时的基础上执行电机步进控制代码。每次 TIM5 溢出产生中断,就相当于“时钟敲一下”,驱动电机前进一小步,并检查是否达到目标。相比在主循环中用延时或轮询产生脉冲,中断方式更加精准和高效。
简而言之,TIM5 定时器充当了电机的“节拍器”,每一次节拍(中断)让电机迈出一步,并最终在完成指定步数时停止节拍。
3. 如何判断哪个电机在运行
在该系统中,通过状态标志变量来判断电机的运行状态。具体而言,有两个全局变量:motor0_Running
和 motor1_Running
,分别对应电机0和电机1的运行状态。它们的用法如下:
-
在启动电机运动时,这两个标志会被置为1。例如,在
Start_Motors
函数中,启动双电机运动之前,代码执行:motor0_Running = 1; motor1_Running = 1;
这表示电机0和电机1的运行标志均被设为“正在运行”。 -
在
HAL_TIM_PeriodElapsedCallback
回调函数中,根据这些标志决定是否产生脉冲并执行步进。当motorX_Running
为真且步数未完成时,代码对相应电机执行HAL_GPIO_TogglePin
产生脉冲并累加步数(如代码第6-9行所示)。如果motorX_Running
为假,则意味着该电机当前没有运动需求,回调中也不会对其产生脉冲。 -
当电机完成其目标步数时(即
stepCount[x]
达到targetSteps[x]
),回调函数会执行对应的 “停止” 分支:调用HAL_TIM_PWM_Stop
停止PWM输出,拉高控制引脚,并将motorX_Running
标志置0。将标志清零表示该电机的运动已结束。 -
主程序或其他任务可以通过检查
motor0_Running
和motor1_Running
来判断电机是否还在运行。例如,在MovePathWithCenterReturn
等上层逻辑中,代码使用while (motor0_Running || motor1_Running);
来等待,直到两个电机的运行标志都变为0,才说明此次运动已经全部完成.
总结: 哪个电机在运行取决于对应的 motorX_Running
标志是否为1。标志为1表示电机正处于运动过程中;标志为0表示该电机已停止(要么尚未启动,要么已经完成运动)。此外,还可以结合步数计数判断:当 stepCount[x]
尚未达到 targetSteps[x]
时且 motorX_Running
为1,则该电机正在执行运动;一旦步数达到目标并标志被清零,即表示该电机运动结束。
4. GPIO 控制如何驱动步进电机
本项目中,步进电机采用脉冲+方向的控制方式,也就是常见的步进电机驱动控制:由一个引脚提供脉冲信号控制步进,另一个引脚提供方向信号控制电机转动方向。GPIO 的控制具体体现在以下方面:
-
方向控制(Direction): 在开始运动时,通过GPIO设置电机转动方向。代码中
Start_Motors
函数对几个引脚进行了初始化:HAL_GPIO_WritePin(GPIOE, GPIO_PIN_6, dirX ? GPIO_PIN_RESET : GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, dirY ? GPIO_PIN_SET : GPIO_PIN_RESET);
这里推测 GPIOE_Pin_6 控制电机0的方向、GPIOE_Pin_4 控制电机1的方向。
dirX
/dirY
是传入的方向参数,根据其值决定将方向引脚拉高还是拉低,从而设定电机朝正转或反转方向运动。在步进电机驱动器中,方向引脚电平高低通常对应顺时针或逆时针旋转。 -
步进脉冲控制(Step Pulse): 正是通过定时器中断里的 GPIO 翻转来实现的。比如电机0使用 PA2 引脚作为步进脉冲引脚,每次在中断中执行
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2)
就会使 PA2 从低电平变高,或从高电平变低。这个电平的跳变沿即构成了一个脉冲信号,被步进驱动器识别为一步指令。通常,步进驱动器会在检测到引脚从低->高的上升沿时让电机走一步(也有的驱动对下降沿敏感,但无论哪种,每次 Toggle 产生一个完整的脉冲周期)。因此每进入一次定时中断翻转引脚,电机就前进一“步距角”。正如步进电机的特性所述:每输入一个脉冲信号,电机转子就转过一个固定角度(前进一步) (STM32之步进电机 - Sakura_Ji - 博客园)。 -
使能控制(Enable/Disable): 从代码看,GPIOE_Pin_5 和 GPIOE_Pin_3 似乎用作电机驱动器的使能或相关控制信号。在启动电机时,这两个引脚被拉低 (
GPIO_PIN_RESET
),而在停止电机时被拉高 (GPIO_PIN_SET
) 来关闭驱动。许多步进电机驱动模块(如常见的TB6600、A4988模块)都有使能引脚使能(ENABLE)或睡眠引脚等,通常低电平激活驱动,高电平关闭输出。由此推断:- 当开始运动时,将使能引脚拉低,使能驱动器输出,使电机准备接收脉冲。
- 当运动结束或需要停机时,将使能引脚拉高,禁用驱动器输出,防止电机继续受到脉冲(也减少电机功耗或锁定位置)。
-
GPIO 引脚配置: 为了可靠驱动步进电机,这些引脚一般配置为输出模式,推挽输出,高速,以确保能够产生清晰的方波脉冲。另外,最好在硬件上这些引脚连接到驱动器时有共地,驱动器根据脉冲信号变化驱动电机线圈。
简要流程: 初始化时设定方向,引脚使能驱动器;运动过程中定时翻转步进引脚产生持续的脉冲序列;结束时停止脉冲并禁用驱动。GPIO 的这种控制方式实现了步进电机的典型开环控制:脉冲数决定转动角度,脉冲频率决定转动速度 (STM32之步进电机 - Sakura_Ji - 博客园)。整个过程中GPIO输出的高低电平序列就是电机动作的直接指令。
5. HAL_TIM_PWM_Stop
和 HAL_TIM_Base_Stop_IT
的作用
在代码中,我们看到了这两个停止函数:
-
HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
: 停止指定定时器通道的 PWM 输出。调用此函数会关闭对应通道的比较输出,使其不再产生PWM波形。在本项目中,TIM5的通道3和通道4被用于产生电机步进脉冲信号(对应PA2和PA3引脚)。当调用HAL_TIM_PWM_Stop(&htim5, TIM_CHANNEL_3)
时,通道3的PWM输出被关闭,不再自动翻转PA2引脚电平;同理,TIM_CHANNEL_4
停止后不再输出脉冲。作用: 终止特定电机的脉冲信号输出。从电机驱动的角度看,这意味着不再给该电机发送步进指令脉冲,电机将停止继续转动。值得注意的是,PWM输出停止后,如果需要的话,我们仍然可以通过软件手动控制GPIO引脚电平(正如代码中紧接着通过
HAL_GPIO_WritePin
拉高引脚来锁定电机状态)。HAL_TIM_PWM_Stop
单纯停止硬件定时器对引脚的控制。 -
HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim)
: 停止基础定时器的计数,并且停用其更新中断。当调用HAL_TIM_Base_Stop_IT(&htim5)
时,会停止 TIM5 定时器的运行,也就是停止计数。这样TIM5就不会再触发中断了(对应的HAL_TIM_PeriodElapsedCallback
不会再被调用)。作用: 在确定无需再产生任何步进脉冲时,关闭定时器以结束整个定时中断过程。停止定时器中断有助于节省CPU资源(不再无谓地进入中断处理),也表明当前一次运动控制流程正式结束。
结合本例,HAL_TIM_PWM_Stop
用于单个电机的停止,而 HAL_TIM_Base_Stop_IT
用于整个定时器的停止。当两个电机都已经达到目标步数时,needStop
仍为1,触发执行 HAL_TIM_Base_Stop_IT(&htim5)
,从而完全停止TIM5。这相当于:“两个电机都走完了,该停表了。” 如果只有一个电机走完,另一个还在跑,则仅停止走完的那一路PWM,定时器仍继续跑以服务另一个电机。
小结: HAL_TIM_PWM_Stop
针对定时器的某一通道关闭PWM信号输出;HAL_TIM_Base_Stop_IT
则关闭整个定时器和中断。当使用定时器+PWM组合控制电机时,经常会在任务完成时先停PWM再停定时器,确保不多发脉冲也不多占用中断。
6. 整体流程在系统控制逻辑中的作用
综合来看,这套基于 TIM5 定时器中断的电机控制流程在系统中扮演了步进运动控制核心逻辑的角色,确保电机按照指令完成指定的移动。下面从系统层面说明其工作流程及作用:
-
启动阶段: 上层代码(例如控制逻辑函数
MovePathWithCenterReturn
)在需要电机移动时会调用Start_Motors(stepsX, dirX, stepsY, dirY)
等函数,传入X、Y轴各自需要移动的步数和方向。Start_Motors
将目标步数保存到targetSteps[0/1]
,将已走步数stepCount[0/1]
清零,并设置方向引脚和使能引脚的初始状态,然后开启 TIM5 定时器中断和PWM输出 。这一步相当于发出了“让两个电机按照给定方向各走 N 步”的命令,并启动了驱动装置。 -
运行阶段: TIM5 定时器开始计时,并按照设定频率周期性中断。每一次 TIM5 更新中断都会调用电机控制回调
HAL_TIM_PeriodElapsedCallback
。在回调中,根据每个电机的运行标志和剩余步数:- 如果电机需要继续运行(标志为1且步数未完),就翻转对应步进引脚,产生一个脉冲,电机走一步,同时步数计数加一。
- 如果电机不需要再运行了(标志为1但步数已完),则停止其PWM输出、拉高停止引脚、清除运行标志。
- 如此循环,定时器持续触发中断,“喂”给电机一个接一个脉冲,两个电机各自推进各自的步数。当某个电机先完成目标时,其标志会被清零,但定时器不中止,另一个电机继续运行。
-
停止阶段: 当且仅当检测到两个电机都无需再运行时(即本次中断中没有任何一个电机产生脉冲,
needStop
保持为1),系统调用HAL_TIM_Base_Stop_IT
停止定时器。这终止了进一步的中断调用,意味着预定的运动已全部完成。此时两个电机的运行标志都已清零,上层代码通过检测这些标志即可知道运动结束。 -
后续处理: 主控制逻辑往往在发出运动命令后,会等待运动完成再进行下一步。例如代码里
while (motor0_Running || motor1_Running);
就是忙等待两个电机完成。完成后,主逻辑可能记录当前位置(如更新currentX
,currentY
)或者执行其他动作(如控制其它执行器)。整个过程保证了运动的确定性:不会多走少走步数,且结束时电机状态明确。
控制逻辑作用总结: 该流程相当于实现了一个定长步进运动控制器。上层只需指定方向和步数,启动运动后,底层通过定时器中断精确输出对应数量的脉冲给电机,达到步数后自动停止。一方面,它解放了主CPU(利用硬件定时+中断来产生精确定时脉冲,而非软件延时),另一方面,它确保了运动达到预期的位置:由于记录了 targetSteps
和逐步比较 stepCount
,不会遗漏或多发脉冲。通过标志变量的设置和清除,上层代码也能方便地与此异步过程交互(如等待完成或提前停止等)。
在整个系统中,这段控制逻辑扮演着驱动底层执行机构(步进电机)的任务调度者角色:依据目标,对电机发出一系列脉冲“指令”,严格按计划数量执行,然后在任务完成时善后(停止定时器、清标志)。对于双电机同时运动的情况,它还能基本同步地驱动两轴(在相同的时间基准下脉冲输出),满足简单的直线运动要求。总之,该流程保证了步进电机按指令运动到位,是运动控制系统可靠运行的关键。
相关文章:
步进电机中断函数解释
STM32 motor111.c 中 HAL_TIM_PeriodElapsedCallback 函数逐行解释 下面我们对 STM32 项目中 motor111.c 文件里的 HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 函数进行逐行解析,帮助初学者理解每一行代码的作用。此函数是在定时器产生更新中断时被调…...
多把锁以及线程死锁问题
在 Java 中,每一个对象都可以作为一把锁,synchronized 通过获取对象头中的锁标志位来实现同步。当一个线程获取到对象的锁后,其他线程就无法再获取该锁,只能等待获取到锁的线程释放锁之后才能继续执行被 synchronized 修饰的代码块…...
Vue 3 Element Plus 浏览器使用例子
Element Plus 是一个基于 Vue 3 的流行开源 UI 库,提供了一系列的组件,帮助开发者快速构建现代化的用户界面。它的设计简洁、现代,包含了许多可定制的组件,如按钮、表格、表单、对话框等,适合用于开发各种 Web 应用。 …...
NoxLucky:个性化动态桌面,打造独一无二的手机体验
在数字时代,手机桌面的个性化设置已经成为许多人表达自我和展示个性的重要方式。今天,我们要介绍的 NoxLucky,就是这样一款功能强大的动态桌面手机应用。它不仅提供了独家的动态壁纸素材库,还支持将抖音、INS等平台的短视频直接设…...
如何在WORD WPS中输入英语音标 批量给英语标注音标
在我国,英语的学习,已经是贯穿小学到大学的课程,英语学习,关键是听说读写,而听说读,都离不开一个字--音,这就涉及到了英语的音标了。音标(Phonetics)是表示单词发音的一种…...
RUST变量学习笔记
1,作用域概念 捕获环境 2,所有权概念 Rust则是通过所有权和借用来保证内存安全。很多人不理解为啥说Rust是内存安全的,其实就是在默认情况下,你是写不出内存不安全的代码的。 Rust的所有权并不难理解,它有且只有如下…...
n8n工作流自动化平台的实操:本地化高级部署
一、本地高级部署 1.下载 docker pull docker.n8n.io/n8nio/n8n 2.运行 docker volume create n8n_data docker run -dit --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n -e N8N_SECURE_COOKIEfalse -e N8N_RUNNERS_ENABLEDtrue -e N8N_ENFORCE_SETTINGS_FIL…...
【Ansible自动化运维实战:从Playbook到负载均衡指南】
本文是「VagrantVirtualBox虚拟化环境搭建」的续篇,深入探索Ansible在自动化运维中的核心应用: ✅ Ansible核心技能:Playbook编写、角色(Roles)模块化、标签(Tags)精准控制 ✅ 实战场景覆盖&a…...
数据赋能(210)——质量管理——可靠性原则
概述 数据可靠性原则确保数据的准确性、完整性、一致性和可信性,是决策和业务活动对数据质量的基本要求。在信息化和数字化快速发展的今天,数据已成为企业的重要资产,数据可靠性直接影响到企业的决策质量和业务活动效果。数据可靠性是数据质…...
二、机器学习中Python变量基础
二、Python变量基础 像C语言和Matlab一样,变量名由字母、数字、下划线组成(但不能以数字开头,字母区分大小写)变量名不能与内置的函数同名。 根据变量是否可以充当容器,将变量类型分为基本类型和高级类型。 基本变量…...
有机玻璃材质数据采集活性炭吸附气体中二氧化硫实验装置
JGQ112Ⅱ有机玻璃材质数据采集活性炭吸附气体中二氧化硫实验装置 一.实验目的 1.熟悉活性炭吸附剂的特性和在SO2气体净化方面的应用。 2.掌握活性炭吸附法的流程和实验过程中各参数的控制方法。 3.了解主要参数变化对吸附效率的影响。 4.掌握吸附等温线概念和测定方法。 二.技术…...
Javase 基础入门 —— 07 接口
本系列为笔者学习Javase的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员JavaAI智能辅助编程全套视频教程,java零基础入门到大牛一套通关》,章节分布参考视频教程,为同样学习Javase系列课程的同学们提供参考。 01 概述 接…...
LangChain:重构大语言模型应用开发的范式革命
2022年10月22日,Harrison Chase在GitHub上提交了名为LangChain的开源项目的第一个代码版本。这个看似普通的代码提交,却悄然开启了一场重塑大语言模型(LLM)应用开发范式的技术革命。彼时,距离ChatGPT引爆全球人工智能浪…...
【现代深度学习技术】现代循环神经网络04:双向循环神经网络
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上,结合当代大数据和大算力的发展而发展出来的。深度学习最重…...
重塑数学边界:人工智能如何引领数学研究的新纪元
目录 一、人工智能如何重新定义数学研究的边界 (一)数学与AI的关系:从基础理论到创新思维的回馈 (二)AI的创造力:突破传统推理的局限 (三)AI对数学研究的潜在贡献:创…...
链表的回文结构题解
首先阅读题目: 1.要保证是回文结构 2.他的时间复杂度为O(n)、空间复杂度为O(1) 给出思路: 1.首先利用一个函数找到中间节点 2.利用一个函数逆置中间节点往后的所有节点 3.现在有两个链表,第一个链表取头节点一直到中间节点、第二个链表取头结点到尾…...
xLua笔记
Generate Code干了什么 肉眼可见的,在Asset文件夹生成了XLua/Gen文件夹,里面有一些脚本。然后对加了[CSharpCallLua]的变量寻找引用,发现它被XLua/Gen/DelegatesGensBridge引用了。也可以在这里查哪些类型加了[CSharpCallLua]。 public over…...
【Hive入门】Hive与Spark SQL深度集成:通过Spark ThriftServer高效查询Hive表
目录 引言 1 Spark ThriftServer架构解析 1.1 核心组件与工作原理 1.2 与传统HiveServer2的对比 2 Spark ThriftServer部署指南 2.1 环境准备与启动流程 2.1.1 前置条件检查 2.1.2 服务启动流程 2.2 高可用部署方案 2.2.1 基于ZooKeeper的HA架构 3 性能优化实战 3.…...
快速掌握--cursor
Cursor - The AI Code Editor 官网下载安装 详细教程:cursor 下载安装使用(保姆教程)_cursor下载-CSDN博客 不知道为啥,第一次给我用的是繁体回答 然后改了一下询问方式 codebase就是告诉ai可以从整个项目中找答案࿰…...
Linux之基础开发工具(yum,vim,gcc,g++)
目录 一、软件包管理器 1.1、什么是软件包 1.2、yum具体操作 1.2.1、查看软件包 1.2.2、安装软件 1.2.3、卸载软件 1.2.4、安装源 二、编辑器vim 2.1、vim的基本概念 2.2、vim的基本操作 2.3、vim正常模式命令集 2.4、vim末行模式命令集 2.5、替换模式 2.6、视图…...
【计算机视觉】三维重建: OpenMVS:工业级多视图立体视觉重建框架
深度解析OpenMVS:工业级多视图立体视觉重建框架 技术架构与核心算法1. 系统架构设计2. 核心算法解析稠密点云重建表面重建网格优化 实战全流程指南环境配置硬件要求编译安装(Ubuntu) 数据处理流程输入准备(OpenMVG输出)…...
C++负载均衡远程调用学习之异步消息任务功能与连接属性
目录 1.LarV0.11-异步消息机制的event_loop增添属性分析 2.LARS 3.LarV0.11异步消息发送机制的实现及测试 4.LarV0.11异步消息任务机制bug修复和效果演示 5.LarV0.12链接参数属性的绑定 1.LarV0.11-异步消息机制的event_loop增添属性分析 ## 4) 事件触发event_loop …...
内存性能测试方法
写于 2022 年 6 月 24 日 内存性能测试方法 - Wesley’s Blog dd方法测试 cat proc/meminfo console:/ # cat proc/meminfo MemTotal: 3858576 kB MemFree: 675328 kB MemAvailable: 1142452 kB Buffers: 65280 kB Cached: 992252 …...
游戏引擎学习第256天:XBox 控制器卡顿和修复 GL Blit 伽玛问题
回顾并为今天定下基调 今天的主要任务是让我们的性能分析工具正常工作,因为昨天已经完成了结构性工作。现在,剩下的工作大部分应该是调试和美化。性能分析工具现在应该已经基本可用了。昨天我们在这个方面取得了很大的进展。 接下来,我们将…...
4.29-4.30 Maven+单元测试
单元测试: BeforeAll在所有的单元测试方法运行之前,运行一次。 AfterAll在所有单元测试方法运行之后,运行一次。 BeforeEach在每个单元测试方法运行之前,都会运行一次 AfterEach在每个单元测试方法运行之后,都会运行…...
Android 端如何监控 ANR、Crash、OOM 等严重问题
在移动互联网时代,Android 应用已经成为我们生活中不可或缺的一部分。从社交聊天到在线购物,从娱乐消遣到办公学习,几乎每个人的手机里都装满了各式各样的应用。然而,作为开发者,咱们得面对一个残酷的现实:…...
Spring Boot 微服务打包为 Docker 镜像并部署到镜像仓库实战案例
案例项目素材可以拉取我github上的: https://github.com/AcademicTECHNERD/SpringCoudEurekaDemo 下面的案例将把我的product-service(也就是提供者)打包为镜像 执行maven命令: mvn clean package -DskipTests在根目录加一个dock…...
springAop代理责任链模式源码解析
目录 两次匹配 Bean 后置处理器中的匹配 方法调用时的匹配 Bean后置处理器中Advisor匹配流程 方法调用时的匹配 Jdk cglib 小小总结 Advisor 收集与排序 责任链执行过程 两次匹配 Bean 后置处理器中的匹配 在 Bean 初始化过程中,Spring 会通过 Bean 后置…...
ElasticSearch深入解析(九):Object、Nested、Flattened类型
文章目录 一、Object 类型:默认的嵌套对象处理方式核心原理典型场景关键限制 二、Nested 类型:解决嵌套数组的关联查询核心原理典型场景使用示例注意事项 三、Join 类型:跨文档的父子关联核心原理典型场景使用示例注意事项 四、Flattened 类型…...
list的迭代器详讲
1.list的迭代器就是封装了节点指针的类 2.迭代器失效 迭代器失效即迭代器封装的节点指针无效 。因为 list 的底层结构为带头结点的双向循环链表 ,因此 在 list 中进行插入时是不会导致 list 的迭代 器失效的,只有在删除时才会失效,并且失效的…...
动态规划之多状态问题1
题目解析: 也就是给一个预约数组,选择一些数字,让其总和最大,但不能选择相邻的两个数字 算法原理: 依旧可以根据经验题目 以dp[i]位置结尾时,巴拉巴拉 根据题目要求补充完整,dp[i]ÿ…...
音视频开源项目列表
音视频开源项目列表 一、多媒体处理框架 通用音视频处理 FFmpeg - https://github.com/FFmpeg/FFmpeg 最强大的音视频处理工具库支持几乎所有格式的编解码提供命令行工具和开发库 GStreamer - https://gitlab.freedesktop.org/gstreamer/gstreamer 跨平台多媒体框架基于管道…...
论微服务架构及其应用
试题四 论微服务架构及其应用 微服务提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通。在微服务架构中,每个服务…...
Spring Cloud与Service Mesh集成:Istio服务网格实践
文章目录 引言一、Spring Cloud与Service Mesh概述二、Istio服务网格架构三、Spring Cloud与Istio集成的基础设施准备四、服务发现与负载均衡五、流量管理与弹性模式六、安全通信与认证授权七、可观测性集成八、配置管理集成总结 引言 微服务架构已成为现代分布式系统的主流设…...
Day109 | 灵神 | 148.排序链表 | 归并排序
Day109 | 灵神 | 148.排序链表 | 归并排序 148. 排序链表 - 力扣(LeetCode) 以下是灵神的题解,笔者认为这题只要可以看懂就好了 两种方法:分治和迭代 文章目录 Day109 | 灵神 | 148.排序链表 | 归并排序前置题目方法一&#x…...
[更新完毕]2025东三省C题深圳杯C题数学建模挑战赛数模思路代码文章教学: 分布式能源接入配电网的风险分析
完整内容请看文章最下面的推广群 分布式能源接入配电网的风险分析 摘要 随着可再生能源渗透率的不断提升,分布式光伏发电在配电网中的大规模接入给传统电力系统运行带来了新的挑战。光伏发电固有的间歇性和波动性特征,加之配电网拓扑结构的复杂性&…...
ActiveMQ 集群搭建与高可用方案设计(二)
五、高可用方案设计与优化 (一)Zookeeper 在 ActiveMQ 集群中的应用 作用:在 ActiveMQ 集群中,Zookeeper 扮演着至关重要的角色。它主要用于选举 Master 节点,通过其内部的选举机制,从众多的 ActiveMQ Br…...
多协议 Tracker 系统架构与传感融合实战 第六章 多传感器时钟同步与数据对齐
第六章 多传感器时钟同步与数据对齐 摘要 本章围绕多源传感融合系统中——尤其是 IMU 与 UWB——的时钟同步与数据对齐问题展开,系统介绍: 硬件时钟源类型及漂移特性 软件校准策略:NTP/PTP 与自定义心跳同步 多源时钟同步算法:两阶段对齐与漂移补偿 数据缓冲与双队列对齐架…...
【算法基础】插入排序算法 - JAVA
一、算法基础 1.1 什么是插入排序 插入排序是一种简单直观的排序算法,它的工作原理类似于我们打牌时整理手牌的过程。插入排序的核心思想是将数组分为已排序和未排序两部分,每次从未排序部分取出一个元素,插入到已排序部分的适当位置。 1.…...
#Paper Reading# DeepSeek-R1
论文题目: DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 论文地址: https://arxiv.org/pdf/2501.12948 论文发表于: arXiv 2025年1月 论文所属单位: DeepSeek 论文大体内容 本文提出DeepSeek-R1模型,主要是以DeepSeek-V3[…...
HTML与CSS实现风车旋转图形的代码技术详解
在前端开发中,HTML和CSS是构建网页的基础技术。通过巧妙运用HTML的结构搭建和CSS的样式控制,我们能够实现各种精美的视觉效果。本文将对一段实现旋转图形效果的HTML和CSS代码进行详细解读,剖析其中的技术要点。 一、运行效果 HTML与CSS实现风…...
AWS在跨境电商中的全场景实践与未来生态构建
AWS在跨境电商中的全场景实践与未来生态构建 一、核心应用场景与技术赋能 1. AI驱动运营效率革命 • 智能选品与市场分析:通过Amazon SageMaker机器学习平台,跨境电商企业可构建精准选品模型。陕西自贸试验区案例显示,AI对亚马逊等平台销…...
AWS云服务深度技术解析:架构设计与最佳实践
作为全球市场份额占比32%的云服务提供商(Synergy Research 2023数据),AWS的技术体系已成为企业级应用架构的标杆。本文将深入剖析AWS核心技术组件的实现原理,并附可落地的架构设计范式。 AWS云服务器:中国企业出海的“…...
130. 被围绕的区域
题目链接:130. 被围绕的区域 思路:使用两遍dfs,第一遍找到可以被替换区域的可进入点并记录,第二遍就从所有的可进入点入手遍历区域内所有点并替换。 这是我的思路,感觉还是挺新颖的(应该很少有人这样想我…...
【Linux】进程优先级与进程切换理解
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:Linux 目录 前言 一、进程优先级 1. 什么是进程优先级 2. 为什么有进程优先级 3. 进程优先级的作用 4. Linux进程优先级的本质 5. 修改进程优先级 二、进…...
数据分析与可视化实战:从鸢尾花到乳腺癌数据集
数据分析是现代数据科学中不可或缺的一部分,它帮助我们理解数据、发现模式并做出明智的决策。本文将分享两个实战案例:鸢尾花数据集分析和乳腺癌数据集预处理,展示如何使用Python进行数据探索和可视化。 鸢尾花数据集分析 数据加载与基本统…...
怎样提升社交机器人闲聊能力
怎样提升社交机器人闲聊能力 本文聚焦社交机器人闲聊能力,指出闲聊在社交中意义重大,当前大语言模型(LLMs)驱动社交机器人闲聊存在不足。通过实验评估ChatGPT-3.5、Gemini Pro和LLaMA-2等LLMs闲聊表现,发现其与人类闲聊存在差异。 为此提出基于观察者模型的反馈重定向方…...
图论之幻想迷宫
题目描述: 幻象迷宫可以认为是无限大的,不过它由若干个 NM 的矩阵重复组成。矩阵中有的地方是道路,用 . 表示;有的地方是墙,用 # 表示。LHX 和 WD 所在的位置用 S 表示。也就是对于迷宫中的一个点(x,y),如…...
数学实验Matlab
一、Matlab语言环境和线性代数实验 1.Matlab语言环境 Matlab简介 Matlab:Matrix Laboratry 矩阵实验室 Matlab 提供了强大的科学计算、灵活的程序设计流程、高质量的图形可视化与界面设计等功能,被广泛应用于科学计算、控制系统、信息处理等领域的分…...
AI日报 · 2025年5月03日|Perplexity 集成 WhatsApp,苹果传与 Anthropic 合作开发 Xcode
1、Perplexity AI 功能更新:新增 WhatsApp 集成与多项优化 Perplexity 于 5 月 2 日发布其每周更新摘要,重点包括新增 WhatsApp 集成,用户现可直接在 WhatsApp 内与 Perplexity AI 交互,显著提升了信息获取的便捷性 [1]。此次更新…...