赞
踩
目录
文章依赖的硬件及工程配置同本文作者的其他文章:细说ARM MCU的串口接收数据的实现过程-CSDN博客 https://wenchm.blog.csdn.net/article/details/139541112
STM32G4系列MCU的定时器功能比较强大,有下面几种定时器:
类 型 | 定时器 | 计数器 | 计数器类型 | 预分频因子 | DMA | 捕捉/ 比较通道 | 互补输出 |
高精度 | HRTIM | 16位 | Up | 1/2/4(x2,x4, | 是 | 12 | 有 |
高级 | TIM1、TIM8、TIM20 | 16位 | Up、Down和 | 1~65536 | 是 | 4 | 4 |
通用 | TIM2和TIM5 | 32位 | Up、Down和 | 1~65536 | 是 | 4 | 无 |
通用 | TIM3和TIM4 | 16位 | Up、Down和 | 1~65536 | 是 | 4 | 无 |
通用 | TIM15 | 16位 | Up | 1~65536 | 是 | 2 | 1 |
通用 | TIM16、TIM17 | 16位 | Up | 1~65536 | 是 | 1 | 1 |
基本 | TIM6、TIM7 | 16位 | Up | 1~65536 | 是 | 0 | 无 |
定时器最基本的功能是起到定时的作用,其中有一个关键模块:计数器(counter)。该计数器可以循环往复计数,计数的模式有三种类型:升、降和升/降。Up模式是从0到最大值递增计数,计到最大值后再从0重新开始计。
除了TIM2和TIM5以外,其余的定时器中,计数器都是16位,相应的计数最大值为65535。除了计数器的参数以外,定时器中的另一个比较重要的参数是预分频因子(prescaler factor),这个参数关系到两次计数之间的计时间隔(具体数值,还要结合定时器的时钟频率来计算)。此外,定时器还可用于输入捕捉,以及产生PWM波形(互补)输出;当然对这两个功能,不同的定时器是有差别的。
本文利用 STM32G474RE上的通用定时器,以定时器中断的方式控制NUCLEO - G474RE板上的发光二极管LD2以不同的频率闪烁(该功能也可通过延时函数的方式实现)。
至此,硬件配置便完成了。保存,启动代码生成过程,系统会将刚才配置硬件的信息自动转换成代码。
该函数自动生成。
- /**
- * @brief TIM3 Initialization Function
- * @param None
- * @retval None
- */
- static 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};
-
- /* USER CODE BEGIN TIM3_Init 1 */
-
- /* USER CODE END TIM3_Init 1 */
- htim3.Instance = TIM3;
- htim3.Init.Prescaler = 999;
- htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim3.Init.Period = 16999;
- htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
- 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();
- }
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
- if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN TIM3_Init 2 */
-
- /* USER CODE END TIM3_Init 2 */
-
- }
MX_TIM3_Init()函数主要完成对TIM3的模式和参数配置,如预分频因子、计数模式、计数周期等参数。在MX_TIM3_Init()函数的定义中,用到了一个结构体变量htim3,该结构体变量也被称为定时器句柄。这个变量是在自动代码生成过程中自动生成的,位于main.c文件的最前面:
TIM_HandleTypeDef htim3;
在MX_TIM3_Init()函数的定义中,把设置的参数赋给了结构体变量htim3。其中一条if语句,在其条件表达式中调用了一个函数:HAL_TIM_Base_Init(&htim3);结构体变量htim3通过调用HAL_ TIM_Base_Init(&htim3)实现与实际硬件关联的。该函数只有一个参数。调用时,把刚配置的结构体变量htim3传递了过来。实际上,真正与硬件关联的,还不是HAL_TIM_Base_Init()函数,而是在HAL_TIM_Base_Init()函数中调用的TIM_Base_SetConfig()函数。正是通过TIM_Base_SetConfig()函数,才真正地把设置的参数传递给了相关寄存器。在库函数文件stm32g4xx_hal_tim.c中有对TIM_Base_Set-Config()函数的定义。
虽然配置了TIM3的中断功能,但在默认情况下,中断不是开启的。所以,在使用时,还要开启该中断。开启定时器中断可以使用如下库函数:
HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
该函数也只有一个参数,并且该参数也是一个结构体变量。对于TIM3来说,其实就可以用前面提到的htim3。开启定时器中断可以使用如下代码:
- /*USER CODE BEGIN 2 */
- HAL_TIM_Base_Start_IT(&htim3); //手动添加
- /*USER CODE END 2*/
上述代码位于while(1)循环前面的注释对中。不过,需要将它放到TIM3初始化函数MX_TIM3_ Init()的后面。
开启TIM3的中断后,当条件满足时,就会执行定时器中断服务函数TIM3_IRQHandler()。该函数是自动生成的,位置在stm32g4xx_it.c文件中有该函数的定义:
- /**
- * @brief This function handles TIM3 global interrupt.
- */
- void TIM3_IRQHandler(void)
- {
- /* USER CODE BEGIN TIM3_IRQn 0 */
-
- /* USER CODE END TIM3_IRQn 0 */
- HAL_TIM_IRQHandler(&htim3);
- /* USER CODE BEGIN TIM3_IRQn 1 */
-
- /* USER CODE END TIM3_IRQn 1 */
- }
TIM3_IRQHandler()函数的定义中又调用了HAL_TIM_IRQHandler()函数,此函数的定义在stm32g4xxhal_tim.c中。实际上,在HAL_TIM_IRQHandler()函数中,还会调用TIM中断的回调函数HAL_TIM_PeriodElapsedCallback()。这个函数的定义也是在stm32g4xxhal_tim.c中,不过,被定义为一个弱函数。这种方式与串口中断接收过程是类似的。就像对串口接收中断回调函数的处理一样,在定时器中断的使用中,需要做的是在main.c中重新定义TIM中断的回调函数。
在main.c中重新定义回调函数HAL_TIM_PeriodElapsedCallback()。在其中让PA5的输出状态翻转。具体实现如下:
- /*USER CODE BEGIN 4 */
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
- }
- /*USER CODE END 4*/
本例中,定时器的预分频因子(Prescaler)和计数器周期(Counter Period)分别置为999和16999,定时器的时钟频率为170 MHz,最终TIM3中断的周期为
(999+1)/(170×10⁶)×(16999+1)=0.1(s),即频率为10 Hz。
编译工程并下载到硬件中运行,会看到LD2灯以5 Hz的频率闪烁。为什么是5 Hz因为控制PA5用的是Toggle。
修改定时器的预分频因子(Prescaler)和计数器周期(CounPeriod),改变LD2灯的闪烁频率为1 Hz、0.5 Hz等。
- (1999+1)/(170×10⁶)×(1699+1)=2(s),即频率为2 Hz。
- (999+1)/(170×10⁶)×(1699+1)=1(s),即频率为1 Hz。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。