从0开始的STM32 定时器(I):聊一聊基本定时器
目录
时钟源
控制器
时基单元
关于HAL库如何配置基本定时器
HAL是如何初始化我们的定时器句柄的
HAL_TIM_Base_Init
开始定时
如何处理句柄?
在我们使用STM32解决一些问题的时候,常常会遇到说:我想要以一个周期做一些事情:比如说周期性的向我的上位机发送当前的温度和湿度,比如说周期性的点亮一个LED,刷新一次LCD屏幕。这都离不开我们定时器的身影。STM32有2个基本定时器,4个通用定时器,2个高级定时器。我们慢慢来阐述不同种类的定时器的作用。现在,让我们从最基础的最简单的基本定时器开始!

学过数电的朋友一眼就能知道这个图怎么回事了:我们对来自RCC时钟的信号进行分频,当到打分频计数的时候向计数器发起一次脉冲,计数器接受到脉冲后会自增1,直到到达我们设定的阈值的时候发起一次中断通知定时器超时。这就是定时器的最基本的工作原理!
这样来看,定时器的核心就是计算器!就是打点计数,到点发起通知重置!他有三个要素组成:
时钟源
要实现计数功能,首先要给它一个时钟源。打点计时,还是需要水滴下来的!基本定时器时钟挂载在 APB1 总线,所以它的时钟来自于 APB1 总线,但是基本定时器时钟不是直接由 APB1 总线直接提供,而是先经过一个倍频器。当APB1 的预分频器系数为 1 时,这个倍频器系数为 1,即定时器的时钟频率等于 APB1 总线时钟频率;当 APB1 的预分频器系数≥2 分频时,这个倍频器系数就为 2 ,即定时器的时钟频率等于 APB1 总线时钟频率的两倍。
控制器
控制器除了控制定时器复位、使能、计数等功能之外,还可以用于触发DAC 转换。这个是我们的定时器可以被控制的根本。
时基单元
时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR) 。基本定时器的这三个寄存器都是 16 位有效数字,即可设置值范围是 0~65535。时基单元中的预分频器PSC,它有一个输入和一个输出。输入CK_PSC 来源于控制器部分,实际上就是来自于内部时钟(CK_INT),即2 倍的APB1 总线时钟频率(72MHz)。输出 CK_CNT是分频后的时钟,它是计数器实际的计数时钟,通过设置预分频器寄存器(TIMx_PSC)的值可以得到不同频率 CK_CNT,计算公式如下:
fCK_CNT= fCK_PSC / (PSC[15:0]+1)
上式中,PSC[15:0]是写入预分频器寄存器(TIMx_PSC)的值。
另外:预分频器寄存器(TIMx_PSC)可以在运行过程中修改它的数值,新的预分频数值将在下一个更新事件时起作用。因为更新事件发生时,会把 TIMx_PSC 寄存器值更新到其影子寄存器中,这才会起作用。
那什么是影子寄存器?从框图上看,可以看到图20.1.1.1中的预分频器PSC 后面有一个影子,自动重载寄存器也有个影子,这就表示这些寄存器有影子寄存器。影子寄存器是一个实际起作用的寄存器,不可直接访问。举个例子:我们可以把预分频系数写入预分频器寄存器(TIMx_PSC),但是预分频器寄存器只是起到缓存数据的作用,只有等到更新事件发生时,预分频器寄存器的值才会被自动写入其影子寄存器中,这时才真正起作用。 也就是说,我们不能直接暴力的打断当前的计数,采用缓存的办法下一次更新,这确保系统至少是稳定的工作的!
自动重载寄存器及其影子寄存器的作用和上述同理。不同点在于自动重载寄存器是否具有缓冲作用还受到 ARPE 位的控制,当该位置0 时,ARR 寄存器不进行缓冲,我们写入新的 ARR值时,该值会马上被写入 ARR 影子寄存器中,从而直接生效;当该位置 1 时,ARR 寄存器进行缓冲,我们写入新的 ARR 值时,该值不会马上被写入 ARR 影子寄存器中,而是要等到更新事件发生才会被写入 ARR 影子寄存器,这时才生效。预分频器寄存器则没有这样相关的控制位,这就是它们不同点。
值得注意的是,更新事件的产生有两种情况,一是由软件产生,将 TIMx_EGR 寄存器的位UG 置 1,产生更新事件后,硬件会自动将 UG 位清零。二是由硬件产生,满足以下条件即可:计数器的值等于自动重装载寄存器影子寄存器的值。
基本定时器的计数器(CNT)是一个递增的计数器,当寄存器(TIMx_CR1)的CEN 位置1,即使能定时器,每来一个 CK_CNT 脉冲,TIMx_CNT 的值就会递增加 1。当TIMx_CNT 值与 TIMx_ARR 的设定值相等时,TIMx_CNT 的值就会被自动清零并且会生成更新事件(如果开启相应的功能,就会产生 DMA 请求、产生中断信号或者触发 DAC 同步电路),然后下一个CK_CNT 脉冲到来,TIMx_CNT 的值就会递增加 1,如此循环。在此过程中,TIMx_CNT 等于TIMx_ARR 时,我们称之为定时器溢出,因为是递增计数,故而又称为定时器上溢。定时器溢出就伴随着更新事件的发生。
由上述可知,我们只要设置预分频寄存器和自动重载寄存器的值就可以控制定时器更新事件发生的时间。自动重载寄存器(TIMx_ARR)是用于存放一个与计数器作比较的值,当计数器的值等于自动重载寄存器的值时就会生成更新事件,硬件自动置位相关更新事件的标志位,如:更新中断标志位。
下面举个例子来学习如何设置预分频寄存器和自动重载寄存器的值来得到我们想要的定时器上溢事件发生的时间周期。比如我们需要一个500ms 周期的定时器更新中断,一般思路是先设置预分频寄存器,然后才是自动重载寄存器。
考虑到我们设置的 CK_INT 为72MHz,我们把预分频系数设置为 7200,即写入预分频寄存器的值为 7199,那么 fCK_CNT=72MHz/7200=10KHz。这样就得到计数器的计数频率为10KHz,即计数器 1 秒钟可以计 10000 个数。我们需要 500ms 的中断周期,所以我们让计数器计数 5000 个数就能满足要求,即需要设置自动重载寄存器的值为4999,另外还要把定时器更新中断使能位 UIE 置 1,CEN 位也要置 1。
关于HAL库如何配置基本定时器
下面给看官演示如何使用使用最基本的定时器完成定时触发任务:
首先,笔者现在用的STM32F103ZET6有两个基本的定时器TIM6和TIM7。笔者使用的是TIM6。现在,勾选Activate使能我们的定时器后,开始设置参数。
-
Prescaler是我们上面提到的预分频的意思:这里笔者的RCC时钟是72MHz,现在做分频笔者按照经典的方案:分7200份,也就是每一份实际上是10KHz
-
CounterMode:向上计数(如果只是定时无所谓)
-
Counter Period:自动重装载值,笔者打算1s触发一次事件,那就是让1s计数1次,即1HZ,需要填入10000 - 1 = 9999(Btw,不太理解为什么非得要填一个很小的值然后在程序里自己维护一个计数,我后来想了想,可能是同步的其他周期的任务计时更加方便)(后补:实际上就是更细粒度的维护
-
auto-reload preload:Disable的时候自动重装载寄存器写入新值后,计数器立即产生计数溢出,然后开始新的计数周期,也就是说,我们在Disable的时候马上修改我们在影子寄存器里的重载值,而在Enable的时候则是完成当前周期之后再将值写入影子寄存器里(多一个周期)

下面,我们就是使能一下我们的NVIC:

完成其他配置之后,我们就可以开始生成工程。值得注意的是,初始化结束我们的寄存器之后记得开启定时器计时(笑)
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim == &htim6){HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);}
}
/* USER CODE END 0 */
/*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */SystemClock_Config();
/* USER CODE BEGIN SysInit *//* USER CODE END SysInit */
/* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM6_Init();/* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(&htim6);/* USER CODE END 2 */
/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
回调事件请在HAL_TIM_PeriodElapsedCallback内完成。下面我们依次介绍HAL库的函数配置。
HAL是如何初始化我们的定时器句柄的
HAL库这样抽象一个定时器:
/*** @brief 初始化 TIM6 定时器。* @note 此函数初始化 TIM6 为基础计时器,设置了预分频器和计数周期,并配置了触发和同步模式。* @retval None*/
static void MX_TIM6_Init(void)
{/* USER CODE BEGIN TIM6_Init 0 */// 用户代码部分:可以在此处添加初始化之前的代码/* USER CODE END TIM6_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0}; // 定义主配置结构体,用于配置 TIM6 的主从同步模式
/* USER CODE BEGIN TIM6_Init 1 */// 用户代码部分:可以在此处添加初始化之后的代码/* USER CODE END TIM6_Init 1 */htim6.Instance = TIM6; // 指定 TIM6 外设实例
// 配置定时器参数htim6.Init.Prescaler = 7199; // 设置预分频器值为 7199。定时器计数频率为系统时钟频率 / (Prescaler + 1)htim6.Init.CounterMode = TIM_COUNTERMODE_UP; // 设置计数模式为向上计数模式htim6.Init.Period = 9999; // 设置定时器周期为 9999。定时器将在计数到达此值时溢出htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 禁用自动重载预加载功能
// 初始化定时器if (HAL_TIM_Base_Init(&htim6) != HAL_OK){Error_Handler(); // 如果定时器初始化失败,调用错误处理函数}
// 配置定时器主输出触发(TRGO)和主从同步模式sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; // 配置主输出触发为重置sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁用主从同步模式if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK){Error_Handler(); // 如果主从同步配置失败,调用错误处理函数}
/* USER CODE BEGIN TIM6_Init 2 */// 用户代码部分:可以在此处添加初始化后的代码/* USER CODE END TIM6_Init 2 */
}
按照流程,我们做了这一些事情:
配置好我们在CubeMx中设置的一系列的参数值。
使用
HAL_TIM_Base_Init(&htim6)函数用于初始化定时器的基本配置,包括预分频器、计数模式、周期等参数。如果初始化失败,程序将调用Error_Handler()进行错误处理。主从同步配置:
主输出触发(Master Output Trigger, TRGO):
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;设置定时器的主输出触发事件为重置信号。重置信号通常用于同步其他外设或触发其他操作。主从同步模式(Master Slave Mode):
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;禁用主从同步模式,这意味着 TIM6 不与其他定时器或外设同步工作。
HAL_TIM_Base_Init
这个是实际的IMPL函数:HAL_TIM_Base_Init 函数用于初始化一个基本定时器的配置。它检查传入的定时器句柄和配置信息是否有效,并根据用户的配置初始化相关硬件资源,包括定时器计数器、时钟和中断。
/*** @brief 初始化 TIM 基本定时器。* @param htim 指向一个 TIM_HandleTypeDef 结构体,该结构体包含了定时器的配置信息。* @retval HAL 状态码(HAL_OK 或 HAL_ERROR)*/
HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
{/* 检查 TIM 句柄是否有效 */if (htim == NULL){return HAL_ERROR; // 如果 TIM 句柄无效,返回错误}
/* 检查定时器配置参数是否有效 */assert_param(IS_TIM_INSTANCE(htim->Instance)); // 确保传入的定时器实例有效assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode)); // 确保计数模式有效assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision)); // 确保时钟分频配置有效assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload)); // 确保自动重载预加载配置有效
if (htim->State == HAL_TIM_STATE_RESET){/* 如果定时器处于重置状态,初始化定时器 */htim->Lock = HAL_UNLOCKED; // 解锁定时器资源
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)/* 如果启用回调函数注册功能,重置中断回调为默认的弱回调 */TIM_ResetCallback(htim);
if (htim->Base_MspInitCallback == NULL){/* 如果没有用户提供的回调函数,则使用默认的硬件初始化回调函数 */htim->Base_MspInitCallback = HAL_TIM_Base_MspInit;}/* 初始化低级硬件配置:GPIO、时钟、NVIC */htim->Base_MspInitCallback(htim);
#else/* 如果没有启用回调函数注册,直接调用默认的硬件初始化函数 */HAL_TIM_Base_MspInit(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */}
/* 设置定时器状态为忙碌 */htim->State = HAL_TIM_STATE_BUSY;
/* 设置定时器时间基准配置 */TIM_Base_SetConfig(htim->Instance, &htim->Init);
/* 初始化 DMA burst 操作状态 */htim->DMABurstState = HAL_DMA_BURST_STATE_READY;
/* 初始化 TIM 通道的状态 */TIM_CHANNEL_STATE_SET_ALL(htim, HAL_TIM_CHANNEL_STATE_READY); // 设置所有 TIM 通道为准备好状态TIM_CHANNEL_N_STATE_SET_ALL(htim, HAL_TIM_CHANNEL_STATE_READY); // 设置所有通道的N状态为准备好
/* 设置定时器状态为就绪 */htim->State = HAL_TIM_STATE_READY;
return HAL_OK; // 返回初始化成功
}
函数的中间部分是参数验证:
-
assert_param(IS_TIM_INSTANCE(htim->Instance)):确保定时器实例(如TIM1,TIM2等)有效。 -
assert_param(IS_TIM_COUNTER_MODE(htim->Init.CounterMode)):确保计数模式有效,如向上计数、向下计数或其它模式。 -
assert_param(IS_TIM_CLOCKDIVISION_DIV(htim->Init.ClockDivision)):检查时钟分频配置是否有效。 -
assert_param(IS_TIM_AUTORELOAD_PRELOAD(htim->Init.AutoReloadPreload)):检查自动重载预加载配置是否有效。
检查完毕,如果定时器的状态为 HAL_TIM_STATE_RESET(即未初始化或重置状态),则执行硬件资源的分配和初始化。此时,定时器的 Lock 锁定状态设置为解锁,准备进一步的配置。
-
如果启用了回调函数注册功能(通过宏
USE_HAL_TIM_REGISTER_CALLBACKS),则重置回调函数为默认的弱回调。 -
如果没有提供用户自定义的回调函数,则使用默认的初始化回调
HAL_TIM_Base_MspInit,进行定时器的低级硬件初始化。硬件初始化通常包括时钟、GPIO 和 NVIC(中断控制器)的配置。
设置定时器配置: 调用 TIM_Base_SetConfig(htim->Instance, &htim->Init) 设置定时器的时间基准配置。这包括预分频器、计数模式、自动重载等设置。
DMA 状态初始化: 设置定时器的 DMA burst 操作状态为 HAL_DMA_BURST_STATE_READY,表示 DMA 操作准备就绪,可以开始数据传输。
定时器通道状态设置: 使用 TIM_CHANNEL_STATE_SET_ALL 和 TIM_CHANNEL_N_STATE_SET_ALL 宏将所有的定时器通道状态设置为 HAL_TIM_CHANNEL_STATE_READY,表示通道准备好进行操作。
函数结尾: 最后,将定时器的状态设置为 HAL_TIM_STATE_READY,表示定时器配置完成并准备好工作。函数返回 HAL_OK,表示初始化成功。
开始定时
下面我们就要开始定时:定时使用的函数就是:HAL_TIM_Base_Start_IT: HAL_TIM_Base_Start_IT 函数用于启动基本定时器的更新中断模式。当启用中断模式时,定时器会定期触发更新事件,并通过中断通知用户。此函数适用于需要周期性执行任务的应用,比如定时器定时中断。这就是为什么我们要在上面开启他的中断
/*** @brief 启动 TIM 基本定时器的中断模式。* @param htim TIM 基本定时器句柄* @retval HAL 状态码*/
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
{uint32_t tmpsmcr;
/* 检查传入的 TIM 实例是否有效 */assert_param(IS_TIM_INSTANCE(htim->Instance));
/* 检查 TIM 的当前状态是否为就绪状态 */if (htim->State != HAL_TIM_STATE_READY){return HAL_ERROR; // 如果定时器不是就绪状态,返回错误}
/* 设置定时器状态为忙碌 */htim->State = HAL_TIM_STATE_BUSY;
/* 启用 TIM 更新中断 */__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
/* 启用定时器外设,除非是触发模式(trigger mode),触发模式下定时器会自动启用 */if (IS_TIM_SLAVE_INSTANCE(htim->Instance)) // 检查是否为从模式定时器{tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS; // 获取定时器从模式的状态if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr)) // 如果不是触发模式,则启用定时器{__HAL_TIM_ENABLE(htim); // 启动定时器}}else{__HAL_TIM_ENABLE(htim); // 如果是主模式,直接启用定时器}
/* 返回操作状态 */return HAL_OK; // 返回成功
}
-
函数概述:
-
参数检查:
-
assert_param(IS_TIM_INSTANCE(htim->Instance)):检查传入的定时器实例是否有效。通过宏IS_TIM_INSTANCE,确认htim->Instance属于有效的 TIM 实例(例如TIM1,TIM2等)。
-
-
定时器状态检查:
-
if (htim->State != HAL_TIM_STATE_READY):检查定时器的当前状态是否为就绪状态。如果定时器处于其他状态(例如忙碌或未初始化状态),则返回错误HAL_ERROR,表示不能启动定时器。
-
-
定时器状态更新:
-
htim->State = HAL_TIM_STATE_BUSY:将定时器状态设置为HAL_TIM_STATE_BUSY,表示定时器正在被配置或启动,防止其他操作与当前操作冲突。
-
-
启用 TIM 更新中断:
-
__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE):启用定时器的更新中断。定时器会在计数溢出时产生更新事件,触发相应的中断,用户可以在中断处理函数中执行定时任务。
-
-
定时器启用:
-
if (IS_TIM_SLAVE_INSTANCE(htim->Instance)):检查定时器是否是从模式(Slave mode)。从模式的定时器通常需要与主定时器同步运行,触发模式的定时器会自动启动,无需手动启用。 -
tmpsmcr = htim->Instance->SMCR & TIM_SMCR_SMS:获取定时器的从模式控制寄存器(SMCR)中的从模式选择字段(SMS)。 -
if (!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr)):如果定时器不是触发模式,调用__HAL_TIM_ENABLE(htim)启动定时器。 -
如果是主模式定时器(非从模式),则直接启用定时器。
-
-
返回状态:
-
如果一切顺利,函数返回
HAL_OK,表示定时器已成功启用并开始工作。
-
如何处理句柄?
定时中断现在被打开了,然后如何呢?答案是我们要重载我们的CallBack函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
这个函数需要我们自己先判定一下句柄,然后接下来就是处理业务代码。
相关文章:
从0开始的STM32 定时器(I):聊一聊基本定时器
目录 时钟源 控制器 时基单元 关于HAL库如何配置基本定时器 HAL是如何初始化我们的定时器句柄的 HAL_TIM_Base_Init 开始定时 如何处理句柄? 在我们使用STM32解决一些问题的时候,常常会遇到说:我想要以一个周期做一些事情:…...
vue常见题型(1-10)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 2.2双向绑定的原理是什么vue框架采用的是数据双向绑定的方式,由三个重要部分构成2.2.1.ViewModel2.2.2 双向绑定2.2.3.1.编译Compile2.2.3.2.依赖收集 3…...
【SpringBoot】使用注解进行XSS防御
在Spring Boot中,我们可以使用注解的方式来进行XSS防御。注解是一种轻量级的防御手段,它可以在方法或字段级别对输入进行校验,从而防止XSS攻击。 引入相关依赖 maven依赖: <!--JSR-303/JSR-380用于验证的注解 --> <de…...
华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)
华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目分享——共九套(每套四十题) 岗位——芯片与器件设计工程师 岗位意向——模拟芯片 真题题目分享,完整题目,无答案(共8套) 实习岗位…...
vscode 下载慢的解决方法
下载链接示例:https://az764295.vo.msecnd.net/stable/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/code1.62.3-1637137107amd64.deb 解决方法: 把 az764295.vo.msecnd.net 替换成 vscode.cdn.azure.cn...
STM32ZET6-USART使用
一、原理说明 STM32自带通讯接口 通讯目的 通信方式: 全双工:通信时可以双方同时通信。 半双工:通信时同一时间只能一个设备发送数据,其他设备接收。 单工:只能一个设备发送到另一个设备,例如USART只有…...
es自动补全(仅供自己参考)
elasticssearch提供了CompletionSuggester查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回。为了提高补全查询效率,对于文档中字段的类型有一些约束: 查询类型必须是:completion 字段内容是多个补全词条形成的数组 P…...
13-综合排序:Function Score Query 优化算分
使用了 function_score 查询来根据某个字段的值对查询结果进行打分。以下是该查询的主要部分: query: 包含了实际执行搜索的部分,在这里包括一个 multi_match 查询。 multi_match:用于在多个字段上执行相同的查询。 query:设置…...
鸿蒙应用App测试-专项测试(DevEco Testing)
注意:大家记得先学通用测试在学专项测试 鸿蒙应用App测试-通用测试-CSDN博客 注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章写的好的话,可以点下关注&am…...
RabbitMQ设置消息过期时间
RabbitMQ设置消息过期时间 1、过期消息(死信)2、设置消息过期的两种方式2.1、设置单条消息的过期时间2.1.1、配置文件application.yml2.1.2、配置类RabbitConfig2.1.3、发送消息业务类service(核心代码)2.1.4、启动类2.1.5、依赖文…...
大数据-209 数据挖掘 机器学习理论 - 梯度下降 梯度下降算法调优
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...
粒子群优化双向深度学习!PSO-BiTCN-BiGRU-Attention多输入单输出回归预测
粒子群优化双向深度学习!PSO-BiTCN-BiGRU-Attention多输入单输出回归预测 目录 粒子群优化双向深度学习!PSO-BiTCN-BiGRU-Attention多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现PSO-BiTCN-BiGRU-Attention粒子…...
排序算法简介
直接插入排序: 将第一个元素视为已排序的序列,其余元素视为未排序序列。 逐个处理:从第二个元素开始,逐个将当前元素插入到已排序序列的适当位置,直到所有元素都被插入。 插入过程:对于每个待…...
(没有跳过联网激活)导致使用微软账号激活电脑---修改为本地账户和英文名字
修改为本地账户和英文名字 前言微软账号,本地账号与用户名基本知识账户管理方式一方式2 查看账户的sid并且修改文件夹名字和系统变量修改注册表和建立软件路径超链接注意事项总结 前言 当没有联网激活新买的电脑时候,这个就不用看了 当你是联网激活的时…...
[论文粗读][REALM: Retrieval-Augmented Language Model Pre-Training
引言 今天带来一篇检索增强语言模型预训练论文笔记——REALM: Retrieval-Augmented Language Model Pre-Training。这篇论文是在RAG论文出现之前发表的。 为了简单,下文中以翻译的口吻记录,比如替换"作者"为"我们"。 语言模型预训练…...
flink 内存配置(五):网络缓存调优
flink 内存配置(一):设置Flink进程内存 flink 内存配置(二):设置TaskManager内存 flink 内存配置(三):设置JobManager内存 flink 内存配置(四)…...
set和map的使用
目录 1.关联式容器 2.键值对 3.set 3.1set的模版参数列表 3.2对set的修改 3.2.1insert 3.2.2 erase 3.2.3clear 3.2.4swap 3.2.5 find 3.3set的迭代器 3.4set的容量 4.map 4.1对map的修改 4.1.1insert 4.1.2erase 4.1.3swap 4.1.4clear 4.2map的迭代器 4.3opera…...
LCL三相并网逆变器simulink仿真+说明文档
背景描述: 详细解析了LCL三相并网逆变器的工作原理,强调了准PR比例谐振控制的重要性,讨论了电感、电容参数选择及保护电路设计。通过仿真结果展示了逆变器性能优化的方法,以提升系统效率和稳定性。 模型介绍: 整体模…...
从0开始深度学习(24)——填充和步幅
1 填充 在上一节中,我们的卷积步骤如下: 可以发现输入是 3 3 3\times3 33,输出是 2 2 2\times2 22,这样可能会导致原始图像的边界丢失了许多有用信息,如果应用多层卷积核,累积丢失的像素就更多了&#…...
CPU Study - Instructions Fetch
参考来源:《超标量处理器设计》—— 姚永斌 N-Way CPU 取指问题 如果CPU可以在每个周期内同时解码N条指令,则此类CPU为N-Way超标量处理器。 N-Way超标量处理器需要每个周期从I-Cache中至少取得N条指令,这N条指令成为一组Fetch Group。 为了…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
