定时器是cpu的一个不可或缺的外部定时器,由于定时器的功能比较多,真正学会定时器的运用还是需要花费一定的时间、精力的。记得当初自己刚刚接触定时器的时候,学到32定时器的时候,对自己的打击非常大,当时都想要放弃了,主要是这一部分的知识复杂太多了,不过现在我们使用STM32cube来学习32架构,比之前要方便很多了,之前的基本的使用标准库学习,出现了问题也不知道该如何解决,这里和大家分享一下,定时器的学习经历。
这次先和大家分享STM32定时器的原理、寄存器介绍、定时器配置,定时器的几个常用的功能(如定时器中断、定时器输出比较PWM波形、定时器输入捕获、定时器编码器模式应用等)在以后得章节中和大家分享。
一:定时器得基本介绍
1:STM32定时器:U083单片机共计有12定时器,分别是1个高级定时器(TIME1),4个通用定时器(TIME2、TIME3、TIME15、TIME16),2个基本定时器(TIME6,TIME7)和3个低功耗定时器(LPTIME1,LPTIME2,LPTIME3)如下图所示:
wan
几种定时器的区别如下所示:
从图中,我们可以看到高级定时器具有捕获,比较通道和互补输出,可以用来控制电机运行,通用定时器只有基本的计数、PWM输出、输入捕获和输出捕获,而基本定时器只有最基本的计数功能,在硬件或者软件设计的时候,用作计数功能就可以;
下面我们简单,STM3 的通用 TIMx (TIM2、TIM3、TIM15 和 TIM16)定时器功能特点包括:
位于低速的APB1总线上(APB1)
16 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。
16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。
4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
输入捕获 、输出比较、 PWM 生成(边缘或中间对齐模式) 、 单脉冲模式输出
可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):
更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) 、输入捕获 、输出比较 、支持针对定位的增量(正交)编码器和霍尔传感器电路
触发输入作为外部时钟或者按周期的电流管理
STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
计数器模式:
通用定时器可以向上计数、向下计数、向上向下双向计数模式。
①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
二:STM32cube软件配置过程:
配置定时器6的基本参数
使能定时器6的中断:
系统时钟的配置,这里为了方便直接使用的默认时钟,系统时钟如下所示:
三:软件编码步骤如下:
1:使能定时器时钟。
2:初始化定时器,配置ARR,PSC。
3:开启定时器中断,配置NVIC。
4:使能定时器。
5: 编写中断服务函数。
四:代码编写:
定时器6初始化:
static void MX_TIM6_Init(void) { /* USER CODE BEGIN TIM6_Init 0 */ /* USER CODE END TIM6_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM6_Init 1 */ /* USER CODE END TIM6_Init 1 */ htim6.Instance = TIM6; htim6.Init.Prescaler = 1599; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 999; 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(); } /* USER CODE BEGIN TIM6_Init 2 */ HAL_TIM_Base_Start_IT(&htim6); /* USER CODE END TIM6_Init 2 */ }
在定时器初始话完成之后,添加开启定时器中断功能。在定时器回调函数中,添加LED灯闪烁的功能。代码如下:
Tout(中断触发时间)=(ARR+1)(PSC+1)/定时器的时钟频率
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { /* USER CODE BEGIN Callback 0 */ /* USER CODE END Callback 0 */ /* USER CODE BEGIN Callback 1 */ if (htim->Instance == TIM6) { // HAL_IncTick(); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } /* USER CODE END Callback 1 */ }
为了方便看到定时器的输出工作状态,我们在使用外部中断,实现开始/关闭定时器6的功能,代码如下:
/** * @brief EXTI line detection callback. * @param GPIO_Pin: Specifies the pins connected EXTI line * @retval None */ void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_13) { if (uwIncrementState == 0) { /* Suspend tick increment */ HAL_TIM_Base_Stop_IT(&htim6); /* Change the Push button state */ uwIncrementState = 1; } else { /* Resume tick increment */ // HAL_ResumeTick(); HAL_TIM_Base_Start_IT(&htim6); /* Change the Push button state */ uwIncrementState = 0; } } }
实现效果如下图所示: