0%

TIM入门

Main Takeaway

Following 哈工深上传到B站的电控组培训来入门robomaster电控组,我购买了普中科技玄武套餐开发板作为硬件。

本篇介绍我学习TIM的见闻

TIM

简介

  • 定时器Timer分类:STM32中的TIM分为三大类:基本定时器(TIM6和TIM7)、通用定时器(TIMx)和高级控制定时器(TIM1和TIM8)

    • 基本定时器具有最基本的定时功能,可编程控制定时周期,计数器溢出(即设置定时间隔,然后自动重装载为0,重新计数)能产生中断/DMA请求。

    • 通用定时器除了基本定时器的功能外,还可配置计数器装载方式,具有4个独立通道,每个通道均可进行输入捕获、输出比较、PWM输出以及单脉冲模式。中断源更多(向上溢出/向下溢出、计数器初始化/启动/停止、输入捕获、输出比较等) HAL_Delay(ms);

    • 高级定时器在通用定时器的基础上,还增加了数个功能:可输出嵌入死区时间的互补PWM、允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器、刹车输入信号可以将定时器输出信号置于复位或者一个已知状态,中断源也多了一个刹车信号输入。

      Notes:可编程定时器的主要部分是一个带有自动重装载的16位累加计数器,计数器的时钟通过一个预分频器得到。软件可以读写计数器、自动重装载寄存器和预分频寄存器,即使计数器运行时也可以操作。

  • 死区:为了避免功率元件烧毁而产生的的一段延迟时间。

    通常,大功率电机、变频器等,末端都是由大功率管、IGBT等元件组成的H桥或3相桥。每个桥的上半桥和下半桥是是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制极时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有关断,造成功率元件烧毁。死区就是在上半桥关断后,延迟一段时间再打开下半桥或在下半桥关断后,延迟一段时间再打开上半桥,从而避免功率元件烧毁。这段延迟时间就是死区。(就是上、下半桥的元件都是关断的)死区时间控制在通常的低端单片机所配备的PWM中是没有的。

  • TIM的刹车功能是一种用于控制PWM输出的技术,它可以在检测到外部信号或者内部事件时,立即停止PWM输出,并将输出管脚置为预设的状态,以避免负载端出现异常或者危险的情况。

基本定时器介绍

TIM6和TIM7为基本定时器,两者资源相互独立不共享。两者各有一个可编程定时器。

image-20230821151535921

时基单元

时基单元是一种用于产生定时或计数功能的模块。

时基单元包含:

  • 计数器寄存器(TIMx_CNT):它可以对分频后的时钟信号进行计数,从而实现定时或计数功能。计数器的计数方向由TIMx_CR1寄存器的DIR位设置,它可以是向上计数或向下计数。计数器的当前值由TIMx_CNT寄存器保存,它是一个16位的只读寄存器。

  • 预分频寄存器(TIMx_PSC):它可以对输入的时钟信号进行分频,从而降低计数器的计数速度,增加计数范围。分频器的分频比由TIMx_PSC寄存器设置,它是一个16位的预装载寄存器,即它有一个影子寄存器和一个预装载寄存器,当发生更新事件时,预装载寄存器的值会被复制到影子寄存器中。

  • 自动重装载寄存器(TIMx_ARR):它可以为计数器设置一个最大值或最小值,当计数器达到这个值时,会发生溢出或下溢,并触发更新事件,该事件可用于产生中断。自动重装载寄存器由TIMx_ARR寄存器设置,它也是一个16位的预装载寄存器,具有影子寄存器和预装载寄存器。

    Tips:自动重装载寄存器是预加载的,每次读写自动重装载寄存器时,实际上是通过读写预加载寄存器实现。根据TIMx_CR1寄存器中的自动重装载预加载使能位(ARPE),写入预加载寄存器的内容能够立即或在每次更新事件时,传送到它的影子寄存器。

预分频

预分频可以以系数介于1至65536之间的任意数值对计数器时钟分频。它是通过一个16位寄存器(TIMx_PSC)的计数实现分频。因为TIMx_PSC控制寄存器具有缓冲,可以在运行过程中改变它的数值,新的预分频数值将在下一个更新事件时起作用。(随时可以写)

计数器模式

计数器从0累加计数到自动重装载数值(TIMx_ARR寄存器:AutoReload Register),然后重新从0开始计数并产生一个计数器溢出事件。每次计数器溢出时可以产生更新事件。ARR=36:

image-20230821153155929
image-20230821153204740

Tips:ARR没有预装载则为FF,只有向上计数

通用定时器介绍

在STM32F10x系列中,通用定时器有TIM2、TIM3、TIM4和TIM5,每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作。

image-20230821153334967

计数器模式

  • 向上计数:当TIMx_CR1寄存器中的DIR位为低的时候执行向上计数。
  • 向下计数:当TIMx_CR1寄存器中的DIR位为高时时候执行向下计数。
  • 中央对齐模式(向上/向下计数)
image-20230821153406553

输入捕获模式

在输入捕获模式下,当检测到信号上相应的边沿后,计数器的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中,同时产生输入捕获事件,该事件可以被用于产生中断。

PWM模式

脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率(周期)、由TIMx_CCRx寄存器确定占空比的信号。

image-20230822174411921

Tips:eg TIMx_CCRx为8,则计数器小于8为低电平,大于等于8为高电平

OCxREF极性与电平相反,CCxIF是中断

在PWM模式(模式1或模式2)下, TIMx_CNT和TIMx_CCRx始终在进行比较, (依据计数器的计数方向)以确定是否符合TIMx_CCRx≤TIMx_CNT或者TIMx_CNT≤TIMx_CCRx。

TIM中断

  • 定时器溢出中断

  • 定时器输入捕获中断

TIM重要寄存器

  1. 计数器(TIMx_CNT)

  2. 预分频器(TIMx_PSC)

  3. 自动重装载寄存器(TIMx_ARR)

  4. 捕获/比较寄存器(TIMx_CCRx)

TIM API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
//IC:input capture
HAL_StatusTypeDef HAL_TIM_IC_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel)

HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)

HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)

HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)

HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)

HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)

HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim)

1
2
3
4
5
6
7
8
9
10
11
/**
* @brief Period elapsed callback in non-blocking mode
* @param htim TIM handle
* @retval None */
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed, the HAL_TIM_PeriodElapsedCallback could be implemented in the user file */
}
//溢出中断
1
2
3
4
5
6
7
8
9
10
11
12
/**
* @brief Input Capture callback in non-blocking mode
* @param htim TIM IC handle
* @retval None
*/
__weak void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed, the HAL_TIM_IC_CaptureCallback could be implemented in the user file */
}
//输入捕获的中断

实验

实现简单定时实验

CubeMX

预分频PSC : 72-1(从0开始计数所以要减1)

counter period: 20000-1

1
2
3
4
5
6
7
8
9
10
11
12
13
HAL_TIM_Base_Start_IT(&htim6);//TIM6,7是基本定时器

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static int cnt = 0;
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_All, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOF, showNum(cnt), GPIO_PIN_RESET);
cnt++;
if (cnt == 9)
{
cnt = 0;
}
}

实现PWM输出实验

输出指定周期和占空比的PWM波,驱动蜂鸣器。

CubeMX

通用定时器:要看原理图选择是哪个channel

clock source:internal clock

默认的串口要修改成我们想要设置为TIM的那个串口

Tips:无TIM可以短接

My fault:PSC预分频设置为0无声音。。。

1
2
3
4
TIM4->ARR = M_Do;
TIM4->CCR3 = TIM4->ARR >> 1;
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
//一打开就开始运行,要写在main function中

实现输入捕获实验

读取上一个实验中输出的PWM一个周期内的高电平时间和低电平时间。

1
2
int tim4_last_count, tim4_count, low_time, high_time;
// 定时器输入捕获中断回调函数
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
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
static uint8_t flag = 0; //0代表上升沿触发;1代表下降沿触发
tim4_last_count = tim4_count;
if(flag == 0)
{
tim4_count = TIM4->CCR4;
// 计算低电平时间
low_time = tim4_count - tim4_last_count;
if(low_time < 0) low_time += 19999;
else low_time += 1;
// 修改输入捕获触发方式为下降沿触发
TIM_RESET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_4);
TIM_SET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_4, TIM_ICPOLARITY_FALLING);
flag = 1;
}
else if(flag == 1)
{
tim4_count = TIM4->CCR4;
// 计算高电平时间
high_time = tim4_count - tim4_last_count+1;
// 修改输入捕获触发方式为上升沿触发
TIM_RESET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_4);
TIM_SET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_4, TIM_ICPOLARITY_RISING);
flag = 0;
}
}

Tips:project中没有输入捕获的回调函数,必须自己写

计数器从0开始计数(有时需要+1)

References