海北藏族自治州网站建设_网站建设公司_JavaScript_seo优化
2026/1/17 17:08:52 网站建设 项目流程

定时器归纳总页:



STM32——定时器-CSDN博客

三、通用定时器

3.1 通用定时器简介(F1)

通用定时器(F1):TIM2、3、4、5

主要特征:

16位 递增、递减、中心对齐计数器

16为预分频器(预分频系数:1~65536)

可用于触发DAC、ADC

更新事件、触发事件、输入捕获、输出比较时,会产生 中断/DMA请求(基本定时器只有 更新事件有中断/DMA请求)

4个独立通道,可用于:输入捕获、输出比较、输出PWM、单脉冲模式。

使用外部信号控制定时器且可实现多个定时器互连的同步电路。

(定时器级联:一个定时器的溢出是下一个定时器计数器计数的开始)

支持编码器和霍尔传感器电路等。

【免费】STM32F1系列参考手册-V10(中)_STM32F1系列寄存器详解资源-CSDN下载https://download.csdn.net/download/PinnsiR/91215140

3.2 通用定时器框图

TIM1不常用

左右两排为分时复用IO

3.3 计数器时钟源(重点)

简介

总共有这几类:

1类.内部时钟(CK_INT):来自外设总线APB提供的时钟

分频要不要乘二取决于APB1总线时钟是否分频

2类.外部时钟模式1:外部输入引脚(TIx),来自定时器 通道1(ch1)或者通道2(ch2) 引脚的信号

a.TI1F_ED(双边沿检测,一次脉冲记两次)

b.TI1FP1(单边沿检测,一次脉冲记一次)

c.TI1FP2(单边沿检测,一次脉冲记一次)

3类.外部时钟模式2:外部触发输入(ETR),来自可以复用为TIMx_ETR的IO引脚

4.内部触发输入(ITRx),用于芯片内部其它 通用、高级定时器级联

计数器时钟源寄存器设置方法(F1)

计数器时钟选择类型设置方法
内部时钟(CK_INT)设置 TIMx_SMCR 的 SMS = 000
外部时钟模式1:外部输入引脚(TIx)设置 TIMx_SMCR 的 SMS = 111
外部时钟模式2:外部触发输入(ETR)设置 TIMx_SMCR 的 ECE = 1(或者注1)
内部触发输入(ITRx)设置可参考STM32F10xxx参考手册_V10,14.3.14

ECE的注1:

选择外部时钟模式2的第二种方式。即 SMS = 111 ,TS= 111

SMS=111,TS=111,也就是ETR进来然后到ETRP滤波然后作为时钟源一条被TRGI选中

第一种方式,ECE = 1:

解释:记录到 N个低电平,输出低电平,又采样到 N个高电平才输出高电平。

上图寄存器中的 fDTS :

00:fDTS = fCK_INT 没经过分频的时钟源频率

01:fDTS = fCK_INT/2 ,2分频

10:fDTS = fCK_INT/4 ,4分频

外部时钟模式1

1.外部始终模式1TRGI设置为上升沿检测,需要在CC2P边沿检测时,如果配置下降沿检测,需要反向

外部时钟模式2

外部时钟模式2 选择方式:

内部触发输入(ITRx):定时器级联

3.4 通用定时器 中断实验

【免费】通用定时器中断实验工程MDK资源-CSDN下载https://download.csdn.net/download/PinnsiR/92299392

与基础定时器中断实验差不多

__HAL_TIM_GET_FLAG(&g_timx_handle, TIM_FLAG_UPDATE) 用于获取更新中断标记的UIF位

__HAL_TIM_CLEAR_IT(&g_timx_handle, TIM_IT_UPDATE); /* 清除定时器溢出中断标志位 */

3.5 通用定时器 PWM 输出 实验

3.5.1 通用定时器输出比较部分框图介绍

捕获的寄存器(F1)

F1有八种输出模式,主要配置PWM模式1,PWM模式2

强制清零:OC1CE配置为1,检测到ETRF高,OC1REF清零

通道输出的寄存器

3.5.2 通用定时器输出PWM原理

总结:(前提:定时器的计数频率没有发生变化)

PWM波周期或频率由ARR决定,PWM波占空比由CRRx决定。

3.5.3 PWM模式

寄存器选择pwm模式1与pwm模式2

pwm模式一图流:

3.5.4 通用定时器PWM输出实验配置步骤

3.5.4.1 步骤简介
步骤HAL 库函数
1.配置定时器基础工作参数HAL_TIM_PWM_Init()
2.对应的MSP callback函数初始化HAL_TIM_PWM_MspInit()配置NVIC、CLOCK、GPIO等
3.配置PWM模式和比较值等HAL_TIM_PWM_ConfigChannel()配置通道
4.使能输出并启动计数器HAL_TIM_PWM_Start()
5.修改比较值控制占空比(可选)__HAL_TIM_SET_COMPARE()占空比设置

6.使能通道预装载

(可选)

__HAL_TIM_ENABLE_OCxPRELOAD()
3.5.4.2 相关HAL库函数介绍

初始化函数与Base_Init功能一致

3.5.5 编程实战:通用定时器PWM输出实验

【免费】编程实战:通用定时器PWM输出实验_基础定时器PWM配置资源-CSDN下载https://download.csdn.net/download/PinnsiR/92479456

原理简介

更新事件触发:

PWM波周期频率计算,参考 “2.5 定时器溢出时间计算方法”:

Ft由板子的频率决定,已知F1为72MHz

PSC,ARR不固定,可配置其他的值。

pin脚选择

重映射寄存器

HAL库设置此寄存器的宏

代码简介:

MDK 工程中必须包含stm32f1xx_hal_tim.c(位于Drivers/STM32F1xx_HAL_Driver/Src目录),否则函数实现不会被编译:

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);/* 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); } }
TIM_HandleTypeDef g_timx_pwm_chy_handle; /* 定时器x句柄 */ void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc) { TIM_OC_InitTypeDef timx_oc_pwm_chy = {0}; /* 定时器PWM输出配置 */ 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; /* 设置比较值,此值用来确定占空比 */ /* 默认比较值为自动重装载值的一半,即占空比为50% */ 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 */ HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY); /* 开启对应PWM通道 */ }
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel) { ... ... /* Enable the Capture compare channel: 设置TIMx_CCER寄存器,使能通道配置为输出 */ TIM_CCxChannelCmd(htim->Instance, Channel, TIM_CCx_ENABLE); ... ... __HAL_TIM_ENABLE(htim); /* 设置TIMx_CR1,使能计数器 */ ... ... return HAL_OK; }
/*----- 捕获/比较寄存器 TIMx_CCR1\2\3\4 -----*/ #define __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__) \ (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCR1 = (__COMPARE__)) :\ ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCR2 = (__COMPARE__)) :\ ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCR3 = (__COMPARE__)) :\ ((__HANDLE__)->Instance->CCR4 = (__COMPARE__))) /*-----捕获/比较模式寄存器 TIMx_CCMR1\2 的OCxPE(1\2\3\4)寄存器位 -----*/ #define __HAL_TIM_ENABLE_OCxPRELOAD(__HANDLE__, __CHANNEL__) \ (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCMR1 |= TIM_CCMR1_OC1PE) :\ ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCMR1 |= TIM_CCMR1_OC2PE) :\ ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCMR2 |= TIM_CCMR2_OC3PE) :\ ((__HANDLE__)->Instance->CCMR2 |= TIM_CCMR2_OC4PE))
结构体介绍

示波器链接:

修改占空比的大小

通过__HAL_TIM_SET_COMPARE

3.6 通用定时器 输入捕获 实验

3.6.1 通用定时器输入捕获部分框图介绍

3.6.2 通用定时器输入捕获脉宽测量原理

3.6.3 通用定时器输入捕获实验配置步骤

通用定时器输入捕获配置步骤
配置步骤HAL 库函数解释
1.配置定时器基础工作参数HAL_TIM_IC_Init配置内容与HAL_TIM_Base_Init() 一致
2.定时器输入捕获MSP初始化HAL_TIM_IC_MspInit配置NVIC、CLOCK、GPIO等
3.配置输入通道映射、捕获边沿等HAL_TIM_IC_ConfigChannel
4.设置优先级,使能中断

HAL_NVIC_SetPriority

HAL_NVIC_EnableIRQ

5.使能定时器更新中断__HAL_TIM_ENABLE_IT计数器记满后会产生溢出,可在中断回调函数中++记录溢出次数
6.使能捕获、捕获中断以及计数器HAL_TIM_Start_IT
7.编写中断服务函数

TIMx_IRQHandler

(.s文件中可查)

调用TIM中断公共处理函数

HAL_TIM_IRQHandler

8.编写更新中断和捕获回调函数

HAL_TIM_PeriodElapsedCallback

计数器溢出更新中断回调函数,用于++溢出次数

HAL_TIM_IC_CaptureCallback

输入捕获中断回调函数,用于确认上升沿、下降沿输入捕获状态

3.6.4 编程实战 :通用定时器输入捕获实验

3.6.4.1 实验介绍

, 需要GPIO配置下拉。

F1设置1MHz计数频率,主板频率72MHz,需要分频系数72,也就是PSC=71

1MHz的作用:为了测量时间的精度,(1s计数1MHz个,一个计数的时间为1us)。

#include "./BSP/TIMER/gtim.h" TIM_HandleTypeDef g_timx_cap_chy_handle; /* 定时器x句柄 */ /* 通用定时器通道y 输入捕获 初始化函数 */ 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; /* 映射到TI1上 */ timx_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); /* 配置TIM5通道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 */ } /* 定时器 输入捕获 MSP初始化函数 */ void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM5) /*输入通道捕获*/ { GPIO_InitTypeDef gpio_init_struct; __HAL_RCC_TIM5_CLK_ENABLE(); /* 使能TIM5时钟 */ __HAL_RCC_GPIOA_CLK_ENABLE(); /* 开启捕获IO的时钟 */ 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); /* 抢占1,子优先级3 */ HAL_NVIC_EnableIRQ(TIM5_IRQn); /* 开启ITMx中断 */ } } /* 输入捕获状态(g_timxchy_cap_sta) * [7] :0,没有成功的捕获;1,成功捕获到一次. * [6] :0,还没捕获到高电平;1,已经捕获到高电平了. * [5:0]:捕获高电平后溢出的次数,最多溢出63次,所以最长捕获值 = 63*65536 + 65535 = 4194303 * 注意:为了通用,我们默认ARR和CCRy都是16位寄存器,对于32位的定时器(如:TIM5),也只按16位使用 * 按1us的计数频率,最长溢出时间为:4194303 us, 约4.19秒 * * (说明一下:正常32位定时器来说,1us计数器加1,溢出时间:4294秒) */ uint8_t g_timxchy_cap_sta = 0; /* 输入捕获状态 */ uint16_t g_timxchy_cap_val = 0; /* 输入捕获值 */ /* 定时器5中断服务函数 */ void TIM5_IRQHandler(void) { HAL_TIM_IRQHandler(&g_timx_cap_chy_handle); /* 定时器HAL库共用处理函数 */ } /* 定时器输入捕获中断处理回调函数 */ 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; /* 标记成功捕获到一次高电平脉宽 */ 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); /* 配置TIM5通道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); /* 定时器5计数器清零 */ 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); /* 定时器5通道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_RISING);/* 配置TIM5通道1上升沿捕获 */ g_timxchy_cap_sta |= 0X80; /* 标记成功捕获了一次 */ g_timxchy_cap_val = 0XFFFF; } else /* 累计定时器溢出次数 */ { g_timxchy_cap_sta++; } } } } }

3.7 通用定时器 脉冲计数 实验

3.7.1 脉冲计数实验原理

此实验相关的计数器时钟源:

2类.外部时钟模式1 :定时器 通道1(ch1)或者通道2(ch2) 引脚的信号

3类.外部时钟模式2:复用为TIMx_ETR的IO引脚

外1的实验原理:

CK_PSC输入后 不做分频(每来一个脉冲就一个数)

外2的实验原理:

3.7.2 通用定时器脉冲计数实验配置步骤

步骤HAL 库函数主要寄存器作用
1.配置定时器基础工作参数HAL_TIM_IC_Init()CR1、ARR、PSC初始化定时器基础参数
2.定时器输入捕获MSP初始化HAL_TIM_IC_MspInit()配置NVIC、CLOCK、GPIO
3.配置定时器从模式HAL_TIM_SlaveConfigSynchro()SMCR、CCMRx、CCER配置定时器从模式、触发选择、分频、滤波等
4.使能输入捕获并启动计数器HAL_TIM_IC_Start()CCER、CR1使能输入捕获、启动计数器
5.获取计数器的值__HAL_TIM_GET_COUNTER()CNT
6.设置计数器的值__HAL_TIM_SET_COUNTER()CNT一般用于清零

3.7.3 编程实战:通用定时器脉冲计数实验

Proj-10-TIM-脉冲计数实验https://download.csdn.net/download/PinnsiR/92546261

初始化函数

void gtim_timx_cnt_chy_init(uint16_t psc) { GPIO_InitTypeDef gpio_init_struct; TIM_SlaveConfigTypeDef tim_slave_config = {0}; GTIM_TIMX_CNT_CHY_CLK_ENABLE(); /* 使能TIMx时钟 */ GTIM_TIMX_CNT_CHY_GPIO_CLK_ENABLE(); /* 开启GPIOA时钟 */ g_timx_cnt_chy_handle.Instance = GTIM_TIMX_CNT; /* 定时器x */ g_timx_cnt_chy_handle.Init.Prescaler = psc; /* 定时器分频 */ g_timx_cnt_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */ g_timx_cnt_chy_handle.Init.Period = 65535; /* 自动重装载值 */ HAL_TIM_IC_Init(&g_timx_cnt_chy_handle); gpio_init_struct.Pin = GTIM_TIMX_CNT_CHY_GPIO_PIN; /* 输入捕获的GPIO口 */ 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(GTIM_TIMX_CNT_CHY_GPIO_PORT, &gpio_init_struct); /* 从模式:外部触发模式1 */ tim_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; /* 从模式:外部触发模式1 */ tim_slave_config.InputTrigger = TIM_TS_TI1FP1; /* 输入触发:选择 TI1FP1(TIMX_CH1) 作为输入源 */ tim_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING; /* 触发极性:上升沿 */ tim_slave_config.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; /* 触发预分频:无 */ tim_slave_config.TriggerFilter = 0x0; /* 滤波:本例中不需要任何滤波 */ HAL_TIM_SlaveConfigSynchro(&g_timx_cnt_chy_handle, &tim_slave_config); HAL_NVIC_SetPriority(GTIM_TIMX_CNT_IRQn, 1, 3); /* 设置中断优先级,抢占优先级1,子优先级3 */ HAL_NVIC_EnableIRQ(GTIM_TIMX_CNT_IRQn); __HAL_TIM_ENABLE_IT(&g_timx_cnt_chy_handle, TIM_IT_UPDATE); /* 使能更新中断 */ HAL_TIM_IC_Start(&g_timx_cnt_chy_handle, GTIM_TIMX_CNT_CHY); /* 开始捕获TIMx的通道y */ }

从模式选择宏:

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询