STM32-10-定时器
STM32-01-认识单片机
STM32-02-基础知识
STM32-03-HAL库
STM32-04-时钟树
STM32-05-SYSTEM文件夹
STM32-06-GPIO
STM32-07-外部中断
STM32-08-串口
STM32-09-IWDG和WWDG
文章目录
- 一、STM32 基础定时器
- 1. 基本定时器简介
- 2. 基本定时器框图
- 3. 基本定时器相关寄存器
- 4. 定时器溢出时间计算
- 5. 基本定时器中断配置步骤
- 6. 代码实现
- 二、STM32通用定时器
- 1. 通用定时器简介
- 2. 通用定时器框图
- 1. 时钟源
- 1. 内部时钟(`CK_INT`)
- 2. 外部时钟模式1(TI1, TI2)
- 3. 外部时钟模式2(ETR)
- 4. 内部触发输入(ITRx)
- 2. 控制器
- 3. 时基单元
- 4. 输入捕获
- 5. 捕获/比较(公共)
- 6. 输出比较
- 3. 通用定时器相关寄存器
- 三、 通用定时器输出PWM波
- 1. 通用定时器PWM输出实验配置步骤
- 2. 代码实现
- 四、通用定时器输入捕获实验
- 1. 输入捕获测量脉冲宽度
- 2. 输入捕获实验相关寄存器
- 3. 通用定时器输入捕获配置步骤
- 4. 代码实现
- 五、通用定时器脉冲计数实验
- 1. 脉冲计数框图
- 2. 相关寄存器
- 3. 通用定时器脉冲计数配置步骤
- 4. 代码实现
- 六、高级定时器输出指定个数PWM实验
- 1. 高级定时器框图
- 2. 重复计数器特性
- 3. 相关寄存器
- 4. 高级定时器输出指定个数PWM实验配置步骤
- 5. 代码实现
- 七、高级定时器输出比较模式实验
- 1. 输出比较模式功能
- 2. 相关寄存器
- 3. 高级定时器输出比较模式实验配置步骤
- 4. 代码实现
- 八、高级定时器互补输出带死区控制实验
- 1. 互补死区的理解
- 2. 相关寄存器
- 3. 高级定时器互补输出带死区控制实验配置步骤
- 4. 代码实现
- 九、高级定时器PWM输入模式实验
- 1. PWM输入工作原理
- 2. 输入模式时序图
- 3. 相关寄存器
- 4. 高级定时器PWM输入模式实验配置步骤
- 4. 代码实现
一、STM32 基础定时器
STM32定时器分类:

STM32定时器特性表:

主要功能:
| 定时器类型 | 主要功能 |
|---|---|
| 基本定时器 | 没有输入输出通道,常用作时基,即定时功能 |
| 通用定时器 | 具有多路独立通道,可用于输入捕获/输出比较,也可用作时基 |
| 高级定时器 | 除具备通用定时器所有功能外,还具备带死区控制的互补信号输出、刹车输入等功能(可用于电机控制、数字电源设计等) |
1. 基本定时器简介
-
STM32F103有两个基本定时器
TIM6和TIM7,它们的功能完全相同,资源是完全独立的,可以同时使用。 -
主要特性:
- 16位自动重载递增计数器;
- 16位可编程预分频器,预分频系数
1~65536,用于对计数器时钟频率进行分频; - 触发DAC的同步电路;
- 生成中断 和DMA请求。
-
定时原理:

2. 基本定时器框图

-
影子寄存器: 实际起作用的寄存器,用户不可直接访问。举个例子:我们可以把预分频系数写入预分频器寄存器(
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时,我们称之为定时器溢出,因为是递增计数,故而又称为定时器上溢。定时器溢出就伴随着更新事件的发生。
- 软件产生,将
-
计数模式与溢出条件:

-
递增计数模式实例说明:

-
递减计数模式实例说明:

-
中心对齐计数模式实例说明:

-
3. 基本定时器相关寄存器
-
控制寄存器 1(
TIMx_CR1)

-
DMA/中断使能寄存器(
TIMx_DIER)

-
状态寄存器(
TIMx_SR)

-
计数器(
TIMx_CNT)

-
预分频器(
TIMx_PSC)

-
自动重装载寄存器(
TIMx_ARR)

4. 定时器溢出时间计算

5. 基本定时器中断配置步骤
-
配置定时器基础工作参数
HAL_TIM_Base_Init() -
定时器基础MSP初始化
HAL_TIM_Base_MspInit() -
使能更新中断并启动计数器
HAL_TIM_Base_Start_IT() -
设置优先级,使能中断
HAL_NVIC_SetPriority() HAL_NVIC_EnableIRQ() -
编写中断服务函数
TIMx_IRQHandler() HAL_TIM_IRQHandler() -
编写定时器更新中断回调函数
HAL_TIM_PeriodElapsedCallback()
-
程序流程

6. 代码实现
-
功能:使用定时器中断实现LED灯闪烁.
-
定时器中断初始化
void btim_timx_int_init(uint16_t psc, uint16_t per) {g_timx_handle.Instance = TIM6;g_timx_handle.Init.Prescaler = psc;g_timx_handle.Init.Period = per;HAL_TIM_Base_Init(&g_timx_handle);HAL_TIM_Base_Start_IT(&g_timx_handle);} -
定时器基础MSP初始化函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) {if (htim->Instance == TIM6){__HAL_RCC_TIM6_CLK_ENABLE();HAL_NVIC_SetPriority(TIM6_IRQn, 1, 3);HAL_NVIC_EnableIRQ(TIM6_IRQn);} } -
定时器6中断服务函数
void TIM6_IRQHandler() {HAL_TIM_IRQHandler(&g_timx_handle); } -
定时器溢出中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM6){LED0_TOGGLE();} } -
主函数
#include "./SYSTEM/sys/sys.h" #include "./SYSTEM/usart/usart.h" #include "./SYSTEM/delay/delay.h" #include "./BSP/LED/led.h" #include "./BSP/KEY/key.h" #include "./BSP/BEEP/beep.h" #include "./BSP/EXTI/exti.h" #include "./BSP/WDG/wdg.h" #include "./BSP/TIMER/btim.h"int main(void) {HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */btim_timx_int_init(7199, 4999);while(1){} }
二、STM32通用定时器
1. 通用定时器简介
- 通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。
- 它适用于多种场合,包括测量输入信号的脉冲宽度(输入捕获)或者产生输出波形(输出比较和PWM)。
- 使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。
- 每个定时器都是完全独立的,没有互相共享任何资源,并且可以一起同步操作。
-
主要特性
-
16位递增、递减、中心对齐计数器(计数值:0~65535)
-
16位预分频器(分频系数:1~65536)
-
4个独立通道:输入捕获,输出比较,PWM生成,单脉冲模式输出
-
使用外部信号控制定时器且可实现多个定时器互连的同步电路
-
支持针对定位的增量编码器和霍尔传感器电路
-
触发输入作为外部时钟或者按周期的电流管理
-
2. 通用定时器框图
1. 时钟源

| 计数器时钟选择类型 | 设置方法 |
|---|---|
| 内部时钟(CK_INT) | 设置TIMx_SMCR的SMS=000 |
| 外部时钟模式1:外部输入引脚(TIx) | 设置TIMx_SMCR的SMS=111 |
| 外部时钟模式2:外部触发输入(ETR) | 设置TIMx_SMCR的ECE=1 |
| 内部触发输入(ITRx) |

1. 内部时钟(CK_INT)
- 定时器TIM2~TIM7挂接在APB1总线上,这些定时器的内部时钟(CK_INT)实际上来自APB1总线提供的时钟,然后经过一个倍频器之后,输出的时钟频率为72MHz。
2. 外部时钟模式1(TI1, TI2)

3. 外部时钟模式2(ETR)

4. 内部触发输入(ITRx)

2. 控制器

-
控制器包括:触发控制器,从模式控制器,编码器接口
-
触发控制器:用来提供触发信号给别的外设
-
从模式控制器:可以控制计数器复位、启动、递增/递减、计数
-
编码器接口:针对编码器计数
-
3. 时基单元

4. 输入捕获

TIMx_CH1~TIMx_CH4表示定时器的4个通道,4个通道独立工作。IO端口通过复用功能与这些通道相连。配置好IO端口的复用功能后,将需要测量的信号输入到相应的 IO端口,输入捕获部分可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常见的测量有:测量输入信号的脉冲宽度、测量PWM输入信号的频率和占空比等。

5. 捕获/比较(公共)

以通道1为例,对应CCR1寄存器,CC1G位可以产生软件捕获事件,那么硬件捕获事件如何产生的?以通道1输入为例,CC1S[1:0]=01,即IC1映射到TI1上;CC1E位置1,使能输入捕获;比如不滤波、不分频,ICF[3:0]=00,ICPS[1:0]=00;比如检测上升沿,CC1P位置0:接着就是等待测量信号的上升沿到来。当上升沿到来时,IC1PS信号就会触发输入捕获事件发生,计数器的值就会被锁存到捕获/比较影子寄存器里。当CCR1寄存器没有被进行读操作的时候,捕获/比较影子寄存器里的值就会锁存到CCR1寄存器中,那么程序员就可以读取CCR1寄存器,得到计数器的计数值。检测下降沿同理。
6. 输出比较

首先程序员写CCR1寄存器,即写入比较值。这个比较值需要转移到对应的捕获比较影子寄存器后才会真正生效。什么条件下才能转移?compare transfer旁边的与门,需要满足三个条件:CCR1不在写入操作期间、CC1S[1:0]=0配置为输出、OC1PE位置 0(或者OC1PE位置1,并且需要发生更新事件,这个更新事件可以软件产生或者硬件产生)。当CCR1寄存器的值转移到其影子寄存器后,新的值就会和计数器的值进行比较,它们的比较结果将会通过输出比较影响定时器的输出。

3. 通用定时器相关寄存器
-
控制寄存器1(
TIMx_CR1)

-
从模式控制寄存器(
TIMx_SMCR)

-
DMA/中断使能寄存器(
TIMx_DIER)

-
状态寄存器(
TIMx_SR)

-
计数寄存器(
TIMx_CNT)

-
预分频寄存器(
TIMx_PSC)

-
自动重载寄存器(
TIMx_ARR)

三、 通用定时器输出PWM波
-
通用定时器输出模式
PWM,即脉冲宽度调制,是利用微处理器的数字输出对模拟电路进行控制的一种非常有效的技术。让定时器产生PWM,在计数器频率固定时,PWM频率自动重载寄存器(TIMx_ARR)的值决定,其占空比由捕获/比较寄存器(TIMx_CCRx)的值决定。

-
PWM模式

-
PWM控制寄存器
-
捕获/比较模式寄存器1/2(
TIMx_CCMR1/2)

-
捕获/比较使能寄存器(
TIMx_CCER)

-
捕获/比较寄存器(
TIMx_CCR1/2/3/4)

-
1. 通用定时器PWM输出实验配置步骤
-
配置定时器基础工作参数
HAL_TIM_PWM_Init() -
定时器PWM输出MSP初始化
HAL_TIM_PWM_MspInit() -
配置PWM模式/比较值等
HAL_TIM_PWM_ConfigChannel() -
使能输出并启动计数器
HAL_TIM_PWM_Start() -
修改比较值控制占空比(可选)
__HAL_TIM_SET_COMPARE() -
使能通道预装载(可选)
__HAL_TIM_ENABLE_OCxPRELOAD()
-
相关库函数介绍
函数 主要寄存器 主要功能 HAL_TIM_PWM_Init() CR1、ARR、PSC 初始化定时器基础参数 HAL_TIM_PWM_MspInit() 无 存放NVIC、CLOCK、GPIO初始化代码 HAL_TIM_PWM_ConfigChannel() CCMRx、CCRx、CCER 配置PWM模式、比较值、输出极性等 HAL_TIM_PWM_Start() CCER、CR1 使能输出比较并启动计数器 __HAL_TIM_SET_COMPARE() CCRx 修改比较值 __HAL_TIM_ENABLE_OCxPRELOAD() CCER 使能通道预装载
2. 代码实现
-
功能:使用TM3通道2(由PB5复用)输出PWM,PB5引脚连接了LED0,从而实现PWM输出控制LED0亮度。
-
程序流程:

-
通用定时器PWM输出初始化函数
void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc) {TIM_OC_InitTypeDef timx_oc_pwm_chy;g_timx_pwm_chy_handle.Instance = TIM3; //定时器选择g_timx_pwm_chy_handle.Init.Prescaler = psc; //定时器分频g_timx_pwm_chy_handle.Init.Period = arr;g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //定时器计数模式HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle); //初始化PWMtimx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1; //模式选择PWM1timx_oc_pwm_chy.Pulse = arr/2; //占空比为50%timx_oc_pwm_chy.OCNPolarity = TIM_OCNPOLARITY_LOW; //输出比较极性为低HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, TIM_CHANNEL_2); //配置定时器3通道2HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_2); //开启PWM通道 } -
定时器输出PWM MSP初始化函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM3){GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_TIM3_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_5;gpio_init_struct.Mode = GPIO_MODE_AF_PP;gpio_init_struct.Pull = GPIO_PULLUP;gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &gpio_init_struct);__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM3_PARTIAL(); //设置重映射,把TIM3通道2映射到PB5} } -
主函数
int main(void) {uint16_t ledrpwmval = 0;uint8_t dir = 1;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */gtim_timx_pwm_chy_init(500 - 1, 72 - 1);while(1){delay_ms(10);if(dir) ledrpwmval++;else ledrpwmval--;if(ledrpwmval > 300) dir = 0;if(ledrpwmval == 0) dir = 1;__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, TIM_CHANNEL_2, ledrpwmval);} }
四、通用定时器输入捕获实验
1. 输入捕获测量脉冲宽度

测量方法:假定工作在递增计数模式,首先设置通道x为上升沿捕获,这样在t1时刻上升沿到来时,就会发生捕获事件(打开捕获中断,捕获事件发生时会触发捕获中断)。在捕获中断里将计数器值清零,并设置通道x为下降沿捕获,这样t2时刻下降沿到来时,就会发生捕获事件和捕获中断。捕获事件发生时,计数器的值会被锁存到捕获/比较寄存器中。在捕获中断内,读取捕获/比较寄存器就可以获取高电平脉冲时间,计数器计数的个数,从而可以算出高电平脉冲的时间(假定计数器没有溢出)。
但是在t1到t2时间段,定时器可能会产生N次溢出,需要对定时器溢出做相应的处理,防止高电平太长,导致测量出错。在t1到t2时间内,假定定时器溢出N次,那么高电平时间内,计数器计数的个数计算方法为:N * (ARR + 1) + CCRx2,CCRx2表示t2时间点,捕获/比较寄存器的值。经过计算得到高电平脉宽时间内计数器计数个数后,用这个个数乘以计数器的计数周期,就可以得到高电平持续的时间。就是输入捕获测量高电平脉宽时间的整个过程。
STM32F103的定时器除了TM6和TM7,其他定时器都有输入捕获功能。输入捕获,简单的说就是通过检测TIMx_CHy上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)时,会发生捕获事件,将当前定时器的值(TIMx_CNT)锁存到对应通道的捕获/比较寄存器(TIMx_CCRy)里,完成一次捕获。同时还可以配置捕获事件发生时是否触发捕获中断/DMA。另外还要考虑测量的过程中是否可能发生定时器溢出,如果可能溢出,还要做溢出处理。
2. 输入捕获实验相关寄存器
-
捕获/比较模式寄存器1/2(
TIMx_CCMR1/2)

-
捕获/比较使能寄存器(
TIMx_CCER)

3. 通用定时器输入捕获配置步骤
-
配置定时器基础工作参数
HAL_TIM_IC_Init() -
定时器输入捕获MSP初始化
HAL_TIM_IC_MspInit() -
配置输入通道映射、捕获边沿等
HAL_TIM_IC_ConfigChannel() -
设置优先级,使能中断
HAL_NVIC_SetPriority() HAL_NVIC_EnableIRQ() -
使能定时器更新中断
__HAL_TIM_ENABLE_IT() -
使能捕获、捕获中断及计数器
HAL_TIM_IC_Start_IT() -
编写中断服务函数
TIMx_IRQHandler() HAL_TIM_IRQHandler() -
编写更新中断和捕获回调函数
HAL_TIM_PeriodElapsedCallback() HAL_TIM_IC_CaptureCallback()
-
相关函数的功能
函数 主要寄存器 主要功能 HAL_TIM_IC_Init() CR1、ARR、PSC 初始化定时器基础参数 HAL_TIM_IC_MspInit() 无 存放NVIC、CLOCK、GPIO初始化代码 HAL_TIM_IC_ConfigChannel() CCMRx、CCER 配置通道映射、捕获边沿、分频、滤波等 __HAL_TIM_ENABLE_IT() DIER 使能更新中断等 HAL_TIM_IC_Start_IT() CCER、DIER、CR1 使能输入捕获、捕获中断并启动计数器 HAL_TIM_IRQHandler() SR 定时器中断处理公用函数,处理各种中断 HAL_TIM_PeriodElapsedCallback() 无 定时器更新中断回调函数,由用户重定义 HAL_TIM_IC_CaptureCallback() 无 定时器输入捕获回调函数,由用户重定义
4. 代码实现
-
功能
1、使用TM5CH1来做输入捕获,捕获PA0上的高电平脉宽,并将脉宽时间通过串口打印出来,然后通过按WKUP按键,模拟输入高电平,例程中能测试的最长高电平脉宽时间为: 4194303us.
2、LED0闪烁指示程序运行。
-
通用定时器TIM5通道1输入捕获初始化函数
void gtim_timx_cap_chy_init(uint16_t arr, uint16_t psc) {TIM_IC_InitTypeDef timx_ic_cap_chy = {0};//初始化定时器参数 g_timx_cap_chy_handle.Instance = TIM5; //定时器5的基地址g_timx_cap_chy_handle.Init.Prescaler = psc; //定时器的分频系数g_timx_cap_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //递增计数模式g_timx_cap_chy_handle.Init.Period = arr; //自动重装载值HAL_TIM_IC_Init(&g_timx_cap_chy_handle); //初始化//配置通道映射、捕获边沿、分频、滤波等timx_ic_cap_chy.ICPolarity = TIM_ICPOLARITY_RISING; //配置捕获极性为上升沿timx_ic_cap_chy.ICSelection = TIM_ICSELECTION_DIRECTTI; //映射到通道1timx_ic_cap_chy.ICPrescaler = TIM_ICPSC_DIV1; //不进行分频timx_ic_cap_chy.ICFilter = 0; //不进行滤波HAL_TIM_IC_ConfigChannel(&g_timx_cap_chy_handle, &timx_ic_cap_chy, TIM_CHANNEL_1); //初始化__HAL_TIM_ENABLE_IT(&g_timx_cap_chy_handle, TIM_IT_UPDATE); //使能更新中断HAL_TIM_IC_Start_IT(&g_timx_cap_chy_handle, TIM_CHANNEL_1); //开始捕获TIM5的通道1 } -
通用定时器输入捕获初始化函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM5) //判断定时器是否正确{GPIO_InitTypeDef gpio_init_struct; //GPIO配置结构体__HAL_RCC_TIM5_CLK_ENABLE(); //使能定时器时钟__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟gpio_init_struct.Pin = GPIO_PIN_0; //配置引脚号gpio_init_struct.Mode = GPIO_MODE_AF_PP; //配置复用推挽输出gpio_init_struct.Pull = GPIO_PULLDOWN; //配置下拉模式gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; //配置输出速度HAL_GPIO_Init(GPIOA, &gpio_init_struct); //初始化HAL_NVIC_SetPriority(TIM5_IRQn, 1, 3); //设置中断优先级HAL_NVIC_EnableIRQ(TIM5_IRQn); //使能TIM5中断} } -
定时器TIM5中断服务函数
//定时器5中断服务函数 void TIM5_IRQHandler(void) {//HAL库中断公共处理函数HAL_TIM_IRQHandler(&g_timx_cap_chy_handle); } -
定时器输入捕获中断处理回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM5){if((g_timxchy_cap_sta & 0x80) == 0) //未成功捕获{if(g_timxchy_cap_sta & 0x40) //捕获下降沿{g_timxchy_cap_sta |= 0x80; //位7置1 代表成功捕获g_timxchy_cap_val = HAL_TIM_ReadCapturedValue(&g_timx_cap_chy_handle, TIM_CHANNEL_1); //保存当前计数器的值TIM_RESET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1); //失能通道TIM_SET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING); //使能通道1为上降沿捕获}else //捕获上升沿{g_timxchy_cap_sta = 0;g_timxchy_cap_val = 0;g_timxchy_cap_sta |= 0x40;__HAL_TIM_DISABLE(&g_timx_cap_chy_handle); //失能定时器5__HAL_TIM_SET_COUNTER(&g_timx_cap_chy_handle, 0); //计数器的值清0TIM_RESET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1); //失能通道TIM_SET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //使能通道1为下降沿捕获__HAL_TIM_ENABLE(&g_timx_cap_chy_handle); //使能定时器5}}} } -
定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM5){if((g_timxchy_cap_sta & 0x80) == 0) //未成功捕获{if(g_timxchy_cap_sta & 0x40) //已经成功捕获{if((g_timxchy_cap_sta & 0X3F) == 0x3f) //高电平时间过长{TIM_RESET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1); //失能通道TIM_SET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); //使能通道1为下降沿捕获g_timxchy_cap_sta |= 0x80; //标记成功捕获一次g_timxchy_cap_val = 0xFFFF;}else //累积定时器溢出次数{g_timxchy_cap_sta++;}}}}if(htim->Instance == TIM6){LED0_TOGGLE();}if(htim->Instance == TIM7){LED1_TOGGLE();} } -
主函数
int main(void) {uint32_t temp = 0;uint8_t t= 0;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */gtim_timx_cap_chy_init(0xFFFF, 72 - 1); //1MHzwhile(1){if(g_timxchy_cap_sta & 0x80){temp = g_timxchy_cap_sta & 0x3F;temp = temp * 65536; //溢出时间总和temp += g_timxchy_cap_val; //溢出的总时间printf("HIGH:%d us\r\n", temp);g_timxchy_cap_sta = 0; //开启下一次捕获}t++;if(t > 20){t = 0;LED0_TOGGLE();}delay_ms(10);} } -
主程序运行流程

-
中断程序运行流程

五、通用定时器脉冲计数实验
1. 脉冲计数框图
脉冲计数实验使用的时钟源是外部时钟模式1,外部输入引脚(TIx)作为定时器的时钟源。实验中使用WK_UP按键按下产生的高电平脉冲作为定时器的计数器时钟,每按下一次按键产生一次高电平脉冲,计数器的值加一。

外部时钟模式1的外部输入引脚只能是通道1或者通道2对应的IO,通道3或者通道4不可以。以通道1输入为例,外部时钟源信号通过通道1输入后,TI1分别要经过滤波器、边沿检测器后,来到TI1FP1,被触发输入选择器选择为触发源,接着来到从模式控制器。从模式选择为外部时钟模式1,这时候外部时钟源信号就会到达时基单元的预分频器,后面就是经过分频后就作为计数器的计数时钟。
2. 相关寄存器
-
捕获/比较模式寄存器1/2(
TIMx_CCMR1/2)与输入捕获配置相同
-
捕获/比较使能寄存器(
TIMx_CCER)与输入捕获配置相同
-
从模式控制寄存器(
TIMx_SMCR)

3. 通用定时器脉冲计数配置步骤
-
配置定时器基础工作参数
HAL_TIM_IC_Init() -
定时器输入捕获MSP初始化
HAL_TIM_IC_MspInit() -
配置定时器从模式等
HAL_TIM_SlaveConfigSynchro() -
使能输入捕获并启动计数器
HAL_TIM_IC_Start() -
获取计数器的值
__HAL_TIM_GET_COUNTER() -
设置计数器的值
__HAL_TIM_SET_COUNTER()
-
相关库函数
函数 主要寄存器 主要功能 HAL_TIM_IC_Init() CR1、ARR、PSC 初始化定时器基础参数 HAL_TIM_IC_MspInit() 无 存放NVIC、CLOCK、GPIO初始化代码 HAL_TIM_SlaveConfigSynchro() SMCR、CCMRx、CCER 配置定时器从模式、触发选择、分频、滤波等 HAL_TIM_IC_Start() CCER、CR1 使能输入捕获、启动计数器 __HAL_TIM_GET_COUNTER() CNT 获取计数器当前值 __HAL_TIM_SET_COUNTER() CNT 设置计数器的值
4. 代码实现
-
功能:
使用TM2CH1做输入捕获,我们将捕获PA0上的高电平脉宽,并将脉宽进行计数,通过串口打印出来。大家可以通过按WKUP按键,输入高电平脉冲,通过按KEY0重设当前计数。 LED0闪烁,提示程序运行。
-
通用定时器脉冲计数初始化函数
void gtim_timx_cnt_chy_init(uint16_t psc) {TIM_SlaveConfigTypeDef timx_slave_config = {0};g_timx_cnt_chy_handle.Instance = TIM2; //定时器选择g_timx_cnt_chy_handle.Init.Prescaler = psc; //定时器分频g_timx_cnt_chy_handle.Init.Period = 65535;g_timx_cnt_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //定时器计数模式HAL_TIM_IC_Init(&g_timx_cnt_chy_handle); //初始化PWMtimx_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;timx_slave_config.InputTrigger = TIM_TS_TI1F_ED;timx_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;timx_slave_config.TriggerFilter = 0;HAL_TIM_SlaveConfigSynchro(&g_timx_cnt_chy_handle, &timx_slave_config);HAL_TIM_IC_Start(&g_timx_cnt_chy_handle, TIM_CHANNEL_1); } -
主函数
int main(void) {uint16_t curcnt; //存储当前的计数值uint16_t oldcnt; //存储旧的计数值uint8_t key; //按键的键值uint8_t t; //延时时间HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */key_init();gtim_timx_cnt_chy_init(0); while(1){key = key_scan(0);if(key == 1){__HAL_TIM_SET_COUNTER(&g_timx_cnt_chy_handle, 0);}curcnt = __HAL_TIM_GET_COUNTER(&g_timx_cnt_chy_handle);if(oldcnt != curcnt){oldcnt = curcnt;printf("CNT:%d\r\n", oldcnt);}t++;if(t > 20){t = 0;LED0_TOGGLE();}delay_ms(10);} }
六、高级定时器输出指定个数PWM实验
1. 高级定时器框图

-
重复计数器
在基本定时器和通用定时器中,定时器发生上溢或者下溢时,会直接生成更新事件。但有重复计数器的定时器并不完全这样,在定时器每次发生上溢或下溢时,重复计数器的值会减一,当重复计数器的值为0时,再发生一次上溢或者下溢才会生成定时器更新事件。如果我们设置重复计数器寄存器的
RCR的值为N,那么更新事件将在定时器发生N+1次上溢或下溢时发生。 -
输出比较
与通用定时器相比,高级定时器多了带死区控制的互补输出功能。通道1、2、3都有互补输出通道,
DTG是死区发生器,死区时间由DTG[7:0]位来配置。如果不使用互补通道和死区时间控制,那么高级定时器TIM1和TIM8和通用定时器的输出比较部分使用方法基本一样,只是要注意MOE位得置1定时器才能输出。 -
断路功能
断路功能也称刹车功能,一般用于控制电机的刹车。F1系列有一个断路通道,断路源可以是刹车输入引脚(
TIMx_BKIN),也可以是一个时钟失败事件。时钟失败事件由复位时钟控制器中的时钟安全系统产生。系统复位后,断路功能默认被禁止,MOE位为低。
2. 重复计数器特性

-
计数器每次上溢或下溢都能使重复计数器减1,减到0时,再发生一次溢出就会产生更新事件。
-
如果设置RCR为N,更新事件将在N+1次溢出时发生。
3. 相关寄存器
-
控制寄存器1(
TIMx_CR1)

-
捕获/比较模式寄存器1/2(
TIMx_CCMR1/2)

-
捕获/比较使能寄存器(
TIMx_CCER)

-
事件产生寄存器(
TIMx_EGR)

-
重复计数器寄存器(
TIMx_RCR)

-
捕获/比较寄存器1/2/3/4(
TIMx_CCR1/2/3/4)

-
断路和死区寄存器(
TIMx_BDTR)

4. 高级定时器输出指定个数PWM实验配置步骤
-
配置定时器基础工作参数
HAL_TIM_PWM_Init() -
定时器PWM输出MSP初始化
HAL_TIM_PWM_MspInit() -
配置PWM模式/比较值等
HAL_TIM_PWM_ConfigChannel() -
设置优先级,使能中断
HAL_NVIC_SetPriority() HAL_NVIC_EnableIRQ() -
使能定时器更新中断
__HAL_TIM_ENABLE_IT() -
使能输出、主输出、计数器
HAL_TIM_PWM_Start() -
编写中断服务函数
TIMx_IRQHandler() HAL_TIM_IRQHandler() -
编写更新中断回调函数
HAL_TIM_PeriodElapsedCallback()
-
具体函数功能
函数 主要寄存器 主要功能 HAL_TIM_PWM_Init() CR1、ARR、PSC 初始化定时器基础参数 HAL_TIM_PWM_MspInit() 无 存放NVIC、CLOCK、GPIO初始化代码 HAL_TIM_PWM_ConfigChannel() CCMRx、CCRx、CCER 配置PWM模式、比较值、输出极性等 __HAL_TIM_ENABLE_IT() CCER 使能更新中断等 HAL_TIM_PWM_Start() CCER、CR1 使能输出、主输出、启动计数器 HAL_TIM_IRQHandler() SR 定时器中断处理公用函数,处理各种中断 HAL_TIM_PeriodElapsedCallback() 无 定时器更新中断回调函数,由用户重定义 HAL_TIM_GenerateEvent() EGR 通过软件产生事件 __HAL_TIM_ENABLE() CR1 启动计数器
5. 代码实现
-
功能:
通过TIM8CH1(由PC6复用)输出PWM,然后为了指示PWM的输出情况,我们用杜邦线将PC6和PE5引脚的排针连接起来,从而实现PWM输出控制LED1(硬件已连接在PPE5引脚上)的亮灭。注意的点是:PE5要设置成浮空输入,避免引脚冲突,我们在main函数中设置好了,请看源码。上电默认输出5个PWM波,连接好杜邦线后可以看见LED1亮灭五次。之后按一下按键KEYO,就会输出5个PWM波控制LED1亮灭五次。LED0闪烁提示系统正在运行。
-
高级定时器输出指定个数PWM初始化
void atim_timx_npwm_chy_init(uint16_t arr, uint16_t psc) {TIM_OC_InitTypeDef timx_oc_npwm_chy = {0};g_timx_npwm_chy_handle.Instance = TIM8;g_timx_npwm_chy_handle.Init.Prescaler = psc;g_timx_npwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数模式g_timx_npwm_chy_handle.Init.Period = arr;g_timx_npwm_chy_handle.Init.RepetitionCounter = 0; //重复计数器初始值g_timx_npwm_chy_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /*使能TIMx_ARR进行缓冲 */HAL_TIM_PWM_Init(&g_timx_npwm_chy_handle);timx_oc_npwm_chy.OCMode = TIM_OCMODE_PWM1; //使用PWM1工作模式timx_oc_npwm_chy.Pulse = arr / 2; //占空比设置为50%timx_oc_npwm_chy.OCPolarity = TIM_OCPOLARITY_HIGH; //高电平有效HAL_TIM_PWM_ConfigChannel(&g_timx_npwm_chy_handle, &timx_oc_npwm_chy, TIM_CHANNEL_1); //进行初始化__HAL_TIM_ENABLE_IT(&g_timx_npwm_chy_handle, TIM_IT_UPDATE); //允许更新中断HAL_TIM_PWM_Start(&g_timx_npwm_chy_handle, TIM_CHANNEL_1); //开启对应的PWM通道 } -
高级定时器输出指定个数PWM MSP回调函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM8){GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_TIM8_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_6;gpio_init_struct.Pull = GPIO_PULLUP;gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;gpio_init_struct.Mode = GPIO_MODE_AF_PP;HAL_GPIO_Init(GPIOC, &gpio_init_struct);HAL_NVIC_SetPriority(TIM8_UP_IRQn, 1, 3);HAL_NVIC_EnableIRQ(TIM8_UP_IRQn);} } -
高级定时器设置PWM个数函数
void atim_timx_npwm_chy_set(uint8_t npwm) {if(npwm == 0) return;g_npwm_remain = npwm; //保存脉冲个数HAL_TIM_GenerateEvent(&g_timx_npwm_chy_handle, TIM_EVENTSOURCE_UPDATE); //产生一次软件更新事件,在中断里面处理脉冲输出__HAL_TIM_ENABLE(&g_timx_npwm_chy_handle); //使能定时器TIM8 } -
定时器8中断服务函数
void TIM8_UP_IRQHandler(void) {HAL_TIM_IRQHandler(&g_timx_npwm_chy_handle); } -
定时器更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM8){if(g_npwm_remain){TIM8->RCR = g_npwm_remain - 1;HAL_TIM_GenerateEvent(&g_timx_npwm_chy_handle, TIM_EVENTSOURCE_UPDATE);__HAL_TIM_ENABLE(&g_timx_npwm_chy_handle);g_npwm_remain = 0;}else{TIM8->CR1 &= ~(1 << 0);}} } -
主函数
void LED_init(void) {GPIO_InitTypeDef gpio_init_struct;gpio_init_struct.Pin = GPIO_PIN_5;gpio_init_struct.Mode = GPIO_MODE_INPUT; //设置为输入,防止冲突(PC6)gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOE, &gpio_init_struct); }int main(void) {uint8_t t = 0;uint8_t key = 0;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */ // usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */key_init();LED_init(); //需要重新配置PE5为输入模式防止冲突atim_timx_npwm_chy_init(5000 -1, 7200 - 1);atim_timx_npwm_chy_set(5); while(1){key = key_scan(0);if(key == 4){atim_timx_npwm_chy_set(6);}t++;if(t > 50){t = 0;LED0_TOGGLE();}delay_ms(10);} }
七、高级定时器输出比较模式实验
1. 输出比较模式功能
输出比较模式下翻转功能作用是:当计数器的值等于捕获/比较寄存器影子寄存器的值时, OC1REF发生翻转,进而控制通道输出(OCx)翻转。通过翻转功能实现输出PWM的具体原理如下:PWM频率由自动重载寄存器(TIMx_ARR)的值决定,在这个过程中,只要自动重载寄存器的值不变,那么PWM占空比就固定为50%。可以通过捕获/比较寄存器(TIMx_CCRx)的值改变PWM的相位。

2. 相关寄存器
-
控制寄存器1(
TIMx_CR1)

-
捕获/比较模式寄存器1/2(
TIMx_CCMR1/2)

-
捕获/比较使能寄存器(
TIMx_CCER)

-
捕获/比较寄存器1/2/3/4(
TIMx_CCR1/2/3/4)

-
TIM1/TIM8断路和死区寄存器(
TIMx_BDTR)

3. 高级定时器输出比较模式实验配置步骤
-
配置定时器基础工作参数
HAL_TIM_OC_Init() -
定时器输出比较MSP初始化
HAL_TIM_OC_MspInit() -
配置输出比较模式等
HAL_TIM_OC_ConfigChannel() -
使能通道预装载
__HAL_TIM_ENABLE_OCxPRELOAD() -
使能输出、主输出、计数器
HAL_TIM_OC_Start() -
修改捕获/比较寄存器的值
__HAL_TIM_SET_COMPARE()
-
具体函数功能
函数 主要寄存器 主要功能 HAL_TIM_OC_Init() CR1、ARR、PSC 初始化定时器基础参数 HAL_TIM_OC_MspInit 无 存放NVIC、CLOCK、GPIO初始化代码 HAL_TIM_OC_ConfigChannel() CCMRx、CCRx、CCER 设置输出比较模式、比较值、输出极性等 __HAL_TIM_ENABLE_OCxPRELOAD() CCMRx 使能通道预装载 HAL_TIM_OC_Start() CR1、CCER、BDTR 使能输出比较、主输出、启动计数器 __HAL_TIM_SET_COMPARE() CCRx 修改捕获/比较寄存器的值
4. 代码实现
-
功能:
使用输出比较模式的翻转功能,通过定时器8的4路通道输出占空比固定为50%、相位分别是25%、50%、75%和100%的PWM。
-
高级定时器输出比较初始化
void atim_timx_comp_pwm_init(uint16_t arr, uint16_t psc) {TIM_OC_InitTypeDef timx_oc_comp_pwm = {0};g_timx_comp_pwm_handle.Instance = TIM8;g_timx_comp_pwm_handle.Init.Prescaler = psc;g_timx_comp_pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //向上计数模式g_timx_comp_pwm_handle.Init.Period = arr;g_timx_comp_pwm_handle.Init.RepetitionCounter = 0; //重复计数器初始值HAL_TIM_PWM_Init(&g_timx_comp_pwm_handle);timx_oc_comp_pwm.OCMode = TIM_OCMODE_TOGGLE; //模式选择翻转timx_oc_comp_pwm.OCPolarity = TIM_OCPOLARITY_HIGH; //极性选择高电平HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_1);HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_2);HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_3);HAL_TIM_OC_ConfigChannel(&g_timx_comp_pwm_handle, &timx_oc_comp_pwm, TIM_CHANNEL_4);//使能通道预装载__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_1);__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_2);__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_3);__HAL_TIM_ENABLE_OCxPRELOAD(&g_timx_comp_pwm_handle, TIM_CHANNEL_4);//使能输出、主输出、计数器HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_1);HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_2);HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_3);HAL_TIM_OC_Start(&g_timx_comp_pwm_handle, TIM_CHANNEL_4); } -
定时器输出比较MSP函数
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM8){GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_TIM8_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();gpio_init_struct.Mode = GPIO_MODE_AF_PP; //推挽复用gpio_init_struct.Pin = GPIO_PIN_6;gpio_init_struct.Pull = GPIO_NOPULL; //没有上下拉gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOC, &gpio_init_struct);gpio_init_struct.Pin = GPIO_PIN_7;HAL_GPIO_Init(GPIOC, &gpio_init_struct);gpio_init_struct.Pin = GPIO_PIN_8;HAL_GPIO_Init(GPIOC, &gpio_init_struct);gpio_init_struct.Pin = GPIO_PIN_9;HAL_GPIO_Init(GPIOC, &gpio_init_struct);} } -
主函数
int main(void) {uint8_t t = 0;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */key_init();atim_timx_comp_pwm_init(1000 - 1, 72 - 1);__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_1, 250 - 1);__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_2, 500 - 1);__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_3, 750 - 1);__HAL_TIM_SET_COMPARE(&g_timx_comp_pwm_handle, TIM_CHANNEL_3, 1000 - 1);while(1){ t++;if(t > 50){t = 0;LED0_TOGGLE();}delay_ms(10);} } -
程序运行结果

八、高级定时器互补输出带死区控制实验
1. 互补死区的理解
- 互补输出

CH1输出黄色的PWM,互补通道CH1N输出绿色的PWM,两个信号恰好是相反的,CH1的PWM为高电平期 间,CH1N的PWM则是低电平,反之亦然,这就是互补输出。
-
带死区控制的互补输出

CH1输出的PWM和CH1N输出的PWM在高低电平转换期间,插入了一段时间才实现互补输出。这段时间称为死区时间。上图箭头所指的区域就是死区时间,两段时间相同。
-
死区互补控制H桥

- 当Q1和Q4导通,电流的方向是从左到右;当Q2和Q3导通,电流的方向是从右到左。
- 因为元器件具有延时特性,控制信号经过OC1传输到电机需要一定的时间。由于元器件的特性,就会直接导致直接使用互补输出信号驱动H桥存在短路现象。为了避免这种情况,就有了带死区控制的互补输出来驱动H桥。用户必须根据与输出相连接的器件及其特性(电平转换器的固有延迟、开关器件产生的延迟)来调整死区时间。
-
死区时间计算

2. 相关寄存器
-
控制寄存器1(
TIMx_CR1)

-
捕获/比较模式寄存器1/2(
TIMx_CCMR1/2)

-
捕获/比较使能寄存器(
TIMx_CCER)

-
捕获/比较寄存器1/2/3/4(
TIMx_CCR1/2/3/4)

-
TIM1/TIM8断路和死区寄存器(
TIMx_BDTR)

对应的结构框图

-
刹车断路功能

发生刹车后:

3. 高级定时器互补输出带死区控制实验配置步骤
-
配置定时器基础工作参数
HAL_TIM_PWM_Init() -
定时器PWM输出MSP初始化
HAL_TIM_PWM_MspInit() -
配置PWM模式/比较值等
HAL_TIM_PWM_ConfigChannel() -
配置刹车功能、死区时间等
HAL_TIMEx_ConfigBreakDeadTime() -
使能输出、主输出、计数器
HAL_TIM_PWM_Start() -
使能互补输出、主输出、计数器
HAL_TIMEx_PWMN_Start()
-
相关函数功能
函数 主要寄存器 主要功能 HAL_TIM_PWM_Init() CR1、ARR、PSC 初始化定时器基础参数 HAL_TIM_PWM_MspInit() 无 存放NVIC、CLOCK、GPIO初始化代码 HAL_TIM_PWM_ConfigChannel() CCMRx、CCRx、CCER 配置PWM模式、比较值、输出极性等 HAL_TIMEx_ConfigBreakDeadTime() BDTR 配置刹车功能、死区时间等 HAL_TIM_PWM_Start() CCER、CR1 使能输出、主输出、启动计数器 HAL_TIMEx_PWMN_Start() CCER、CR1 使能互补输出、主输出、启动计数器
4. 代码实现
-
功能:
- 利用TIM1_CH1(PE9)输出70%占空比的PWM波,它的互补输出通道(PE8)则是输出30%占空比的PWM波。
- 刹车功能,当给刹车输入引脚(PE15)输入高电平时,进行刹车,即PE8和PE9停止输出PWM波。
- LED0闪烁指示程序运行。
-
高级定时器互补输出初始化函数
void atim_timx_cplm_pwm_init(uint16_t arr, uint16_t psc) {TIM_OC_InitTypeDef timx_oc_cplm_pwm = {0};g_timx_cplm_pwm_handle.Instance = TIM1; //定时器选择g_timx_cplm_pwm_handle.Init.Prescaler = psc; //定时器分频g_timx_cplm_pwm_handle.Init.Period = arr;g_timx_cplm_pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP; //定时器计数模式g_timx_comp_pwm_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; //CKD[1:0] = 10HAL_TIM_PWM_Init(&g_timx_cplm_pwm_handle); //初始化PWMtimx_oc_cplm_pwm.OCMode = TIM_OCMODE_PWM1; //模式选择PWM模式1timx_oc_cplm_pwm.OCPolarity = TIM_OCPOLARITY_HIGH; //OC1高电平有效timx_oc_cplm_pwm.OCNPolarity = TIM_OCPOLARITY_HIGH; //OC1N高电平有效timx_oc_cplm_pwm.OCIdleState = TIM_OCIDLESTATE_RESET; //当MOE = 0, OC1 = 1;timx_oc_cplm_pwm.OCNIdleState = TIM_OCNIDLESTATE_RESET;//当MOE = 0, OC1x = 1;HAL_TIM_PWM_ConfigChannel(&g_timx_cplm_pwm_handle, &timx_oc_cplm_pwm, TIM_CHANNEL_1);//设置死区参数g_sbreak_dead_time_config.OffStateRunMode = TIM_OSSR_DISABLE; //运行模式下的关闭状态选择g_sbreak_dead_time_config.OffStateIDLEMode = TIM_OSSI_DISABLE; //空闲模式下的关闭状态选择g_sbreak_dead_time_config.LockLevel = TIM_LOCKLEVEL_OFF; //寄存器锁定配置g_sbreak_dead_time_config.BreakState = TIM_BREAK_ENABLE; //断路输入使能控制g_sbreak_dead_time_config.BreakPolarity = TIM_BREAKPOLARITY_HIGH; //断路输入极性g_sbreak_dead_time_config.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE; //自动恢复输出使能控制HAL_TIMEx_ConfigBreakDeadTime(&g_timx_cplm_pwm_handle, &g_sbreak_dead_time_config);HAL_TIM_PWM_Start(&g_timx_cplm_pwm_handle, TIM_CHANNEL_1); //启动定时器的正常输出HAL_TIMEx_PWMN_Start(&g_timx_cplm_pwm_handle, TIM_CHANNEL_1); //启动定时器的互补输出 } -
定时器设置输出比较值死区时间
void atim_timx_cplm_pwm_set(uint16_t ccr, uint8_t dtg) {//设置比较寄存器的值__HAL_TIM_SET_COMPARE(&g_timx_cplm_pwm_handle, TIM_CHANNEL_1, ccr);//单独进行死区时间的设置g_sbreak_dead_time_config.DeadTime = dtg;HAL_TIMEx_ConfigBreakDeadTime(&g_timx_cplm_pwm_handle, &g_sbreak_dead_time_config); } -
主函数
int main(void) {uint8_t t = 0;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */key_init();//设置1khz的周期atim_timx_cplm_pwm_init(1000 - 1, 72 - 1);//设置TIM捕获比较寄存器值,从而控制占空比为70%atim_timx_cplm_pwm_set(700 - 1, 100);while(1){ t++;if(t > 50){t = 0;LED0_TOGGLE();}delay_ms(10);} } -
程序运行流程

-
程序运行结果

九、高级定时器PWM输入模式实验
1. PWM输入工作原理

- 确定定时器的时钟源:本代码使用内部时钟(CK_INT),时钟频率为72MHz,计数频率确定了测量精度。
- 确定PWM输入的通道:PWM输入模式下测量PWM,PWM信号输入只能从通道1或通道2输入。
- 确定IC1和IC2的捕获边沿:以通道 1(CH1)输入 PWM 为例,一般设置 IC1 捕获边沿为上升沿捕获,IC2 捕获边沿为下降沿捕获。
- 选择触发输入信号:选择TI1FP1或TI2FP2。
- 从模式选择:复位模式,在出现所选触发输入(TRGI)上升沿时,重新初始化计数器并生成一个寄存器更新事件。
- 读取一个PWM周期内计数器的计数个数,以及高电平期间计数个数,再结合计数器的计数周期,最终通过计算得到输入的PWM周期和占空比等参数。
2. 输入模式时序图

假设计数器的计数频率是72MHz,那我们就可以计算出PWM的周期、频率和占空比等参数。由计数器的计数频率为72Hz,可以得到计数器计一个数的时间是13.8ns(即测量的精度是13.8ns)。知道了测量精度,再来计算PWM的周期,PWM周期=(4+1)*(1/72000000)=69.4ns,那么PWM的频率就是14.4MHz。占空比= (2+1)/(4+1)=3/5(即占空比为60%)。
3. 相关寄存器
-
从模式控制寄存器(
TIMx_SMCR)

-
捕获/比较模式寄存器1/2(
TIMx_CCMR1/2)

-
捕获/比较使能寄存器(
TIMx_CCER)

-
捕获/比较寄存器1/2/3/4(
TIMx_CCR1/2/3/4)

-
DMA中断使能寄存器(
TIMx_DIER)

4. 高级定时器PWM输入模式实验配置步骤
-
配置定时器基础工作参数
HAL_TIM_IC_Init() -
定时器捕获输入MSP初始化
HAL_TIM_IC_MspInit() -
配置IC1/2映射、捕获边沿等
HAL_TIM_IC_ConfigChannel() -
配置从模式,触发源等
HAL_TIM_SlaveConfigSynchro() -
设置优先级,使能中断
HAL_NVIC_SetPriority() HAL_NVIC_EnableIRQ() -
使能捕获、捕获中断及计数器
HAL_TIM_IC_Start_IT() HAL_TIM_IC_Start() -
编写中断服务函数
TIMx_IRQHandler() -
编写输入捕获回调函数
HAL_TIM_IC_CaptureCallback()
-
函数具体功能
函数 主要寄存器 主要功能 HAL_TIM_IC_Init() CR1、ARR、PSC 初始化定时器基础参数 HAL_TIM_IC_MspInit() 无 存放NVIC、CLOCK、GPIO初始化代码 HAL_TIM_IC_ConfigChannel() CCMRx、CCER 配置通道映射、捕获边沿、分频、滤波等 HAL_TIM_SlaveConfigSynchro() SMCR、CCER 配置从模式、触发源、触发边沿等 HAL_TIM_IC_Start_IT() CCER、DIER、CR1 使能输入捕获、捕获中断并启动计数器 HAL_TIM_IRQHandler() SR 定时器中断处理公用函数,处理各种中断 HAL_TIM_IC_CaptureCallback() 无 定时器输入捕获回调函数,由用户重定义
4. 代码实现
-
功能:
首先通过TM3_CH2(PB5)输出PWM波。然后把PB5输出的PWM波用杜邦线接入PC6(定时器8通道1),最后通过串口打印PWM波的脉宽和频率等信息。通过LED1闪烁来提示程序正在运行。
-
通用定时器PWM输出初始化函数
void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc) {TIM_OC_InitTypeDef timx_oc_pwm_chy;g_timx_pwm_chy_handle.Instance = TIM3;g_timx_pwm_chy_handle.Init.Prescaler = psc;g_timx_pwm_chy_handle.Init.Period = arr;g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);timx_oc_pwm_chy.OCMode = TIM_OCMODE_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, TIM_CHANNEL_2);HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_2); } -
定时器输出PWM MSP初始化函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM3){GPIO_InitTypeDef gpio_init_struct;__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_TIM3_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_5;gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽复用 */gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */HAL_GPIO_Init(GPIOB, &gpio_init_struct);__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_TIM3_PARTIAL();} } -
PWM输入模式初始化函数
void atim_timx_pwmin_chy_init(void) {TIM_SlaveConfigTypeDef slave_config = {0};TIM_IC_InitTypeDef tim_ic_pwmin_chy = {0};g_timx_pwmin_chy_handle.Instance = TIM8; /* 定时器8 */g_timx_pwmin_chy_handle.Init.Prescaler = 0; /* 定时器预分频系数 */g_timx_pwmin_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */g_timx_pwmin_chy_handle.Init.Period = 65535; /* 自动重装载值 */HAL_TIM_IC_Init(&g_timx_pwmin_chy_handle);/* 从模式配置,IT1触发更新 */slave_config.SlaveMode = TIM_SLAVEMODE_RESET; /* 从模式:复位模式 */slave_config.InputTrigger = TIM_TS_TI1FP1; /* 定时器输入触发源:TI1FP1 */slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; /* 上升沿检测 */slave_config.TriggerFilter = 0; /* 不滤波 */HAL_TIM_SlaveConfigSynchro(&g_timx_pwmin_chy_handle, &slave_config);/* IC1捕获:上升沿触发TI1FP1 */tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_RISING; /* 上升沿检测 */tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_DIRECTTI; /* 选择输入端IC1映射到TI1 */tim_ic_pwmin_chy.ICPrescaler = TIM_ICPSC_DIV1; /* 不分频 */tim_ic_pwmin_chy.ICFilter = 0; /* 不滤波 */HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, TIM_CHANNEL_1);/* IC2捕获:下降沿触发TI1FP2 */tim_ic_pwmin_chy.ICPolarity = TIM_ICPOLARITY_FALLING; /* 下降沿检测 */tim_ic_pwmin_chy.ICSelection = TIM_ICSELECTION_INDIRECTTI; /* 选择输入端IC2映射到TI1 */HAL_TIM_IC_ConfigChannel(&g_timx_pwmin_chy_handle, &tim_ic_pwmin_chy, TIM_CHANNEL_2);HAL_TIM_IC_Start_IT(&g_timx_pwmin_chy_handle, TIM_CHANNEL_1);HAL_TIM_IC_Start(&g_timx_pwmin_chy_handle, TIM_CHANNEL_2); } -
定时器输入捕获MSP初始化函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM8){GPIO_InitTypeDef gpio_init_struct = {0};__HAL_RCC_TIM8_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();gpio_init_struct.Pin = GPIO_PIN_6;gpio_init_struct.Mode = GPIO_MODE_AF_PP;gpio_init_struct.Pull = GPIO_PULLDOWN;gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOC, &gpio_init_struct);/* TIM1/TIM8有独立的输入捕获中断服务函数 */HAL_NVIC_SetPriority(TIM8_CC_IRQn, 1, 3);HAL_NVIC_EnableIRQ(TIM8_CC_IRQn);} } -
定时器8输入捕获中断服务函数
void TIM8_CC_IRQHandler(void) {HAL_TIM_IRQHandler(&g_timx_pwmin_chy_handle); /* 定时器共用处理函数 */ } -
PWM输入模式重新启动捕获函数
void atim_timx_pwmin_chy_restart(void) {sys_intx_disable(); /* 关闭中断 */g_timxchy_pwmin_sta = 0; /* 清零状态,重新开始检测 */g_timxchy_pwmin_hval=0;g_timxchy_pwmin_cval=0;sys_intx_enable(); /* 打开中断 */ } -
定时器输入捕获中断处理回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM8){if(g_timxchy_pwmin_sta == 0){if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){g_timxchy_pwmin_hval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handle, TIM_CHANNEL_2) + 1 + 1;g_timxchy_pwmin_cval = HAL_TIM_ReadCapturedValue(&g_timx_pwmin_chy_handle, TIM_CHANNEL_1) + 1 + 1;g_timxchy_pwmin_sta = 1;}}} } -
主函数
int main(void) {uint8_t t = 0;double ht, ct, f, tpsc;HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */led_init(); /* 初始化LED */gtim_timx_pwm_chy_init(10 - 1, 72 - 1);TIM3->CCR2 = 3;atim_timx_pwmin_chy_init();while (1){delay_ms(10);t++;if (t >= 20) /* 每200ms输出一次结果,并闪烁LED0,提示程序运行 */{if (g_timxchy_pwmin_sta) /* 捕获了一次数据 */{printf("\r\n"); /* 输出空,另起一行 */printf("PWM PSC :%d\r\n", g_timxchy_pwmin_psc); /* 打印分频系数 */printf("PWM Hight:%d\r\n", g_timxchy_pwmin_hval); /* 打印高电平脉宽 */printf("PWM Cycle:%d\r\n", g_timxchy_pwmin_cval); /* 打印周期 */tpsc = ((double)g_timxchy_pwmin_psc + 1) / 72; /* 得到PWM采样时钟周期时间 */ ht = g_timxchy_pwmin_hval * tpsc; /* 计算高电平时间 */ct = g_timxchy_pwmin_cval * tpsc; /* 计算周期长度 */f = (1 / ct) * 1000000; /* 计算频率 */printf("PWM Hight time:%.3fus\r\n", ht); /* 打印高电平脉宽长度 */printf("PWM Cycle time:%.3fus\r\n", ct); /* 打印周期时间长度 */printf("PWM Frequency :%.3fHz\r\n", f); /* 打印频率 */ atim_timx_pwmin_chy_restart(); /* 重启PWM输入检测 */} LED1_TOGGLE(); /* LED1(GREEN)闪烁 */t = 0;}} }
声明:资料来源(战舰STM32F103ZET6开发板资源包)
- Cortex-M3权威指南(中文).pdf
- STM32F10xxx参考手册_V10(中文版).pdf
- STM32F103 战舰开发指南V1.3.pdf
- STM32F103ZET6(中文版).pdf
- 战舰V4 硬件参考手册_V1.0.pdf
相关文章:
STM32-10-定时器
STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG 文章目录 一、STM32 基础定时器1. 基本定时器简介2. 基本定时器框图3. 基本定时器相关寄存器4. 定时器溢出…...
今天说的什么好呢
先这样吧...
计算机网络-Traffic-Filter流量过滤策略
一、概述 为提高网络安全性,管理人员需要控制进入网络的流量,将不信任的报文丢弃在网络边界。所谓的不信任报文是指对用户来说存在安全隐患或者不愿意接收的报文。同时保证数据访问安全性,企业网络中经常会要求一些部门之间不能相互访问。 背…...
小白入职 必要熟悉 Git / tortoiseGit 工具
1.安装Git 1.1 了解Git Git是分布式版本控制系统,没有中央服务器的每个人的电脑就是一个完整的版本库,工作时无需联网可多人协作,只需把各自的修改推送给对方,就可以互相看到对方的修改了 分布式版本控制工具管理方式ÿ…...
春秋CVE-2022-23906
简介 CMS Made Simple v2.2.15 被发现包含通过上传图片功能的远程命令执行 (RCE) 漏洞。此漏洞通过精心制作的图像文件被利用。 正文 1.进入靶场2.进入登录界面,弱口令admin/123456 3.进入后台,文件上传点 4.上传一句话木马图片 5.复制图片…...
JavaFX安装与使用
前言 最近学习了javafx,开始时在配置环境和导包时遇到了一些麻烦,关于网上很多方法都尝试过了,现在问题都解决了,和大家分享一下我是怎么实现javafx的配置,希望大家可以通过这个方法实现自己的环境配置! 🙈个人主页: 心.c 🔥文章专题:javafx Ὁ…...
漫画|基于SprinBoot+vue的漫画网站(源码+数据库+文档)
漫画网站 目录 基于SprinBootvue的漫画网站 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大…...
python-项目实战
项目实战 1.外星人入侵小游戏 2.数据可视化 3.web应用开发 一、外星人入侵小游戏 需求: 开发大型项目时,做好规划后再动手编写项目很重要。规划可确保你不偏离轨道,从而提高项目成功的可能性。 在游戏《外星人入侵》中,玩家控制着一艘最…...
单片机原理及技术(一)—— 认识单片机(C51编程)
目录 一、单片机概述 1.1 什么是单片机 1.2 单片机的发展历史 1.3 单片机的特点 1.4 MCS-51 系列与 AT89S5x 系列单片机 1.4.1 MCS-51 系列单片机 1.4.2 AT89S5x 系列单片机 1.5 各种衍生品种的8051单片机 1.5.1 STC 系列单片机 1.5.2 C8051Fxxx 系列单片机 一、单片…...
白嫖的在线工具类宝藏网站清单,快点击进来收藏一波
简单整理了一下自己日常经常使用的10个免费工具网站,建议点赞关注收藏,快点分享给小伙伴们! 1.奶牛快传:用户体验更好的网盘工具。 https://cowtransfer.com/ 今年开始使用的一款网盘工具,和百度网盘类似,叫奶牛快传,如…...
【机器学习300问】97、机器学习中哪些是凸优化问题,哪些是非凸优化问题?
在机器学习的领域中,多数模型的参数估计问题实质上可以转化为优化问题。鉴于机器学习模型的多样性,不同的模型会对应着不同的损失函数,进而形成各具特色的优化问题。了解优化问题的形式和特点,对于提升我们求解模型参数的效率和准…...
两种盒模型
在CSS中,有两种主要的盒模型(Box Model),它们决定了元素的尺寸计算方式: 标准盒模型(W3C Box Model) 在标准盒模型中,元素的总宽度和总高度分别由以下几个部分组成: Cont…...
【C++】类型转换
目录 前言一、C语言中的类型转换二、为什么C需要四种类型转换三、C强制类型转换3.1 static_cast3.2 reinterpret_cast3.3 const_cast3.4 dynamic_cast3.5 RTTI 前言 本篇文章讲解的是C中对于C语言类型转换做出的一些更好的规范问题,同时也保证了在一些特殊场景下进…...
Redis RDB 持久化问题
前言 Redis 是内存数据库,它将自己的数据储存在内存里面,如果不想办法将储存在内存中的数据保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据也就没了。 因此,Redis 提供了 RDB 持久化功能,这个功能…...
windows 下nginx常用命令
1、启动,目录cmd,后 start nginx.exe 2.重新加载 nginx -s reload 3.查看状态 tasklist /fi “imagename eq nginx.exe” 4.关闭 nginx -s quit...
xjoi题库一级1-10段题解(c语言版)
xjoi题库一级一段 xjoi题库一级二段 xjoi题库一级三段 xjoi题库一级四段 xjoi题库一级五段...
1.int 与 Integer 的简单区别
蓝桥杯刷题从此开始: 第一题就是两个数的和,个人看来主要考察 int与integer 的区别; 这是我提交的答案,竟然会报错: import java.util.*; //输入A、B,输出AB。 class add {public static void main(String …...
单片机原理及技术(二)—— AT89S51单片机(一)(C51编程)
目录 一、AT89S51单片机的片内硬件结构 二、AT89S51的引脚功能 2.1 电源及时钟引脚 2.2 控制引脚 2.3 并行 I/O口引脚 三、AT89S51的CPU 3.1 运算器 3.1.1 算术逻辑单元(ALU) 3.1.2 累加器A 3.1.3 程序状态字寄存器(PSW)…...
某方protobuf闲谈
问题 当我们去看某方的时候,搜索了关键词svm,然后通过抓包查看,请求的Request Payload是一串看不懂的乱码,并且返回的数据也大部分是乱码 观察请求的Content-Type是application/grpc-web+proto,没错数据的传输是protobuf的形式了 protobuf的相关概念和原理,网上有很多教…...
专为汽车内容打造的智能剪辑解决方案
汽车内容创作已成为越来越多车主和汽车爱好者热衷的活动。然而,如何高效、便捷地将行车途中的精彩瞬间转化为高质量的视频作品,一直是困扰着广大用户的一大难题。美摄科技凭借其深厚的视频处理技术和智能分析能力,推出了专为汽车内容记录而生…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
