STM32CubeMX学习笔记(5)——基本定时器接口使用

发布者:DreamySerenity最新更新时间:2025-02-21 来源: jianshu关键字:STM32CubeMX  基本定时器 手机看文章 扫描二维码
随时随地手机看文章

一、定时器简介

STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。
基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。
通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。
高级定时器 TIM1/8 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。


二、新建工程

1. 打开 STM32CubeMX 软件,点击“新建工程”


2. 选择 MCU 和封装


3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)


选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置


4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire


5. 配置GPIO
GPIO 设置,在右边图中找到 LED 灯对应引脚,选择 GPIO_Output,输出低电平点亮,可以添加自定义标签



三、TIM6基本定时器

3.1 参数配置

在 Timers 中选择 TIM6 设置,并勾选 Activated 激活


在 Parameter Settings 进行具体参数配置。

Tclk 即内部时钟CK_INT,经过APB1预分频器后分频提供,如果APB1预分频系数等于1,则频率不变,否则频率乘以2,库函数中APB1预分频的系数是2,即PCLK1=36M,如图所以定时器时钟Tclk=36*2=72M。


定时器溢出时间:

Tout = 1 / (Tclk / (psc + 1)) ∗ (arr + 1)

  • 定时器时钟Tclk:72MHz

  • 预分频器psc:71

  • 自动重装载寄存器arr:999

即 Tout = 1/(72MHz/(71+1))∗(999+1) = 1ms

  • Prescaler(时钟预分频数):72-1 则驱动计数器的时钟 CK_CNT = CK_INT(即72MHz)/(71+1) = 1MHz

  • Counter Mode(计数模式):Up(向上计数模式) 基本定时器只能是向上计数

  • Counter Period(自动重装载值):1000-1 则定时时间 1/CK_CLK*(999+1) = 1ms

  • auto-reload-preload(自动重装载):Enable(使能)

  • TRGO Parameters(触发输出):不使能 在定时器的定时时间到达的时候输出一个信号(如:定时器更新产生TRGO信号来触发ADC的同步转换)

3.2 配置NVIC

使能定时器中断


3.3 生成代码

输入项目名和项目路径


选择应用的 IDE 开发环境 MDK-ARM V5


每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。


点击 GENERATE CODE 生成代码


3.4 修改中断回调函数

打开 stm32f1xx_it.c 中断服务函数文件,找到 TIM6 中断的服务函数 TIM6_IRQHandler()
中断服务函数里面就调用了定时器中断处理函数 HAL_TIM_IRQHandler()


打开 stm32f1xx_hal_tim.c 文件,找到定时器中断处理函数原型 HAL_TIM_IRQHandler(),其主要作用就是判断是哪个定时器产生哪种事件中断,清除中断标识位,然后调用中断回调函数 HAL_TIM_PeriodElapsedCallback()。


/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
这个函数不应该被改变,如果需要使用回调函数,请重新在用户文件中实现该函数。

HAL_TIM_PeriodElapsedCallback() 按照官方提示我们应该再次定义该函数,__weak 是一个弱化标识,带有这个的函数就是一个弱化函数,就是你可以在其他地方写一个名称和参数都一模一样的函数,编译器就会忽略这一个函数,而去执行你写的那个函数;而 UNUSED(htim) ,这就是一个防报错的定义,当传进来的定时器号没有做任何处理的时候,编译器也不会报出警告。其实我们在开发的时候已经不需要去理会中断服务函数了,只需要找到这个中断回调函数并将其重写即可而这个回调函数还有一点非常便利的地方这里没有体现出来,就是当同时有多个中断使能的时候,STM32CubeMX会自动地将几个中断的服务函数规整到一起并调用一个回调函数,也就是无论几个中断,我们只需要重写一个回调函并判断传进来的定时器号即可。

接下来我们就在 stm32f1xx_it.c 这个文件的最下面添加 HAL_TIM_PeriodElapsedCallback()

/* USER CODE BEGIN 1 */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

    static uint32_t time = 0;

    if(htim->Instance == TIM6)  // 定时器6基地址

    {

        // 自定义应用程序

        time++;           // 每1ms进来1次

        if(time == 1000)  // 每1秒LED灯翻转一次

        {

            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);

            time = 0;

        }

    }

}

/* USER CODE END 1 */


3.5 添加定时器启动函数

现在进入 main 函数并在 while 循环前加入开启定时器函数 HAL_TIM_Base_Start_IT(),这里所传入的 htim6 就是刚刚定时器初始化后的结构体。

/**

  * @brief  The application entry point.

  * @retval int

  */

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_TIM6_Init();

  /* USER CODE BEGIN 2 */

  HAL_TIM_Base_Start_IT(&htim6);  

  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


现在实验现象是每1秒LED灯翻转一次


3.6 HAL库与标准库代码比较

STM32CubeMX 使用 HAL 库生成的代码:

/**

  * @brief TIM6 Initialization Function

  * @param None

  * @retval None

  */

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 = 72-1;

  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;

  htim6.Init.Period = 1000-1;

  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 */


  /* USER CODE END TIM6_Init 2 */

}


/**

  * @brief This function handles TIM6 global interrupt.

  */

void TIM6_IRQHandler(void)

{

  /* USER CODE BEGIN TIM6_IRQn 0 */


  /* USER CODE END TIM6_IRQn 0 */

  HAL_TIM_IRQHandler(&htim6);

  /* USER CODE BEGIN TIM6_IRQn 1 */


  /* USER CODE END TIM6_IRQn 1 */

}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

    static uint32_t time = 0;

    if(htim->Instance == TIM6)

    {

        // 自定义应用程序

        time++;

        if(time == 1000)

        {

            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);

            time = 0;

        }

    }

}


HAL_TIM_Base_Start_IT(&htim6); 


使用 STM32 标准库的代码:


/**

 @brief 定时器中断配置(使用TIM6基本定时器)

 @param 无

 @return 无

*/

void BASIC_TIM_Config(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    /*

    可以从上图看出基本定时器和通用定时器使用APB1总线,

    高级定时器使用APB2总线。

    */

    // 开启定时器时钟,即内部时钟 CK_INT=72M

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);


    /*

    预分频将输入时钟频率按1~65536之间的值任意分频,分频值决定了计数频率。

    计数值为计数的个数,当计数寄存器的值达到计数值时,产生溢出,发生中断。

    如系统时钟为72MHz,预分频 TIM_Prescaler = 71,

    计数值 TIM_Period = 1000,

    则 TIM_Period * (TIM_Prescaler + 1) / 72000000 = 0.001,

    即每1ms产生一次中断。

    */

    // 自动重装载寄存器周的值(计数值)

    TIM_TimeBaseStructure.TIM_Period = 1000;

 

    // 累计 TIM_Period 个频率后产生一个更新或者中断

    // 时钟预分频数为 71,

    // 则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M

    TIM_TimeBaseStructure.TIM_Prescaler = 71;


    // 时钟分频因子 ,基本定时器没有,不用管

    //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;


    // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置

    //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;


    // 重复计数器的值,基本定时器没有,不用管

    //TIM_TimeBaseStructure.TIM_RepetitionCounter=0;


    /*

    完成时基设置

    */

    // 初始化定时器

    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);


    /*

    为了避免在设置时进入中断,这里需要清除中断标志位。

    如果是向上计数模式(基本定时器采用向上计数),

    则采用函数 TIM_ClearFlag(TIM6, TIM_FLAG_Update),

    清除向上溢出中断标志。

    */

    // 清除计数器中断标志位

    TIM_ClearFlag(TIM6, TIM_FLAG_Update);


    // 使能计数器

    TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);


    // 开启计数器

    TIM_Cmd(TIM6, ENABLE);


    // 暂时关闭定时器的时钟,等待使用

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, DISABLE);

}


/**

 @brief NVIC初始化(使用TIM6基本定时器)

 @param 无

 @return 无

*/

void BASIC_TIM_NVIC_Config(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;

    // 设置中断组为 0

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

    // 设置中断来源

    NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ;

    // 设置主优先级为 0

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    // 设置抢占优先级为 3

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}


#define BASIC_TIM_IRQHandler TIM6_IRQHandler

// 1ms发生一次中断,time 记录中断次数

uint16_t time;


void BASIC_TIM_IRQHandler(void)

{

    if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)

    {

        time++;

        TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update);

    }

}


RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);


MX_TIM6_Init(); 对应 BASIC_TIM_Config();BASIC_TIM_NVIC_Config();
HAL_TIM_Base_Init(&htim6) 对应 TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure)
HAL_TIM_Base_Start_IT(&htim6); 对应 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);


四、注意事项

用户代码要加在 USER CODE BEGIN N 和 USER CODE END N 之间,否则下次使用 STM32CubeMX 重新生成代码后,会被删除。

关键字:STM32CubeMX  基本定时器 引用地址:STM32CubeMX学习笔记(5)——基本定时器接口使用

上一篇:STM32CubeMX学习笔记(6)——USART串口使用
下一篇:STM32CubeMX学习笔记(4)——系统延时使用

推荐阅读最新更新时间:2026-03-19 10:58

STM32CubeMX学习笔记(5)——基本定时器接口使用
一、定时器简介 STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。 基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。 通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。 高级定时器 TIM1/8 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。 二、新建工程 1. 打开 STM32CubeMX 软件,点击“新建工程” 2.
[单片机]
STM32CubeMX学习笔记(2)——GPIO接口使用
一、新建工程 1. 打开 STM32CubeMX 软件,点击“新建工程” 2. 选择 MCU 和封装 3. 配置时钟 RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器) 选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz 修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置 4. 配置调试模式 非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器 SYS 设置,选择 Debug 为 Serial Wire 二、GPIO输出 2.1 参数配置 在 System Core
[单片机]
STM32CubeMX学习笔记(7)——DMA接口使用
一、DMA简介 DMA(Direct Memory Access) 直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是多线程一样。数据传输支持从外设到存储器或者存储器到存储器,这里的存储器可以是 SRAM 或者是 FLASH。DMA 控制器包含了 DMA1 和 DMA2,其中 DMA1 有 7 个通道,DMA2 有 5 个通道,这里的通道可以理解为传输数据的一种管道。 要注意的是 DMA2 只存在于大容量的单片机中。 二、DMA请求映像 DMA1 各个通道的请求映像 DMA2 各个通道的请求映像 其中 ADC3、SD
[单片机]
STM32CubeMX学习笔记(42)——ETH接口+LwIP协议栈使用(静态IP)
一、ETH简介 STM32F4xx 系列控制器内部集成了一个以太网外设,它实际是一个通过 DMA 控制器进行介质访问控制(MAC),它的功能就是实现 MAC 层的任务。借助以太网外设,STM32F4xx 控制器可以通过 ETH 外设按照 IEEE 802.3-2002 标准发送和接收 MAC 数据包。ETH 内部自带专用的 DMA 控制器用于 MAC,ETH 支持两个工业标准接口介质独立接口(MII)和简化介质独立接口(RMII)用于与外部 PHY 芯片连接。MII 和 RMII 接口用于 MAC 数据包传输,ETH 还集成了站管理接口(SMI)接口专门用于与外部 PHY 通信,用于访问 PHY 芯片寄存器。 物理层定义了以太网
[单片机]
STM32CubeMX学习笔记(46)——USB接口使用(HID自定义设备)
一、USB简介 USB(Universal Serial BUS)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、Microsoft 等多家公司联合提出的。 USB 发展到现在已经有 USB1.0/1.1/2.0/3.0 等多个版本。目前用的最多的就是 USB1.1 和 USB2.0,USB3.0 目前已经开始普及。STM32F103 自带的 USB 符合 USB2.0 规范,不过 STM32F103 的 USB 都只能用来做设备,而不能用作主机。 标准 USB 共四根线组成,除
[单片机]
【STM32学习笔记7.1】定时器基本原理
前言 本系列文章统一围绕STM32F103C8T6最小系统开发板进行记录,如涉及其他开发板将会特别说明。 基本概念 主要功能 嵌入式领域中广泛应用, 主要通过计时、计数的方式,周期性执行某件工作,如检测、响应、控制等。 应用场合:输入捕获、输出波形、计时等。 类型 由硬件资源决定,其精度主要由硬件时钟决定 单个硬件定时器可以扩充出多个软件定时器 硬件定时器 软件定时器:由软件实现 – 循环延时 工作原理:本质上是一个计数器,当计数器计满溢出时,代表着一次事件,即完成一次计时。 STM32F1x定时器 8个Timer定时器+1个系统嘀嗒定时器(SysTick)+2个看门狗定时器 Timer定时器
[单片机]
STM32G0开发笔记:定时器timer的基本使用方法
使用Platformio平台的libopencm3开发框架来开发STM32G0,以下为定时器timer的基本使用方法。 1 新建项目 在PIO主页新建项目timer,框架选择libopencm3,开发板选择 MonkeyPi_STM32_G070RB; 新建完成后在src目录新建主程序文件main.c; 然后更改项目文件platformio.ini的烧写和调试方式: 1upload_protocol = cmsis-dap 2debug_tool = cmsis-dap 2 使用基本定时器 定时器设置 以下为设置定时器3的过程: 1static void timer_setup(void) 2{ 3 /* Enabl
[单片机]
STM32G0开发笔记:<font color='red'>定时器</font>timer的<font color='red'>基本</font><font color='red'>使用</font>方法
STM32-基本定时器TIM6-TIM7基本定时功能
  1. STM32的Timer简介   STM32中一共有11个定时器,其中2个高级控制定时器,4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中系统嘀嗒定时器是前文中所描述的SysTick,看门狗定时器以后再详细研究。今天主要是研究剩下的8个定时器。 定时器 计数器分辨率 计数器类型 预分频系数 产生DMA请求 捕获/比较通道 互补输出 TIM1 TIM8 16位 向上,向下,向上/向下 1-65536之间的任意数 可以 4 有 TIM2 TIM3 TIM4 TIM5 16位 向上,向下,向上/向下 1-65536之间的任意数 可以 4 没有 TIM6 TIM7 16位 向上 1-6553
[单片机]
STM32-<font color='red'>基本</font><font color='red'>定时器</font>TIM6-TIM7<font color='red'>基本</font>定时功能
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved