STM32通用定时器TIM3的PWM输出实验配置步骤
通用定时器 PWM 输出实验
本小节我们来学习使用通用定时器的 PWM 输出模式。
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。我们可以让定时器产生PWM,在计数器频率固定时,PWM 频率或者周期由自动重载寄存器(TIMx_ARR)的值决定,其占空比由捕获/比较寄存器(TIMx_CCRx)的值决定。PWM 产生原理示意图如下图所示:

上图中,定时器工作在递增计数模式,纵轴是计数器的计数值 CNT,横轴表示时。当CNT<CCRx 时,IO 输出低电平(逻辑 0);当 CNT>=CCRx 时,IO 输出高电平(逻辑 1);当CNT=ARR 时,定时器溢出,CNT 的值被清零,然后继续递增,依次循环。在这个循环中,改变 CCRx 的值,就可以改变 PWM的占空比,改变 ARR 的值,就可以改变 PWM 的频率,这就是 PWM 输出的原理。
定时器产生 PWM的方式有许多种,下面我们以边沿对齐模式(即递增计数模式/递减计数模式)为例,PWM 模式 1 或者 PWM 模式 2 产生 PWM 的示意图,如下图所示:

TIM2/TIM3/TIM4/TIM5 寄存器
要使 STM32F429的通用定时器 TIMx产生 PWM 输出,除了上一小节介绍的寄存器外,我们还会用到另外 3 个寄存器,来控制 PWM 输出。这三个寄存器分别是:捕获/比较模式寄存器(TIMx_CCMR1/2)、 捕 获/比 较 使 能 寄 存 器 (TIMx_CCER)、 捕 获/比较寄存器(TIMx_CCR1~4)。接下来我们简单介绍一下这三个寄存器。
捕获/比较模式寄存器 1/2(TIMx_CCMR1/2)
TIM2/TIM3/TIM4/TIM5的捕获/比较模式寄存器(TIMx_CCMR1/2),该寄存器一般有 2 个:TIMx _CCMR1 和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 CH2,而 TIMx_CCMR2 控制CH3 和 CH4。TIMx_CCMR2 寄存器描述如下图所示:

该寄存器的有些位在不同模式下,功能不一样,我们现在用到输出比较,先看输出比较部分,输入捕获在后面的实验再讲解。关于该寄存器的详细说明,请参考《STM32F4xx 参考手册_V4(中文版).pdf》第 432 页,15.4.7 节。比如我们要让 TIM3 的 CH4 输出 PWM 波,该寄存器的模式设置位 OC4M[2:0]就是对应着通道 4 的模式设置。总共可以配置 8 种模式,我们使用的是 PWM 模式 1 或者 PWM 模式 2,所以位 OC4M[2:0]设置为 110 或者 111。这两种 PWM模式的区别就是输出有效电平的极性相反。位 OC4PE 控制输出比较通道 4 的预装载使能,实际就是控制 CCR4 寄存器是否进行缓冲。因为 CCR4 寄存器也是有影子寄存器的,影子寄存器才是真正起作用的寄存器。CC4S[1:0]用于设置通道 4 的方向(输入/输出)默认设置为 0,就是设置通道作为输出使用。
捕获/比较使能寄存器(TIMx_ CCER)
TIM2/TIM3/TIM4/TIM5 的捕获/比较使能寄存器,该寄存器控制着各个输入输出通道的开关和极性。TIMx_CCER 寄存器描述如图 所示:

该寄存器比较简单,要让 TIM3 的 CH4 输出 PWM 波,这里我们要使能 CC4E 位,该位是通道 4 输入/输出使能位,要想 PWM 从 IO 口输出,这个位必须设置为 1。CC4P 位是设置通道4 的输出极性,我们默认设置 0。
捕获/比较寄存器 1/2/3/4(TIMx_ CCR1/2/3/4)
捕获/比较寄存器(TIMx_ CCR1/2/3/4),该寄存器总共有 4 个,分别对应 4 个通道CH1~CH4。我们使用的是通道 4,所以来看看 TIMx_ CCR4 寄存器描述,如图所示:

在输出模式下,捕获/比较寄存器影子寄存器的值与 CNT 的值比较,根据比较结果产生相应动作,利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的占空比了。注意,对于 TIM2 和 TIM5 来说,该寄存器是 32 位有效的,对其他定时器来说,则是 16 位有效位。
硬件设计
1. 例程功能
使用 TIM3 通道 4(由 PB1 复用)输出 PWM, PB1 引脚连接了 LED0,从而实现 PWM 输出控制 LED0 亮度。
2. 硬件资源
1)LED 灯 LED0: LED0 – PB1
2)定时器 3 输出通道 4(对应 PB1)
3. 原理图
定时器属于 STM32F429 的内部资源,只需要软件设置好即可正常工作。我们通过 LED0来间接指示定时器的 PWM 输出情况。
程序设计
定时器的 HAL 库驱动
定时器在 HAL 库中的驱动代码在前面介绍基本定时器已经介绍了部分,这里我们再介绍几个本实验用到的函数。
1. HAL_TIM_PWM_Init 函数
定时器 PWM 输出基础工作参数初始化函数,其声明如下:
HAL_StatusTypeDef HAL_TIM_PWM_Init(TIM_HandleTypeDef *htim);
函数描述
用于初始化定时器的基础工作参数,即初始化 TIM_HandleTypeDef 结构体成员。
函数形参:
形参 1 是 TIM_HandleTypeDef 结构体类型指针变量,基本定时器的时候已经介绍。
函数返回值: HAL_StatusTypeDef 枚举类型的值。
注意事项:
该函数实现的功能以及使用方法和 HAL_TIM_Base_Init 类似,作用都是初始化定时器的ARR 和 PSC 等参数。为什么 HAL 库要提供这个函数而不直接让我们使用 HAL_TIM_Base_Init函数呢?这是因为 HAL 库为定时器的针对 PWM 输出定义了单独的 MSP 回调函数HAL_TIM_PWM_MspInit,所以当我们调用 HAL_TIM_PWM_Init 进行 PWM 初始化之后,该函数内部会调用 MSP 回调函数 HAL_TIM_PWM_MspInit。当我们使用 HAL_TIM_Base_Init 初始化定时器参数的时候,它内部调用的回调函数是 HAL_TIM_Base_MspInit,这里大家注意区分。
2. HAL_TIM_PWM_ConfigChannel 函数
定时器 PWM 模式通道配置函数。其声明如下:HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,TIM_OC_InitTypeDef *sConfig, uint32_t Channel);
函数描述:
该函数用于设置定时器的 PWM 输出模式及通道等参数。
函数形参:
形参 1 是 TIM_HandleTypeDef 结构体类型指针变量,用于配置定时器基本参数。
形参 2 是 TIM_OC_InitTypeDef 结构体类型指针变量,用于配置定时器输出比较参数。
下面重点来了解一下 TIM_OC_InitTypeDef 结构体指针类型,其定义如下:
typedef struct
{uint32_t OCMode; /* 输出比较模式选择,寄存器的时候说过了,共 8 种模式 */uint32_t Pulse; /* 设置比较值*/uint32_t OCPolarity; /* 设置输出比较极性 */uint32_t OCNPolarity; /* 设置互补输出比较极性 */uint32_t OCFastMode; /* 使能或失能输出比较快速模式 */uint32_t OCIdleState; /* 选择空闲状态下的非工作状态(OC1 输出) */uint32_t OCNIdleState; /* 设置空闲状态下的非工作状态(OC1N 输出) */
} TIM_OC_InitTypeDef;
我们重点关注前三个结构体成员。成员变量 OCMode 用来设置模式,这里我们设置为PWM模式 1。成员变量 Pulse 用来设置捕获比较值。成员变量 TIM_OCPolarity用来设置输出极性。其他成员 TIM_OutputNState,TIM_OCNPolarity,TIM_OCIdleState 和 TIM_OCNIdleState后面用到再介绍。形参 3 是定时器通道,范围:TIM_CHANNEL_1~4,比如定时器 3 只有 4 个通道,那选择范围就只有 TIM_CHANNEL_1~4,所以要根据具体情况选择。
函数返回值: HAL_StatusTypeDef 枚举类型的值。
3. HAL_TIM_PWM_Start 函数
定时器 PWM 输出启动函数,其声明如下:
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
函数描述:
用于使能通道输出和启动计数器,即启动 PWM 输出。
函数形参:
形参 1 是 TIM_HandleTypeDef 结构体类型指针变量。
形参 2 是定时器通道,范围:TIM_CHANNEL_1 到 TIM_CHANNEL_4。
函数返回值: HAL_StatusTypeDef 枚举类型的值。
注意事项:
HAL 库提供了单独使能定时器输出通道的函数,其声明如下:
void TIM_CCxChannelCmd(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ChannelState); HAL_TIM_PWM_Start 函数内部也是调用了该函数。
4. HAL_TIM_ConfigClockSource 函数
配置定时器时钟源函数,其声明如下:
HAL_StatusTypeDef HAL_TIM_ConfigClockSource(TIM_HandleTypeDef *htim, TIM_ClockConfigTypeDef *sClockSourceConfig);
函数描述:
用于配置定时器时钟源。
函数形参:
形参 1 是 TIM_HandleTypeDef 结构体类型指针变量。
形参 2 是 TIM_ClockConfigTypeDef 结构体类型指针变量,用于配置定时器时钟源参数。
TIM_ClockConfigTypeDef 定义如下:
typedef struct
{uint32_t ClockSource; /* 时钟源 */uint32_t ClockPolarity; /* 时钟极性 */uint32_t ClockPrescaler; /* 定时器预分频器 */
uint32_t ClockFilter; /* 时钟过滤器 */
} TIM_ClockConfigTypeDef;
函数返回值: HAL_StatusTypeDef 枚举类型的值。
注意事项:
该函数主要配置 TIMx_SMCR 寄存器。默认情况下,定时器的时钟源是内部时钟。本实验就是使用内部时钟的,所以我们不用对时钟源进行初始化,默认即可。这里只是让大家知道有这个函数可以设定时器的时钟源。比如用 HAL_TIM_ConfigClockSource 初始化选择内部时钟,
方法如下:
TIM_HandleTypeDef timx_handle; /* 定时器 x 句柄 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; /* 选择内部时钟 */
HAL_TIM_ConfigClockSource(&timx_handle, &sClockSourceConfig);
后面的定时器初始化凡是用到内部时钟我们都没有去进行初始化,系统默认即可。
定时器 PWM 输出模式配置步骤
1)开启 TIMx 和相应通道输出的 GPIO 时钟,配置该 IO 口的复用功能输出
首先开启 TIMx 的时钟,然后配置 GPIO 为复用功能输出。本实验我们默认用到定时器 3通道 4,对应 IO 是 PB1,它们的时钟开启方法如下:
__HAL_RCC_TIM3_CLK_ENABLE(); /* 使能定时器 3 */
__HAL_RCC_GPIOB_CLK_ENABLE(); /* 开启 GPIOB 时钟 */
IO 口复用功能是通过函数 HAL_GPIO_Init 来配置的。
2)初始化 TIMx,设置 TIMx 的 ARR 和 PSC 等参数
使用定时器的 PWM 输出功能时,通过 HAL_TIM_PWM_Init 函数初始化定时器 ARR 和PSC 等参数。
注意:该函数会调用:HAL_TIM_PWM_MspInit 函数,我们可以通过后者存放定时器和GPIO 时钟使能、GPIO 初始化、中断使能以及优先级设置等代码。
3)设置定时器为 PWM 模式,输出比较极性,比较值等参数
在 HAL 库中,通过 HAL_TIM_PWM_ConfigChannel 函数来设置定时器为 PWM1模式或者PWM2 模式,根据需求设置输出比较的极性,设置比较值(控制占空比)等。
4)使能 TIMx,使能 TIMx 的 CHy 输出
在 HAL 库中,通过调用 HAL_TIM_PWM_Start 函数来使能 TIMx 的某个通道输出 PWM。
5)修改 TIM3_CCR4 来控制占空比
在经过以上设置之后,PWM 其实已经开始输出了,只是其占空比和频率都是固定的,而我们可以通过修改比较值来控制 PWM的输出占空比。HAL库中提供一个修改占空比的宏定义:
__HAL_TIM_SET_COMPARE (__HANDLE__, __CHANNEL__, __COMPARE__)
__HANDLE__是 TIM_HandleTypeDef 结构体类型指针变量,__CHANNEL__对应 PWM 的输出通道,__COMPARE__则是要写到捕获/比较寄存器(TIMx_ CCR1/2/3/4)的值。实际上该宏定义最终还是往对应的捕获/比较寄存器写入比较值来控制 PWM 波的占空比。如下解析:比如我们要修改定时器 3 通道 4 的输出比较值(控制占空比),寄存器操作方法:
TIM3->CCR4 = ledrpwmval; /* ledrpwmval 是比较值,并且动态变化的, 所以我们要周期性调用这条语句,已达到及时修改 PWM 的占空比 */
__HAL_TIM_SET_COMPARE这个宏定义函数最终也是调用这个寄存器操作的,所以说我们使用 HAL 库的函数其实就是间接操作寄存器的。
程序流程图

这里我们只讲解核心代码,详细的源码请大家参考本实验对应源码。通用定时器驱动源码包括两个文件:gtim.c 和 gtim.h。
首先看 gtim.h 头文件的几个宏定义
/* TIMX PWM 输出定义* 这里输出的 PWM 控制 LED0(RED)的亮度* 默认是针对 TIM2~TIM5*/#define GTIM_TIMX_PWM_CHY_GPIO_PORT GPIOB#define GTIM_TIMX_PWM_CHY_GPIO_PIN GPIO_PIN_1#define GTIM_TIMX_PWM_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB 口时钟使能 */#define GTIM_TIMX_PWM_CHY_GPIO_AF GPIO_AF2_TIM3 /* 端口复用到 TIM3 *//* TIMX REMAP 设置 */#define GTIM_TIMX_PWM TIM3 /* TIM3 */#define GTIM_TIMX_PWM_CHY TIM_CHANNEL_4 /* 通道 Y, 1<= Y <=4 */ #define GTIM_TIMX_PWM_CHY_CCRX TIM3->CCR4 /* 通道 Y 的输出比较寄存器 */ #define GTIM_TIMX_PWM_CHY_CLK_ENABLE() do{ __HAL_RCC_TIM3_CLK_ENABLE(); }while(0) /* TIM3 时钟使能 */
可以把上面的宏定义分成两部分,第一部分是定时器 3输出通道 4对应的 IO口的宏定义。第二部分则是定时器 3 输出通道 4 的相应宏定义,这里的宏定义是定时器 3 通道 4 输出 PWM控制 LED0 的相关宏定义。
gtim.h 头文件就添加了这部分的程序,下面看 gtim.c 的程序,首先是通用定时器 PWM 输出初始化函数。
/**
* @brief 通用定时器 TIMX 通道 Y PWM 输出 初始化函数(使用 PWM 模式 1)
* @note
* 通用定时器的时钟来自 APB1,当 PPRE1 ≥ 2 分频的时候
* 通用定时器的时钟为 APB1 时钟的 2 倍, 而 APB1 为 45M, 所以定时器时钟 = 90Mhz
* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
* Ft = 定时器工作频率,单位:Mhz
*
* @param arr: 自动重装值
* @param psc: 预分频系数
* @retval 无
*/
void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc)
{TIM_OC_InitTypeDef timx_oc_pwm_chy = {0}; /* 定时器输出句柄 */g_timx_pwm_chy_handle.Instance = GTIM_TIMX_PWM; /* 定时器 x */g_timx_pwm_chy_handle.Init.Prescaler = psc; /* 预分频系数 */g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;/* 递增计数模式*/g_timx_pwm_chy_handle.Init.Period = arr; /* 自动重装载值 */HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle); /* 初始化 PWM */timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1; /* 模式选择 PWM1 */timx_oc_pwm_chy.Pulse = arr / 2; /* 设置比较值,此值用来确定占空比 */timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_LOW; /* 输出比较极性为低 */ HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy,GTIM_TIMX_PWM_CHY); /* 配置 TIMx 通道 y *//* 开启对应 PWM 通道 */HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY);
}
HAL_TIM_PWM_Init 初始化 TIM3 并设置 TIM3 的 ARR 和 PSC 等参数,其次通过调用函数 HAL_TIM_PWM_ConfigChannel 设置 TIM3_CH4 的 PWM 模式以及比较值等参数,最后通过调用函数 HAL_TIM_PWM_Start 来使能 TIM3 以及使能 PWM 通道 TIM3_CH4 输出。本实验我们使用 PWM 的 MSP 初始化回调函数 HAL_TIM_PWM_MspInit 来存放时钟、GPIO 的初始化代码,其定义如下:
/**
* @brief 定时器底层驱动,时钟使能,引脚配置此函数会被 HAL_TIM_PWM_Init()调用
* @param htim:定时器句柄
* @retval 无
*/
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{if (htim->Instance == GTIM_TIMX_PWM){GPIO_InitTypeDef gpio_init_struct;GTIM_TIMX_PWM_CHY_GPIO_CLK_ENABLE(); /* 开启通道 y 的 GPIO 时钟 */GTIM_TIMX_PWM_CHY_CLK_ENABLE(); /* 使能定时器时钟 */gpio_init_struct.Pin = GTIM_TIMX_PWM_CHY_GPIO_PIN; /* 通道 y 的 GPIO 口 */gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */gpio_init_struct.Alternate = GTIM_TIMX_PWM_CHY_GPIO_AF; /* IO 口 REMAP 设置, 是否必要查看头文件配置的说明! */HAL_GPIO_Init(GTIM_TIMX_PWM_CHY_GPIO_PORT, &gpio_init_struct);}
}
该函数首先判断定时器寄存器基地址,符合条件后,开启对应的 GPIO 时钟和定时器时钟,并且初始化 GPIO。上面是使用 HAL 库标准的做法,我们亦可把 HAL_TIM_PWM_MspInit 函数里面的代码直接放到 gtim_timx_pwm_chy_init 函数里。这样做的好处是当一个项目中用到多个定时器时,代码的移植性、可读性好,方便管理。
在 main.c 里面编写如下代码:
int main(void)
{uint16_t ledrpwmval = 0;uint8_t dir = 1;HAL_Init(); /* 初始化 HAL 库 */sys_stm32_clock_init(360, 25, 2, 8); /* 设置时钟,180Mhz */delay_init(180); /* 延时初始化 */usart_init(115200); /* 初始化 USART */led_init(); /* 初始化 LED */gtim_timx_pwm_chy_init(500 - 1, 90 - 1); /* 90 000 000 / 90 = 1 000 000 1Mhz 的计数频率,2Khz 的 PWM */while(1){delay_ms(10);if (dir)ledrpwmval++; /* dir==1 ledrpwmval 递增 */else ledrpwmval--; /* dir==0 ledrpwmval 递减 */if (ledrpwmval > 300)dir = 0; /* ledrpwmval 到达 300 后,方向为递减 */if (ledrpwmval == 0)dir = 1; /* ledrpwmval 递减到 0 后,方向改为递增 *//* 修改比较值控制占空比 */__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY,ledrpwmval);}
}
本小节开头我们就说 PWM 频率由自动重载寄存器(TIMx_ARR)的值决定,其占空比则由捕获/比较寄存器(TIMx_CCRx)的值决定。下面结合实际看看具体怎么计算:
定时器 3 的时钟源频率为 2 倍 APB1 总线时钟频率,即频率为 90MHz,而调用gtim_timx_pwm_chy_init 初始化函数之后,就相当于写入预分频寄存器的值为 89,写入自动重载寄存器的值为 499。基本定时器讲的定时器溢出公式由公式得:
Tout= ((arr+1)*(psc+1))/Tclk= ((499+1)*(89+1))/90000000=0.0005s
再由频率是周期的倒数关系得到 PWM 的频率为 2000Hz。
占空比怎么计算的呢?结合图 20.3.1,我们分两种情况分析,输出比较极性为低和输出比较极性为高,它们的情况正好相反。因为在 main 函数中的比较值是动态变化的,不利于我们计算占空比,我们假设比较值固定为 200,在本实验中可以调用如下语句得到。
__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY, 200);
因为 LED0 是低电平有效,所以我们在 gtim_timx_pwm_chy_init 函数中设置了输出比较极性为低,那么当比较值固定为200时,占空比 = ((arr+1) – CCR4)/ (arr+1) = (500-200)/500=60%。
其中 arr 是写入自动重载寄存器(TIMx_ARR)的值,CCR4 就是写入捕获/比较寄存器 4(TIMx_CCR4)的值。这里我们还需要提醒一下,占空比是指在一个周期内,高电平时间相对于总时间所占的比例。
另外一种情况:设置了输出比较极性为高,那么当比较值固定为 200 时,占空比 = CCR4 / (arr+1) = 200/500=40%。可以看到输出比较极性为低和输出比较极性为高的占空比正好反过来。
在这里,我们使用 DS100 示波器进行验证,效果图如下图 所示:

这里把输出比较极性低和输出比较极性高的 PWM 波形都显示出来了。本实验默认设置PWM 模式 1、输出比较极性低,当 CCR1 寄存器的值设置为 200 时,对应的 PWM 波形如上图黄色的波形图。如果把输出比较极性设置为高,对应的波形图就是绿色的波形图了。
相关文章:
STM32通用定时器TIM3的PWM输出实验配置步骤
通用定时器 PWM 输出实验 本小节我们来学习使用通用定时器的 PWM 输出模式。 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。我们可以让定时…...
device tree 预研
linux kernel 引入 dts 的背景 http://www.wowotech.net/linux_kenrel/why-dt.html 什么是 device tree device tree 是一种描述硬件资源的数据结构。device tree 可以描述的信息包括 cpu 的数量和类别、内存基地址和大小、clock 控制器和 clock 使用情况、外设基地址以及…...
英伟达股价分析:英伟达股价能否上涨到150美元,接下来该如何操作?
来源:猛兽财经 作者:猛兽财经 猛兽财经核心观点: (1)华尔街投行Oppenheimer已将英伟达的目标价上调到了150美元。 (2)产品方面的最新进展和合作伙伴关系进一步提升了英伟达的市场地位。 &…...
Rust 快速入门(一)
Rust安装信息解释 cargo:Rust的编译管理器、包管理器、通用工具。可以用Cargo启动新的项目,构建和运行程序,并管理代码所依赖的所有外部库。 Rustc:Rust的编译器。通常Cargo会替我们调用此编译器。 Rustdoc:是Rust的…...
java 程序在服务器出现时区错误问题(使用Date,LocalDateTime,ZonedDateTime都不正确)
排查 查询系统时区信息 timedatectl status打印java的时区信息 import java.util.TimeZone;public class CheckTimeZone {public static void main(String[] args) {TimeZone defaultTimeZone TimeZone.getDefault();System.out.println("Default TimeZone ID: "…...
Kotlin 语言的协程是什么?
目录 1. 什么是协程 2. 协程的基本概念 3. 如何使用协程 3.1. 引入依赖 3.2. 启动协程 3.3. 使用挂起函数 4. 结构化并发 5. 处理异常 6. 总结 Kotlin 的协程是一种轻量级的线程,可以用于简化异步编程。它允许你以顺序的方式编写异步代码,从而提…...
uniapp 游戏 - 使用 uniapp 实现的扫雷游戏
0. 思路 1. 效果图 2. 游戏规则 扫雷的规则很简单。盘面上有许多方格,方格中随机分布着一些雷。你的目标是避开雷,打开其他所有格子。一个非雷格中的数字表示其相邻 8 格子中的雷数,你可以利用这个信息推导出安全格和雷的位置。你可以用右键在你认为是雷的地方插旗(称为标…...
LeetCode组合总和
题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限制重复被…...
MATLAB - 机械臂手眼标定(眼在手内) - 估计安装在机器人上的移动相机的姿态
系列文章目录 前言 本示例展示了如何为装有手眼构型摄像头的机械臂或机械手执行和验证手眼校准。 一、概述 执行手眼校准有助于操作配备末端执行器(简称 “手”)的机械臂,该末端执行器依赖于摄像头提供的视觉数据。一旦完成了眼在手外的校准&…...
【Unity】TextMeshPro 3.0.9无法显示emoji表情问题
需要下载TextMeshPro 3.2.x-pre.xxx版本,重新生成Sprite Asset文件解决 注意:若Package Manager没有搜到pre版本,那么可以去github下载到本地,再解压后,将文件夹移动到工程Packages文件夹下,然后打开Packa…...
金九银十软件测试面试题(800道)
今年你的目标是拿下大厂offer?还是多少万年薪?其实这些都离不开日积月累的过程。 为此我特意整理出一份(超详细笔记/面试题)它几乎涵盖了所有的测试开发技术栈,非常珍贵,人手一份 肝完进大厂 妥妥的&#…...
中国剩余定理 C++
题目 解题思路 原链接:https://www.acwing.com/solution/content/3539/ 大致步骤: 将第2,3,4…n个方程不断与第一个方程合并,得到方程a1k1a2k2m2-m1;用扩展欧几里得算法解出a1k1a2k2gcd(a1, a2)的结果,再将结果扩大(m2-m1)/d倍即…...
动态规划lc
先找到规律,然后找边界情况;部分特殊情况分类讨论 *递归 70.爬楼梯 简单 提示 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:…...
介绍xshell的使用技巧
使用技巧目录 1. 开启左键选中即复制,右键点击即粘贴2. 开启撰写功能3. 开启日志记录功能 1. 开启左键选中即复制,右键点击即粘贴 参考:https://blog.csdn.net/chirrupy_hamal/article/details/108619262 2. 开启撰写功能 使用场景&#x…...
揭秘语音识别巨头1:国内外顶尖技术服务商全解析01(万字长文)
一、学习导航 解密语音识别巨头:国内顶尖技术服务商全解析00:学习地图 解密语音识别巨头:国内顶尖技术服务商全解析01:微软语音,商业No.1 解密语音识别巨头:国内顶尖技术服务商全解析02:百度…...
JAVA使用SM2算法生成密钥对加密解密加签验签
简介 SM2是非对称加密算法,一提非对称加密算法,第一想到的是RSA,没错,这个就是替代RSA的。它是基于椭圆曲线密码的公钥密码算法标准,其秘钥长度256bit,包含数字签名、密钥交换和公钥加密,用于替…...
uniapp(vue)打包web项目页面刷新后报404解决方案
一、问题概述 uniapp是一款优秀的跨平台开发框架,它可以帮助开发者快速构建出适用于多端的应用程序。然而,在项目打包后,有可能发现页面在刷新时会出现404错误。这无疑给用户体验带来了极大的困扰,下面我们就来分析一下这个问题。…...
ansible学习之ansible-vault
相关文档参考:http://www.ansible.com.cn/docs/playbooks_vault.html#what-can-be-encrypted-with-vault ansible-vault 功能介绍 Ansible-Vault是一个用于加密和管理Ansible playbook中敏感数据的工具。通过创建、编辑、加密、解密、查看和重置密码,可以安全地存储…...
封装el-upload组件,用于上传图片和视频的组件
使用环境 vue3element plus 需要根据后端返回结构修改的函数:onPreview onRemove onSuccess 组件使用 基本使用 源代码: <script setup> import AutoUploadFile from /components/auto-upload-file/index.vue function change(urls){console.log…...
6.将扩散模型与其他生成模型的关联(2)
1.归一化流与扩散模型 自一化流(Normalizing Flow)是生成模型,通过将易于处理的分布进行变换以队对高维数据进行建模。归一化流可以将简单的概率分布转化为极其复杂的分布,并用于强化学习、变分推理等领域。 现有的归一化流是基于变量替换公式构…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...
