STM32————TIM定时器

【STM32】HAL库 STM32CubeMX教程七—PWM输出(呼吸灯)_stm32 hal pwm-CSDN博客

STM32CubeIde中互补PWM配置项的详细解读_ch idle state-CSDN博客 基于上述博客以及keyskingSTM32教程写的个人学习文档 【【STM32入门教程】应该是全B站最好的STM32教程了!!】https://www.bilibili.com/video/BV12v4y1y7uV?vd_source=5a0790755035f26a67935abfbfcdfd5b

定时器简介

HAL库开启定时器的基本函数

开启定时器

1
2
HAL_TIM_Base_Start(&htim1);//仅开启定时器
HAL_TIM_Base_Start_IT(&htim1);//开启定时器和中断
1
2
HAL_TIM_Base_Stop(&htim1);//关闭定时器
HAL_TIM_Base_Stop_IT(&htim1);//既关闭定时器,同时关闭中断

框架

解释整个TIM外设的构成

计数信号来源

有内部时钟以及外部时钟

内部时钟模式

f103c8t6中,TIM1是高级定时器,TIM2TIM3TIM4是通用计时器

CubeMX参数配置

  1. Prescaler:预分频,实际分频数是number+1
  2. Counter Mode:计数模式设置
  3. Counter Period:自动重装载计数器计数值
  4. Internal Clock Division:内部时钟预分频
  5. Repetiton Counter:重复计数器 (RCR -8 bits),属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出 PWM 的个数,与内部时钟模式无关
  6. auto-reload preload:是否开启影子寄存器模式

还需要开启定时器更新中断

代码实现

用的PA2GPIO输出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {//中断回调函数
	if( htim == &htim1 ) {
		HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_2);
	}
}

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_TIM1_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

外部时钟模式

【【STM32】动画讲解定时器外部时钟 & 实战传送带测速装置】https://www.bilibili.com/video/BV1N94y1u7Uz?vd_source=5a0790755035f26a67935abfbfcdfd5b

__HAL_GET_COUNTER(&htim)获取计数值

外部时钟模式2

在Clock Source处选择

注意外部时钟的滤波器Clock Filter,输入滤波 输入滤波,极性选择,预分频器

采样频率等于内部时钟的频率

一般推荐选择1110(15)

外部时钟模式1

通过定时器的Slave Mode 进行选择 启用从模式,选择外部时钟模式1

选择Trigger Source时,就是选择什么方式来外部计数 就是选择触发器的来源 TI_ED是双边沿触发,且只能是双边沿触发

使用外部计数ETR

  1. 可以在外部时钟模式1下,Trigger Source选择ETR1 芯片上会有引脚被设置为ETR1

  2. 直接选择外部时钟模式2,引脚上会自动有一个ETR2

关于定时器的事件更新中断

关于定时器中断 计数值到达自动重装载值时,触发更新中断 在Cube中开启global interrupt

关于MX_TIM2_Init()启动时会将中断标志位置1

在MX_TIM2_Init()时,会将定时器更新中断标志位置1,在调用HAL_TIM_Base_Start_IT后,NVIC会检测到更新中断标志位被置1,会立马触发中断

在HAL_TIM_Base_Start_IT前选择下面两个函数其中一个写上即可

事件更新中断的逻辑

先是NVIC中断向量表查找到TIM2_IRQhandler,在该函数中,调用了HAL_TIM_IRQhandler函数 其中的事件更新处理的代码(HAL库中HAL_TIM_IRQHandler中的处理事件更新中断的代码) 判断标志位,判断是否开启事件更新中断,清零标志位,调用HAL_TIM_PeriodElapsedCallback函数

定时器的从模式

【【STM32】一看就懂的定时器从模式讲解】https://www.bilibili.com/video/BV1mU421o7vt?vd_source=5a0790755035f26a67935abfbfcdfd5b

定时器从模式

  1. Reset Mode 复位模式
  2. Gate Mode 门模式
  3. Trigger Mode 触发模式

复位模式

设定为复位模式时

  1. 选取计数信号,计数信号可以时内部时钟,也可以是外部时钟模式2(不是从模式控制器下外部时钟模式1)
  2. 触发器的信号,每出现一次,执行一次复位操作(向上计数模式恢复为0,向下计数模式恢复为自动重装载值) 例子:选取计数信号为内部时钟,计数器不断计数,当触发器信号来临时(TI1的TIFP1检测到信号上升沿),则触发一次更新事件,计数器值复位

注意:如果开启定时器的事件更新中断,触发器信号也会触发事件更新中断

复位模式下的从模式控制器,在接收到触发信号后,就会让计数器重新开始计数,并且会触发定时器更新中断

如何判断事件更新中断的产生原因

在复位模式中,需要区分事件更新中断是触发信号的复位导致还是自动挡重装载时导致

从模式收到触发信号后,会设置触发器中断标志位,可以借此来区分中断原因

使用该函数来获取触发器中断标志位

1
__HAL_TIM_GET_FALG(htim,TIM_FLAG_UPDATE)//可以获取定时器对应标志位的值

TIM_FLAG_TRIGGER是触发器中断标志位

1
__HAL_TIM_GET_FLAG(htim,TIM_FLAG_TRIGGER)

使用上述语句可以获取其标志位 使用时需要注意,HAL库为了方便我们判断,并不会对该标志位清零,所以在获取标志位的值后,需要对其进行清零

1
2
3
if(__HAL_TIM_GET_FLAG(htim,TIM_FLAG_TRIGGER)==SET) {
	__HAL_TIM_CLEAR_FLAG(htim,TIM_FLAG_TRIGGER);
}

HAL_TIM_PeriodElapsedCallback回调函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void HAL_TIM_PeriodElapsedCallback( TIM_HandleTypeDef *htim ) {
	if( htim == &htim2 ) {
		if( __HAL_TIM_GET_FLAG(htim,TIM_FLAG_TRIGGER) == SET ) {//获取触发标志位,用来区分复位引起的中断还是自动重装载引起的中断
		__HAL_TIM_CLEAR_FLAG(htim,TIM_FLAG_TRIGGER);
		HAL_UART_Transmit( &huart2 , (uint8_t*)triggerMsg , strlen(triggerMsg) , 100 );
		}
		else {
			HAL_UART_Transmit( &huart2 , (uint8_t*)updateMsg , strlen(updateMsg) , 100 );
		}
	}
}
关于MX_TIM2_Init()启动时会将中断标志位置1

在MX_TIM2_Init()时,会将定时器更新中断标志位置1,在调用HAL_TIM_Base_Start_IT后,NVIC会检测到更新中断标志位被置1,会立马触发中断

在HAL_TIM_Base_Start_IT前选择下面两个函数其中一个写上即可

事件更新中断的逻辑

先是NVIC中断向量表查找到TIM2_IRQhandler,在该函数中,调用了HAL_TIM2_IRQhandler函数 其中的事件更新处理处的代码(HAL库中HAL_TIM_IRQHandler中的处理事件更新中断的代码) 判断标志位,判断是否开启事件更新中断,清零标志位,调用HAL_TIM_PeriodElapsedCallback函数

门模式

如果TI1的TI1FP1为上升沿检测,则是当触发信号是高电平时,时钟信号可以正常进入定时器,定时器能正常计数 当触发信号时低电平时,门关闭,时钟信号不能正常进入定时器,定时器停止计数 若将触发器的极性改为检测下降沿的话,门的控制作用则相反 触发器的极性选择

需要注意,在门模式情况下,上升下降沿的时刻,也会将触发器中断标志位置1,但是不会触发事件更新中断(因为没有对计数值进行复位,就不会触发事件更新中断)

触发模式

在检测到设定的边沿后,让定时器开始计数 开始后不能设定停止 触发模式仅能启动定时器,并不能停止计数器计数

一般配合计时器的单脉冲模式使用 单脉冲模式,是指计数器计数到重装载计数值后,就停止计数(不再循环计数)

一般需要勾选单脉冲模式

三种模式的总结

Trigger Source 触发源的滤波器设置

在有触发源的时候,对触发源的信号的滤波设置

定时器的输入捕获

软件层面上的模拟

在软件层面检测Echo端的电平高低,进行计时,到那时再极高精度要求的情况则 力不足

输入捕获的概括

硬件在检测到上升或者下降沿时,就记录计数器值到捕获寄存器

输入捕获的运行机制

在TI1检测到上升沿时,捕获寄存器立即复制计数器的值 还可以开启输入捕获中断,输入捕获后,启动中断,可以快速处理捕获寄存器上的值

一个通道只能进行一种边沿检测 捕获的模式

注意:TI3和TI4没有接入从模式控制器中

TI1和TI2是一对,可以相互借用 TI3和TI4是一对,可以相互借用

Cube上的配置

注意设置边沿检测

打开捕获中断

启动,该例子中是需要在CHANNEL4捕获到后进行处理,所以CHANNEL44开启了中断 输入捕获的开启

可能遇到的问题 ![[Pasted image 20250105120132.png]] 用SET_COUNTER来清零一下

中断回调函数

1
HAL_TIM_IC_CaptureCallback(htim);

回调函数的代码编写 判断是否是TIM1,判断是否是TIM1的4通道(HAL_TIM_ACTIVE_CHANNEL_4) 再读取指定寄存器的值

定时器的输出比较模式

较为鸡肋,对这些模式能理解其行为即可

定时器的PWM

【STM32】HAL库 STM32CubeMX教程七—PWM输出(呼吸灯)_stm32 hal pwm-CSDN博客

STM32CubeIde中互补PWM配置项的详细解读_ch idle state-CSDN博客

PWM

脉冲宽度调制,用数字信号去模拟 模拟信号

PWM模式

  1. PWM模式1 是 计数器值 小于 比较器值 时输出有效电平
  2. PWM模式2 是 计数器值 大于 比较器值 时输出有效电平

Cube配置

为实现一个呼吸灯,进行以下配置 PWM的频率为1000Hz,最大计数值为1000-1

基础时钟配置

预分频器值,计数模式选择(向上计数模式,向下计数模式,中央对齐模式),自动重装载值,内部时钟分频,重复计数器值,是否开启影子寄存器

PWM配置

  1. Mode:选择PWM模式
  2. Pulse:设置比较寄存器的值
  3. Output compare preload:是否开启影子寄存器
  4. Fast Mode:是否需要输出非常高频的PWM信号
  5. CH Polarity:设置有效电平极性
  6. CH Idle State:空闲时,PWM通道的输出

HAL库PWM常用函数

1
2
3
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//开启PWM
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);//关闭PWM
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,num);//设置比较寄存器的值

使用PWM控制流水灯 PWM的频率为1000Hz,最大计数值为1000-1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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_TIM1_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		for( int i = 0 ; i < 1000 ; ++ i ) {
			__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,i);
			HAL_Delay(0);
		}
		for( int i = 1000-1 ; i >= 0 ; -- i ) {
			__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,i);
			HAL_Delay(0);
		}
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

编码器的使用

待完成

experience
使用 Hugo 构建
主题 StackJimmy 设计