当前位置: 首页 > article >正文

采用STM32CubeMX和HAL库的定时器应用实例

目录

STM32的通用定时器配置流程

定时器应用的硬件设计

定时器应用的软件设计

1.    通过STM32CubeMX新建工程 通过STM32CubeMX新建工程的步骤如下:

2. 通过Keil MDK实现工程 通过Keil MDK实现工程的步骤如下:


STM32的通用定时器配置流程

通用定时器具有多种功能,但其原理大致相同,但其流程有所区别,以使用中断方式为例,主要包括三部分,即NVIC设置、TIM中断配置、定时器中断服务程序。 对每个步骤通过库函数的实现方式描述。首先要提到是,定时器相关的库函数主要中在HAL库文件stm32f1xx_hal_tim.h 和stm32f1xx_hal_tim.c文件中。 定时器配置步骤如下:

(1)TIM3时钟使能。 HAL中定时器使能是通过宏定义标识符实现对相关寄存器操作的,方法如下:

__HAL_RCC_TIM3_CLK_ENABLE(); //使能TIM3时钟

(2)初始化定时器参数,设置自动重装值,分频系数,计数方式等。 在HAL库中,定时器的初始化参数是通过定时器初始化函数HAL_TIM_Base_Init 实现的: HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim); 该函数只有一个入口参数,就是TIM_HandleTypeDef类型结构体指针。

(3)使能定时器更新中断,使能定时器。 HAL库中,使能定时器更新中断和使能定时器两个操作可以在函数HAL_TIM_Base_Start_IT()中一次完成的,该函数声明如下:

HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim); 该函数非常好理解,只有一个入口参数。调用该定时器之后,会首先调用__HAL_TIM_ENABLE_IT宏定义使能更新中断,然后调用宏定义__HAL_TIM_ENABLE 使能相应的定时器。

这里分别列出单独使能/关闭定时器中断和使能/关闭定时器方法:

__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);//使能句柄指定的定时器更新中断 __HAL_TIM_DISABLE_IT (htim, TIM_IT_UPDATE);//关闭句柄指定的定时器更新中断 _HAL_TIM_ENABLE(htim);//使能句柄 htim 指定的定时器

__HAL_TIM_DISABLE(htim);//关闭句柄 htim 指定的定时器

(4)TIM3 中断优先级设置。 在定时器中断使能之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器,设置中断优先级。之前多次讲解到中断优先级的设置,这里就不重复讲解。 和串口等其他外设一样,HAL 库为定时器初始化定义了回调函数 HAL_TIM_Base_MspInit。 一般情况下,与MCU有关的时钟使能,以及中断优先级配置都会放在该回调函数内部。 函数声明如下: void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim); 对于回调函数,这里不做过多讲解,只需要重写这个函数即可。

(5)编写中断服务函数。 在最后,还是要编写定时器中断服务函数,通过该函数处理定时器产生的相关中断。通常情况下,在中断产生后,通过状态寄存器的值判断此次产生的中断属于什么类型。然后执行相关的操作,这里使用的是更新(溢出)中断,所以在状态寄存器SR的最低位。在处理完中断之后应该向TIM3_SR的最低位写 0,清除该中断标志。

定时器应用的硬件设计

本实例利用基本定时器TIM6/7定时1s,1s时间到LED翻转一次。基本定时器是单片机内部的资源,没有外部IO,不需要接外部电路,只需要一个LED灯即可。

定时器应用的软件设计

在HAL库函数头文件stm32f1xx_hal_tim.h中对定时器外设建立了四个初始化结构体,基本定时器只用到其中一个即TIM_TimeBaseInitTypeDef,其实现如下:

typedef struct {
uint32_t Prescaler; // 预分频器
uint32_t CounterMode; // 计数模式
uint32_t Period; // 定时器周期
uint32_t ClockDivision; // 时钟分频
uint32_t RepetitionCounter; // 重复计算器
uint32_t AutoReloadPreload; // 自动预装载
} TIM_TimeBaseInitTypeDef;

这些结构体成员说明如下,其中括号内的文字是对应参数在STM32 HAL库中定义的宏:

(1)Prescaler:定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定TIMx_PSC寄存器的值。可设置范围为0至65535,实现1至65536分频。

(2)CounterMode:定时器计数方式,可设置为向上计数、向下计数以及中心对齐模式。基本定时器只能是向上计数,即TIMx_CNT只能从0开始递增,并且无须初始化。

(3)Period:定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为0至65535。

(4)ClockDivision:时钟分频,设置定时器时钟CK_INT频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能,不用设置。

(5)RepetitionCounter:重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出PWM的个数。这里不用设置。

(6)AutoReloadPreload:计数器在计满一个周期之后会自动重新计数,也就是默认会连续运行。连续运行过程中如果修改了Period,那么根据当前状态的不同有可能发生超出预料的过程。如果使能了AutoReloadPreload,那么对Period的修改将会在完成当前计数周期后才更新。这里不用设置。

下面讲述如何通过STM32CubeMX新建工程、如何通过Keil MDK实现工程。

1.    通过STM32CubeMX新建工程 通过STM32CubeMX新建工程的步骤如下:

(1)新建文件夹   Demo目录下新建文件夹TIMER,这是保存本章新建工程的文件夹。

(2)新建STM32CubeMX工程 在STM32CubeMX开发环境中新建工程。

(3)选择MCU或开发板 Commercial Part Number和MCUs/MPUs List选择STM32F103ZET6,选择Start Project启动工程。

(4)保存STM32Cube MX工程 使用STM32CubeMX菜单File→Save Project,保存工程。

(5)生成报告 使用STM32CubeMX菜单File→Generate Report生成当前工程的报告文件。

(6)配置MCU时钟树 STM32CubeMX Pinout & Configuration子页面下,选择System Core→RCC,High Speed Clock(HSE)根据开发板实际情况,选择Crystal/Ceramic Resonator(晶体/陶瓷晶振)。 STM32CubeMX切换到Clock Configuration子页面下,根据开发板外设情况配置总线时钟。此处配置PLL Source Mux为HSE,PLLMul为9倍频72MHz,System Clock Mux为PLLCLK,APB1 Prescaler为X2,其余默认设置即可。

(7)配置MCU外设 根据LED电路,整理出MCU连接的GPIO引脚的输入/输出配置

再根据表进行GPIO引脚配置,具体步骤如下。 STM32CubeMX Pinout & Configuration子页面下选择System Core→GPIO,对使用的GPIO口进行设置。LED输出端口LED1_RED(PB5)

STM32CubeMX Pinout & Configuration子页面下选择Timers→TIM6,对TIM6进行设置。Mode选择Activated,定时器预分频系数71,时钟频率为1MHz;BASIC_TIMx_PERIOD为1000,定时器计数周期为1ms

切换到STM32CubeMX Pinout & Configuration子页面下选择System Core→NVIC,修改Priority Group为2 bits for pre-emption priority(2位抢占优先级),Enabled栏勾选TIM3 global interrupt,修改Preemption Priority(抢占优先级)为0,Sub Priority(子优先级)为3

Code Generation页面Select for init sequence ordering栏勾选TIM6 global interrupt

(8)配置工程 STM32CubeMX Project Manager子页面Project栏下Toolchain/IDE选择MDK-Arm,Min Version选择V5,可生成Keil MDK工程;选择STM32CubeIDE,可生成STM32CubeIDE工程。

(9)生成C代码工程 STM32CubeMX主页面,单击GENERATE CODE按钮生成C代码工程。

2. 通过Keil MDK实现工程 通过Keil MDK实现工程的步骤如下:

(1)打开工程   打开TIMER\MDK-Arm文件夹下的工程文件。

(2)编译STM32CubeMX自动生成的MDK工程 在MDK开发环境中通过菜单Project→Rebuild all target files或工具栏      Rebuild按钮编译工程。

(3)STM32CubeMX自动生成的MDK工程 main.c文件中函数main()依次调用了HAL_Init()函数用于复位所有外设,初始化Flash接口和Systick定时器。SystemClock_Config()函数用于配置各种时钟信号频率。MX_GPIO_Init()函数初始化GPIO引脚。 文件gpio.c包含了函数MX_GPIO_Init()的实现代码,如下。

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LED1_RED_GPIO_Port, LED1_RED_Pin, GPIO_PIN_SET);
  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = LED1_RED_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(LED1_RED_GPIO_Port, &GPIO_InitStruct);
}

main()函数外设初始化函数MX_TIM6_Init(),它是TIM6的初始化函数。MX_TIM6_Init()是在文件time.c中定义的函数,它的代码里调用了函数HAL_TIM_Base_Init()实现STM32CubeMX配置的定时器设置。MX_TIM6_Init()实现的代码如下。

void MX_TIM6_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 71;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 1000;
 htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  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();
  }
}
函数MX_NVIC_Init()实现中断的初始化,代码如下
static void MX_NVIC_Init(void)
{
  /* TIM6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(TIM6_IRQn, 0, 3);
  HAL_NVIC_EnableIRQ(TIM6_IRQn);
}

(4)新建用户文件   在TIMER\Core\Src下新建bsp_led.c,在TIMER\Core\Inc下新建bsp_led.h。将bsp_led.c添加到工程Application/User/Core文件夹下。

(5)编写用户代码 bsp_led.h和bsp_led.c文件实现LED操作的宏定义和LED初始化。 timer.c文件MX_TIM6_Init()函数使能TIM6和更新中断。   /* USER CODE BEGIN TIM6_Init 2 */   HAL_TIM_Base_Start_IT(&htim6);   /* USER CODE END TIM6_Init 2 */ timer.c文件添加中断回调函数HAL_TIM_PeriodElapsedCallback(),对计数器time加1。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim==(&htim6))
		time++;     
}
main.c文件添加对用户自定义头文件的引用。
/* Private includes ---------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bsp_led.h"
/* USER CODE END Includes */
main.c文件添加计数器time的定义。
/* USER CODE BEGIN PV */
volatile uint32_t time = 0; // ms 计时变量 
/* USER CODE END PV */
main.c文件添加对LED1的取反操作
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		if ( time == 1000 ) /* 1000 * 1 ms = 1s 时间到 */
    {
      time = 0;
		/* LED1 取反 */      
		LED1_TOGGLE; 
    } 
 /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

(6)重新编译工程   重新编译添加代码后的工程。

(7)配置工程仿真与下载项 在MDK开发环境中通过菜单Project→Options for Target或工具栏     配置工程。

打开Debug选项卡,选择使用的仿真下载器ST-Link Debugger。Flash Download下勾选Reset and Run选项。单击确定。

(8)下载工程   连接好仿真下载器,开发板上电。 在MDK开发环境中通过菜单Flash→Download或工具栏    下载工程。 工程下载完成后,可以看到LED1以1s的频率闪烁一次


http://www.kler.cn/a/375662.html

相关文章:

  • flinksql-Queries查询相关实战
  • 【每日C/C++问题】
  • 泛微开发修炼之旅--51关于解决ecology中em_auth_token is empty的报错问题解决方案
  • Vision - 开源视觉分割算法框架 Grounded SAM2 配置与推理 教程 (1)
  • Python和MATLAB都可以用于绘制折线图,下面是分别用Python和MATLAB绘制简单折线图的示例。
  • 字符脱敏工具类
  • 竞赛管理新篇章:Spring Boot大学生竞赛平台
  • 【深度学习基础】深入理解 卷积与卷积核
  • 鸿蒙基础篇-ArkTS-语句-类型进阶与渲染控制
  • 生物信息与机器学习6 - 有监督学习算法和无监督学习算法
  • 强势改进!TCN-Transformer时间序列预测
  • 新能源汽车充电桩安装限流式保护器如何选配-安科瑞黄安南
  • 网络安全战略论文学习笔记day2
  • 013:开发软件Visual Studio 2012安装教程
  • 动态规划 - 编辑距离
  • PHP面试题总结
  • 三大专项计划助力教育公平,你准备好了吗?
  • 数字ic/FPGA,Windows/Linux系统,其他相关领域,软件安装包(matlab、vivado、modelsim。。。)
  • MacOS/Macbook用户自定义字体安装教程
  • T级别DDoS攻击与大型DDoS防御
  • 保持HTTP会话状态:缓存策略与实践
  • mint-ui Picker 显示异常
  • 数字信号处理:自动增益控制(AGC)
  • 高频谐振功放电路
  • C语言 | Leetcode C语言题解之第526题优美的排列
  • C++基本语法