STM32定时器精讲(定时中断,PWM,输入捕获)

一.定时器原理(工作流程)

stm32的定时器分为基本定时器,通用定时器和高级定时器,本文主要介绍通用定时器.

基本定时器

在这里插入图片描述
基本定时器的时钟只能来源于内部时钟,上图画圈的部分是整个计时器最重要的部分,叫定时器的时基单元,我们从左往右看,首先是PSC预分频器,他可以对我们的内部时钟进行分频,比如我们的内部时钟的频率是72MHZ,假设PSC = 1,那就是2分频,所以分频之后的时钟频率就是就是36MHZ,如果PSC = 2,那就是3分频所以分频之后的时钟频率就是18MHZ,以此类推。因此预分频的值和实际的分频系数差1,然后预分频的值是16位的,所以预分频的最大值是65535,也就是65536分频,然后是计数器,计数器可以对分频后的时钟进行计数,计数时钟每来一个上升沿,计数器的值就+1,这个计数器也是16位的,所以计数器的值可以从0加到65535,再加的话,就会从0开始。然后我们要怎样产生中断呢?是不是只需要我们设置一个值,当计数器的值达到这个值的时候,就产生中断,这个值我们可以通过自动重载寄存器来配置,在上图中向上的箭头我们一般叫他更新中断,这个中断产生之后就会通完NVIC,这个时候我们只需要配置好NVIC定时器通道,那么更新的中断就能够通向CPU了,向下的箭头,代表产生更新事件,更新事件不会触发中断,但可以触发内部其他电路的工作,以上就是定时器全部的工作流程了。
我们可以通过一个图来加深一下理解,ARR就是自动重载寄存器的值,CLK的值从0不断自增,增到与ARR的值相等的时候,变为0,同时申请中断,再开始下一轮,不断循环。在这里插入图片描述

在这里插入图片描述

通用定时器

![在这里插入图片描述](https://img-blog.csdnimg.cn/0ebfac24b7d74a80b59d520f04ed477e.png

通用定时器看来就复杂多了是吧,其实通用定时器的工作流程跟基本定时器的工作流程基本是一样的,如上图黑色圈部分,只是通用定时器有三种工作模式,基本定时的工作模式是向上计数,通用计时器有向上计数,向下计数模式跟中央对齐模式,向下计数模式就是从重装值开始,往下减,减到0 之后,回到重装值,同时申请中断,然后进行下一次,中央对齐模式,就是从0开始,先向上自增,增到重装值,申请中断,然后再向下自减,减到0,再申请中断。通用定时器可选择的时钟源比较多,并且通用定时器有输入捕获跟输出比较功能,如上图红色圈内,我们可以发现通用定时器可选择TIMX_ETR,也就是外部时钟,也可选择其他定时器作为外部时钟,在配置的时候我们一般选择TIMX_ETR,蓝色圈部分是输出比较部分,可用于PWM波形的输出,棕色圈是输入捕获部分,可用于测量方波的频率等,由上图可知,输入捕获跟输出比较的寄存器是同一个,也就是说,同一通道的输入捕获跟输出比较不能同时工作。
在这里插入图片描述

计数器的频率
在这里插入图片描述
计数器的溢出频率
CK CNT_OV = CK CNT /(ARR + 1)
=CK PSC /(PSC + 1)/(ARR + 1)
其中,CK_PSC 为主频率,PSC为预分频器的值,ARR为自动重装器的值。
现在我们来举个例子,假设我们需要定时1秒钟,也就是说计数器的溢出频率为1HZ,假设我们的主频是72MHZ,这个时候我们在程序中配置PSC =7200 -1;CK PSC /(PSC + 1) = 10000 (这里说一下,1MZH = 1*10^6hz),然后我们只需要配置,ARR = 7200-1,就可以得出就是频率为1HZ.

TIM定时中断

主要函数

HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim) //启用定时器
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//回调函数,定时时间一到,就会进入到这个函数里面。
这里我们配置定时时间为1s,定时时间一到,我们让指定IO口的电平翻转
在程序中我们只需要启动一下TIM2_IT模式就可以了,下面来看一下cubemx的配置

在这里插入图片描述

n
在这里插入图片描述
NVIC也需要开启

注意!!!,基本定时器是挂在APB1上的,因此,我这里的时钟主频是90MHZ。.

主要代码

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_TIM2_Init();
  /* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM2)
	{
		HAL_GPIO_TogglePin(GPIOB,  GPIO_PIN_0);
	}
}

现象
在这里插入图片描述

TIM输出比较模式(PWM)

输出比较模式的介绍
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。
PWM的简介
脉冲宽度调制(PWM)是一种对模拟信号电平进行数字编码的方法,由于计算机不能输出模拟电压,只能输出0或5V的的数字电压值,我们就通过使用高分辨率计数器,利用方波的占空比被调制的方法来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么是5V(ON),要么是0V(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。

PWM的简单应用,比如说呼吸灯,按理来说灯只有亮灭两种状态,那怎么呈现出灯由亮到灭跟由灭到亮的过程呢,这个时候就可以使用PWM,我们让灯不断的亮不断的灭,这个时候,灯就会发出中等亮度的光,那我们是不是只需要让亮的时间大于灭的时间,这个时候灯光的强度就会变大,反之,灯光的强度就会变小,因此我们只需要调整好亮灭时间的比例,就可以得到不同程度的光。PWM调试电机也是这个道理。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述接下来我们来看一下PWM的工作模式 ,这里我们只介绍PWM模式1向上计数模式
![在这里插入图片描述](https://img-blog.csdnimg.cn/508701608af347b99645084f2a74198b.png

这里黄色线是ARR的值,计数器从0自增到99之后置0然后循环,红色线是CNT的值,这个时候我们可以看到当蓝色线小于红色线时(CNT<CRR),输出的是高电平(有效电平),当红色线小于蓝色线时(CNT>CCR),输出的是低电平(无效电平)
在这里插入图片描述
PWM频率Freg = CK PSC /(PSC + 1) /(ARR +1)
PWM占空比:Duty = CCR /(ARR +1)
PWM分辨率:Reso =1/(ARR +1).
配置PWM
在这里插入图片描述

时基单元的配置我们在定时中断那里已经讲清楚了,在程序中我们不配置他进入中断,配置他进入输出比较通道,然后选择极性就可以了

主要函数

这里我们使用PWM,配置一下LED呼吸灯

HAL_TIM_PWM_Start(TIM_HandleTypeDef htim, uint32_t Channel)//PWM的使能
__HAL_TIM_SetCompare(__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_3,duty);)在运行时设置TIM Capture Compare Register(CCR)值,duty 就是需要设置的值。
cubemx的配置
在这里插入图片描述
这里我们配置了定时器3通道三,时钟源选择外部时钟,设定频率f = 90
10^6 / 900 / 100 = 1kHZ
Pulse是在这个“时钟频率/预分频”速度里面计的数的脉冲速
在程序里面可以用这个程序修改它的脉冲数(这个其实就是CCR的值):
(__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_3,duty);)

主要代码

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_TIM3_Init();
  /* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);//PWM使能
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  
	  for (duty =0 ; duty <=100 ; duty++)
	  
	  {
		  __HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_3,duty);
		 HAL_Delay(10);
	  }
	  
	  for (duty =0 ; duty <=100 ; duty++)
	  {
		  __HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_3,100-duty);
		  HAL_Delay(10);
	  
	  }
	  
  }
void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 900-1;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 100-1;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 20;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}

这里简单说一下while 循环里面,这里我们使用了for循环,让duty的值不断的增加,然后传给__HAL_TIM_SetCompare函数,这个时候就可以不断使CCR的值自增,然后每次传完值之后,需要delay一下下,不然运行速度太快了,就会出现一闪一闪的现象,然后自减也是一样的.
再说一下这个100是怎么来的,因为我们ARR设置的值是100,也就是说计数器的值会从0自增到100,因此duty的最大值是100,此时的占空比就是100%。
现象
请添加图片描述

TIM输入捕获模式

介绍:
IC (Input Capture) 输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWM模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
工作流程:
在这里插入图片描述
圈中4个引脚是边沿信号输入引脚,一旦有信号输入进来,比如说上升沿,边沿检测器就会检测到,让输入捕获电路产生动作,让CNT的值锁存到CCR中。
与输出比较的区别
输入捕获的引脚是输入端口,输出比较的引脚是输出端口,输入捕获是检测输入信号,将CNT的值锁存到CCR中,输出比较是根据CNT和CCR的大小关系来执行输出动作.
接下来我们主要介绍,输入捕获电路是如何测量频率的
在这里插入图片描述
测量两个上升沿内的时间,然后取个倒数就是频率了,但是我们并且没有这种精度的测量仪器,那这个时间需要怎么去测量呢,这个时候,我们可以用计数器去测量,以标准频率fc计次,计数器从0开始,一直计到下一个上升沿停止得到N,记一个数的时间是1/fc,计N个数的时间就是N/fc,则频率fx = fc / N。
注意!!!在配置定时器的时候fc是计数器的频率,不是计数器的溢出频率(注意看上面的公式)。

主要函数

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//测量频率捕获定时器开启
HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);//读取CLK的计数值,就是x = fc / N中的N
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);//开启定时器2
接下来看看cubex的主要配置
在这里插入图片描述
在这里我配置的分频值为90,因为我这里的主频是90Mhz,因此定时器的计数频率为fc = 90*10^6/90.
ARR可以随便设置,这里没影响,极性选择上升沿触发也就是(RSING Edge).

主要代码

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_TIM2_Init();
  MX_FMC_Init();
  /* USER CODE BEGIN 2 */
  lcd_init();
  
 HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);//测量频率捕获定时器开启
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  lcd_show_num(200,400,frq ,4,32,BLACK);
  }
  /* USER CODE END 3 */
}
#include "stm32f4xx.h"                  // Device header
#include "IC_INPUT.H"
uint32_t ccrl_val = 0;
uint32_t  frq = 0;

 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
 {
	if(htim->Instance ==TIM2)
	{
		ccrl_val  =  HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);//获取定时器的计数值
		__HAL_TIM_SetCounter (htim,0);//定时器清0
		frq = (90000000 / 90) / ccrl_val;
	HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
	}
	
 }

在这里插入图片描述

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值