STM32CubMX自学笔记(五)---定时器

前景回顾

上一节主要介绍了在STM32CubMx中如何配置中断,并且如何使用其中的中断函数,首次提到了回调函数这个概念,这一小节,我们在此基础上实现通过定时器来实现。。。。。

主要介绍

定时器功能:定时、输出比较、输入捕获、互补输出
定时器分类:基本定时器、通用定时器、高级定时器
定时器资源:STM32F429有2个高级定时器、10个通用定时器、2个基本定时器
在这里插入图片描述
基本定时器功能简介
1-计数器16bit,只能向上计数,只有TIM6和TIM7
2-没有外部的GPIO,是内部资源,只能用来定时
3-时钟来自PCLK1,可实现1~65536分频

我们知道时钟就是单片机的心脏,并且,使用单片机万万离不开时钟,可以说时钟是单片机内容的重中之重,之前配置文件时,我们都没有介绍时钟这一模块,在这里,将要花费大量篇幅介绍STM32中的时钟小节。关于时钟的基本概念请转至时钟超详细讲解。这里还是主要对STM32CubMx中的时钟进行介绍。

工程配置-基本定时器

首先进入软件界面,使能HSE(高速时钟)和LSE(低速时钟),使能完成之后进入Clock Configuration界面。
在这里插入图片描述

系统时钟图介绍

下图为STM32F407ZGT6的时钟树界面。以系统时钟SYSCLK为界限划分左中右。我们可以清晰的看到左侧部分系统的时钟源有LSE(低速外部时钟)、HSE(高速外部时钟),系统内部有LSI(低速内部时钟)、HSI(高速内部时钟)。箭头指向不同的地方,是为不同的外设提供时钟信号。
中间部分系统时钟源(SYSCLK)来源有3处,HSI,HSE,PLLCLK锁相环。PLL锁相环是一个倍频器,可以把频率低的时钟经过乘除运算放大成为频率高的时钟。下图中PLL锁相环将25MHz的HSE倍频成为了168MHz的高速时钟。
右侧将得到的系统时钟在经过预分频器AHB处理得到了HCLK,HCLK再通过APB1和APB2预分频器将时钟分配给外设。如APB1外设时钟,APB1定时器时钟、APB2外设时钟、APB2定时器时钟。
在这里插入图片描述

配置时钟有一个原则,就是用到哪些外设就配置哪些时钟。下图为定时器1-14所挂载在时钟树上的位置,在本次实验中我们用到了timer6,可以看到timer6挂载在APB1上,而配置的APB1时钟为84MHz。
在这里插入图片描述
在这里插入图片描述

系统时钟设置

通用定时器的工作原理:
首先,定时器的时钟信号送入16位可编程预分频器(Prescaler),该预分频器的系数为0-65535之间的任意数值,预分配器溢出之后,会向16位的主计数器(Counter Period)发送一个脉冲信号。
预分频器,实质上是一个加法计数器,预分频系数就是加计数的溢出值。
定时器一个周期产生的时间我们如何计算呢?下面以timer6为例,具体配置细节。
先介绍定时器发生中断时间的计算方法:
定时器时间=(Prescaler+1)X(Counter Period)X1/定时器时钟频率 单位:秒/s
这里我们配置Prescaler为8400-1,Counter Period为5000-1,可以得到0.5s的计时时间,同时也要使能自动重装载。
在这里插入图片描述

同样的这里我们配置Prescaler为8400-1,Counter Period为2000-1,可以得到0.2s的计时时间。
在这里插入图片描述时钟初始化配置完成,紧接着要使能两个定时器中断,如下图所示,至此,工程配置完毕,可以生成系统文件了。
在这里插入图片描述

系统代码编写

观察生成的系统文件。

void MX_TIM6_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 8399;
  //预分频设置,就是将84MHz的系统时钟均分成8400份,得到一份的时间为0.1ms
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 1999;		//计数器设置为2000,2000*0.1ms=0.2s
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

依照惯例,首先打开stm32f4xx__it.c文件,在中断函数里面追溯根源,找到中断回调函数。
在这里插入图片描述或者在hal库的定时器的头文件找到回调函数,复制到主函数对它进行重写。
在这里插入图片描述
main.c函数中添加如下代码:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM6) //是否是定时器6触发中断
	{
		HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);//翻转LED0的电平
	}
	
	if(htim->Instance==TIM7)//是否是定时器7触发中断
	{
		HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);//翻转LED1的电平
	}
}

在main函数中添加:

HAL_TIM_Base_Start_IT(&htim6);//启动定时器中断6
HAL_TIM_Base_Start_IT(&htim7);//启动定时器中断7

完成配置

代码验证

我们将代码下载到开发板上,观察现象,发现LED0按照定时器6设置的时间翻转。LED1按照定时器7设置的时间翻转。

工程配置2-高级定时器输入捕获(来自野火)

【 !】功能简介:
使用STM32的高级控制定时器PWM输入捕获模式,测量PWM波形频率和周期。
学习目的:学会使用高级控制定时器输入捕获功能,以及通用定时器PWM输出功能。
【 !】实验操作:
电脑端使用串口调试助手,选择电脑与STM32相连的COM口,设置为115200-N-8-1,
根据硬件设计内容结合软件设计的引脚宏定义参数,用杜邦线连接通用定时器
PWM输出引脚和高级控制定时器的输入捕获引脚。
【*】 引脚分配
高级控制定时器捕获输入引脚:
IC <—> PC6
通用定时器PWM输出引脚:
OC <—> PA15
时钟配置
在这里插入图片描述TIM2生成PWM定时器配置:
时钟来源选择的是内部时钟,产生PWM的是定时器2的通道1。时钟源是APB2 84Mhz。

在这里插入图片描述
TIM8定时器输入捕获配置:

在这里插入图片描述1、复位模式:当触发信号产生变化的时候,计数器与预分频器可以重新初始化。
2、选择触发源TI1FP1,是因为通道有两个触发源还有一个是2的。通道1配置为输入捕获上升沿,通道2配置为输入捕获下降沿。
在这里插入图片描述

系统代码生成

PWM输出配置:
static void TIM_PWMOUTPUT_Config(void)
{	
	TIM_OC_InitTypeDef TIM_OCInitStructure;
	// 开启TIMx_CLK,x[2,3,4,5,12,13,14] 
	GENERAL_TIM_CLK_ENABLE(); 
	/* 定义定时器的句柄即确定定时器寄存器的基地址*/
	TIM_PWMOUTPUT_Handle.Instance = GENERAL_TIM;
	/* 累计 TIM_Period个后产生一个更新或者中断*/		
	//当定时器从0计数到9999,即为10000次,为一个定时周期
	TIM_PWMOUTPUT_Handle.Init.Period = 10000-1;
	// 高级控制定时器时钟源TIMxCLK = HCLK=108MHz 
	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=100KHz
	TIM_PWMOUTPUT_Handle.Init.Prescaler = 108-1;	
	// 采样时钟分频
	TIM_PWMOUTPUT_Handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	// 计数方式
	TIM_PWMOUTPUT_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;
	// 重复计数器
	TIM_PWMOUTPUT_Handle.Init.RepetitionCounter=0;	
	// 初始化定时器TIMx, x[1,8]
	HAL_TIM_PWM_Init(&TIM_PWMOUTPUT_Handle);
	/*PWM模式配置*/
	//配置为PWM模式1
	TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;
	TIM_OCInitStructure.Pulse = 5000;
	TIM_OCInitStructure.OCPolarity = TIM_OCPOLARITY_HIGH;
	TIM_OCInitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH;
	TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_SET;
	TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;
	//初始化通道1输出PWM 
HAL_TIM_PWM_ConfigChannel(&TIM_PWMOUTPUT_Handle,&TIM_OCInitStructure,TIM_CHANNEL_1);
	/* 定时器通道1输出PWM */
	HAL_TIM_PWM_Start(&TIM_PWMOUTPUT_Handle,TIM_CHANNEL_1);
}

PWM输入捕获配置:
static void TIM_PWMINPUT_Config(void)
{	
	TIM_IC_InitTypeDef  	TIM_ICInitStructure;
	TIM_SlaveConfigTypeDef  TIM_SlaveConfigStructure;
	// 开启TIMx_CLK,x[1,8] 
	ADVANCE_TIM_CLK_ENABLE(); 
	/* 定义定时器的句柄即确定定时器寄存器的基地址*/
	TIM_PWMINPUT_Handle.Instance = ADVANCE_TIM;
	TIM_PWMINPUT_Handle.Init.Period = 0xFFFF; 	
	// 高级控制定时器时钟源TIMxCLK = HCLK=216MHz 
	// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz
	TIM_PWMINPUT_Handle.Init.Prescaler = 216-1;	
	// 采样时钟分频
	TIM_PWMINPUT_Handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	// 计数方式
	TIM_PWMINPUT_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;	
	// 初始化定时器TIMx, x[1,8]
	HAL_TIM_IC_Init(&TIM_PWMINPUT_Handle);
	/* IC1捕获:上升沿触发 TI1FP1 */
	TIM_ICInitStructure.ICPolarity = TIM_ICPOLARITY_RISING;
	TIM_ICInitStructure.ICSelection = TIM_ICSELECTION_DIRECTTI;
	TIM_ICInitStructure.ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStructure.ICFilter = 0x0;
HAL_TIM_IC_ConfigChannel(&TIM_PWMINPUT_Handle,&TIM_ICInitStructure,ADVANCE_IC1PWM_CHANNEL);
	/* IC2捕获:下降沿触发 TI1FP2 */	
	TIM_ICInitStructure.ICPolarity = TIM_ICPOLARITY_FALLING;
	TIM_ICInitStructure.ICSelection = TIM_ICSELECTION_INDIRECTTI;
	TIM_ICInitStructure.ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStructure.ICFilter = 0x0;
HAL_TIM_IC_ConfigChannel(&TIM_PWMINPUT_Handle,&TIM_ICInitStructure,ADVANCE_IC2PWM_CHANNEL);
    /* 选择从模式: 复位模式 */
	TIM_SlaveConfigStructure.SlaveMode = TIM_SLAVEMODE_RESET;
	/* 选择定时器输入触发: TI1FP1 */
	TIM_SlaveConfigStructure.InputTrigger = TIM_TS_TI1FP1;
	HAL_TIM_SlaveConfigSynchronization(&TIM_PWMINPUT_Handle,&TIM_SlaveConfigStructure);
	/* 使能捕获/比较2中断请求 */
	HAL_TIM_IC_Start_IT(&TIM_PWMINPUT_Handle,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&TIM_PWMINPUT_Handle,TIM_CHANNEL_2);
}

main代码编写

中断配置:
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
  {
	  /* 获取输入捕获值 */
	  IC1Value = HAL_TIM_ReadCapturedValue(&TIM_PWMINPUT_Handle,ADVANCE_IC1PWM_CHANNEL);
	  IC2Value = HAL_TIM_ReadCapturedValue(&TIM_PWMINPUT_Handle,ADVANCE_IC2PWM_CHANNEL);	
	  if (IC1Value != 0)
	  {
		/* 占空比计算 */
		DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);

		/* 频率计算 */
		Frequency = 216000000/216/(float)(IC1Value+1);
		
	  }
	  else
	  {
		DutyCycle = 0;
		Frequency = 0;
	  }

  }
}

int main(void)
{
/* 初始化系统时钟为216MHz */
SystemClock_Config();
/* 初始化串口 */
DEBUG_USART_Config();
/* 初始化基本定时器定时,1s产生一次中断 */
TIMx_Configuration();
while(1)
{
HAL_Delay(500);
printf("IC1Value = %d  IC2Value = %d ",IC1Value,IC2Value);
printf("占空比:%0.2f%%   频率:%0.2fHz\n",DutyCycle,Frequency);
}
}

实验显示:
可以查看到定时器2产生的PWM方波的占空比,频率。定时器8捕获的2次捕获的数值。
在这里插入图片描述

结语

本节介绍了STM32中基本定时器6&7的使用,通过配置定时器6&7,LED灯精准时间翻转。另外,完成了高级定时器的输入捕获实验。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值