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

【星云 Orbit•STM32F4】13. 探索定时器:基本定时器

【星云 Orbit•STM32F4】13. 探索定时器:基本定时器

七律 · 定时器
芯片之心精巧藏,
定时精准度量长。
初学莫畏千般难,
动手方知妙用强。

为读者提供完整代码,但不提供代码文件,也别做“三键”工程师。唯有自己动手,技术这活,动手才行。
摘要:本文详细讲解STM32F407基本定时器原理与HAL库开发流程,涵盖硬件设计、寄存器配置、HAL库函数解析及模块化代码实现。
关键词:STM32F407, TIM6, HAL库, 定时器中断, 裸机开发


1. 引言

基本定时器(TIM6/TIM7)是STM32中结构最简单的定时单元,适用于时基生成和DAC触发场景。本教程以TIM6为例,实现500ms周期定时中断控制LED翻转。


2. 基础知识

2.1 定时器分类

  • 基本定时器:16位递增计数器,无输入捕获/输出比较
  • 通用定时器:TIM2-TIM5,支持输入捕获/PWM输出
  • 高级定时器:TIM1/TIM8,带死区控制等复杂功能

2.2 TIM6关键寄存器

寄存器功能描述
CR1控制寄存器(使能、计数模式)
SR状态寄存器(中断标志位)
CNT当前计数值
PSC预分频器
ARR自动重装载值

3. 硬件电路连接

  • LED:PA5(推挽输出,串联220Ω限流电阻)
  • TIM6:内部时钟源(无外部引脚)

4. 软件配置

4.1 时钟树配置

// system_stm32f4xx.c中配置主频为168MHz  
#define PLL_M      8  
#define PLL_N      336  
#define PLL_P      2       // APB1时钟=84MHz

4.2 HAL库关键函数

HAL_TIM_Base_Init(TIM_HandleTypeDef *htim); // 定时器初始化  
HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim); // 启动定时器中断  
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); // 中断回调函数

关键点解析:
  1. 定时器参数计算

    Tout = (ARR + 1) * (PSC + 1) / TIM_CLK
    
    • 当APB1时钟为84MHz时,设置PSC=999得到分频后时钟84MHz/1000=84kHz
    • ARR设置为41999,则定时周期为(41999+1)/84kHz = 0.5s
  2. HAL库工作流程

    HAL_TIM_Base_Init
    初始化定时器
    调用HAL_TIM_Base_MspInit
    配置NVIC和时钟
    HAL_TIM_Base_Start_IT
    开启定时器中断
  3. 中断响应流程

    定时器溢出
    触发TIM6中断
    进入TIMx_IRQHandler
    调用HAL_TIM_IRQHandler
    自动执行HAL_TIM_PeriodElapsedCallback

5. 代码实现

5.1 工程目录结构

STM32F40x_Project/
├── Drivers/
│   ├── BSP/
|       ├── LED/
│   │       ├── bsp_led.c    # LED硬件抽象层
│   │       └── bsp_led.h    
│   └── Module/TIMER/
│       ├── TIMER/├── drv_tim.c    # 定时器驱动模块
│           └── drv_tim.h    
└── Users ├── main.c           # 主程序└── stm32f4xx_it.c   # 中断服务程序

5.2 定时器配置流程

启动系统时钟
配置GPIO
初始化TIM6
设置预分频PSC
设置ARR值
使能更新中断
启动定时器

5.3 计算定时周期公式

Tout = (ARR+1)*(PSC+1)/TIMx_CLK  
例:APB1=84MHz, ARR=41999, PSC=999  
Tout = (41999+1)*(999+1)/84e6 = 0.5s

5.4 核心代码

drv_btim.c

#include "drv_btim.h"TIM_HandleTypeDef htim6;void TIM6_Init(uint16_t arr, uint16_t psc) {htim6.Instance = TIM6;htim6.Init.Prescaler = psc;htim6.Init.CounterMode = TIM_COUNTERMODE_UP;htim6.Init.Period = arr;htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&htim6);HAL_TIM_Base_Start_IT(&htim6);
}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) {if(tim_baseHandle->Instance == TIM6) {__HAL_RCC_TIM6_CLK_ENABLE();HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0);HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);}
}

stm32f4xx_it.c

void TIM6_DAC_IRQHandler(void) {HAL_TIM_IRQHandler(&htim6);
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if(htim->Instance == TIM6) {LED_Toggle(); // LED状态翻转}
}

6. 测试验证

  1. 编译工程生成HEX文件
  2. 使用ST-Link下载到开发板
  3. 观察PA5引脚LED以1Hz频率闪烁
  4. 示波器测量PA5波形:高/低电平各500ms

附录: 完整工程代码

1. BSP层代码

2.1 bsp_led.h
#ifndef __BSP_LED_H
#define __BSP_LED_H#include "stm32f4xx_hal.h"/* 硬件定义 */
#define LED_GPIO_PORT    GPIOA
#define LED_GPIO_PIN     GPIO_PIN_5
#define LED_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()/* 函数声明 */
void LED_Init(void);               // LED初始化
void LED_Toggle(void);             // LED状态翻转#endif /* __BSP_LED_H */
2.2 bsp_led.c
#include "bsp_led.h"/*** @brief  LED GPIO初始化* @note   配置PA5为推挽输出模式*/
void LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};LED_GPIO_CLK_ENABLE();  // 使能GPIO时钟GPIO_InitStruct.Pin = LED_GPIO_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;      // 推挽输出GPIO_InitStruct.Pull = GPIO_NOPULL;              // 无上下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;     // 低速模式HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_RESET); // 初始状态熄灭
}/*** @brief  翻转LED状态*/
void LED_Toggle(void)
{HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PIN);
}

2. 定时器模块

2.1 drv_btim.h
#ifndef __DRV_BTIM_H
#define __DRV_BTIM_H#include "stm32f4xx_hal.h"/* 定时器定义 */
#define TIMx                           TIM6
#define TIMx_CLK_ENABLE()              __HAL_RCC_TIM6_CLK_ENABLE()
#define TIMx_IRQn                      TIM6_DAC_IRQn
#define TIMx_IRQHandler                TIM6_DAC_IRQHandler/* 函数声明 */
void TIM6_Init(uint16_t arr, uint16_t psc);  // 定时器初始化#endif /* __DRV_BTIM_H */
2.2 drv_tim.c
#include "drv_btim.h"TIM_HandleTypeDef htim6;  // 定时器句柄/*** @brief  TIM6初始化* @param  arr : 自动重装载值* @param  psc : 预分频系数* @note   定时周期公式: Tout = (arr+1)*(psc+1)/TIMx_CLK*/
void TIM6_Init(uint16_t arr, uint16_t psc)
{htim6.Instance = TIMx;htim6.Init.Prescaler = psc;                  // 预分频值htim6.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数htim6.Init.Period = arr;                     // 自动重装载值htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // 不缓冲ARR// 初始化定时器if (HAL_TIM_Base_Init(&htim6) != HAL_OK){Error_Handler();}// 启动定时器中断HAL_TIM_Base_Start_IT(&htim6);
}/*** @brief  HAL库MSP初始化回调函数* @param  htim : 定时器句柄指针* @note   此函数由HAL_TIM_Base_Init()自动调用*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim)
{if(htim->Instance == TIMx){TIMx_CLK_ENABLE();                       // 使能TIM6时钟// 配置NVICHAL_NVIC_SetPriority(TIMx_IRQn, 1, 0);   // 中断优先级设置HAL_NVIC_EnableIRQ(TIMx_IRQn);           // 使能中断}
}

3. 用户层代码

3.1 main.c
#include "main.h"
#include "./LED/bsp_led.h"
#include "./TIMER/bsp_tim.h"/*** @brief  系统时钟配置* @note   使用内部HSI时钟,配置系统时钟为168MHz*/
void SystemClock_Config(void)
{// ... 此处需根据实际板载时钟源配置 ...
}int main(void)
{HAL_Init();                     // 初始化HAL库SystemClock_Config();           // 配置系统时钟LED_Init();                     // 初始化LED/* 计算定时器参数:- APB1时钟频率 = 84MHz- 目标定时周期 = 500ms- 预分频值PSC = 999 (实际分频系数=999+1=1000)- 自动重装载值ARR = 41999 (实际计数次数=41999+1=42000)Tout = (42000 * 1000) / 84,000,000 = 0.5s*/TIM6_Init(41999, 999);          // 初始化TIM6while (1){/* 主循环不执行任何操作,由定时器中断处理任务 */}
}// 错误处理函数(示例)
void Error_Handler(void)
{while(1);
}
3.2 stm32f4xx_it.c
#include "stm32f4xx_it.h"
#include "./TIMER/drv_btim.h"
#include "./LED/bsp_led.h"/*** @brief  TIM6中断服务函数*/
void TIMx_IRQHandler(void)
{HAL_TIM_IRQHandler(&htim6);  // 调用HAL库中断处理函数
}/*** @brief  定时器周期到达回调函数* @param  htim : 定时器句柄指针*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIMx){LED_Toggle();  // 每次中断翻转LED状态}
}

  1. graph TD;A[定时器溢出] --> B[触发TIM6中断];B --> C[进入TIMx_IRQHandler];C --> D[调用HAL_TIM_IRQHandler];D --> E[自动执行HAL_TIM_PeriodElapsedCallback];

4. 状态转换图

CNT < ARR
CNT == ARR
IDLE
CNT < ARR
产生中断
复位CNT

5. 流程图思维导图:

触发
硬件初始化
定时器配置
中断使能
主循环空转
定时中断触发
执行回调函数
LED翻转

相关文章:

【星云 Orbit•STM32F4】13. 探索定时器:基本定时器

【星云 Orbit•STM32F4】13. 探索定时器&#xff1a;基本定时器 七律 定时器 芯片之心精巧藏&#xff0c; 定时精准度量长。 初学莫畏千般难&#xff0c; 动手方知妙用强。 为读者提供完整代码&#xff0c;但不提供代码文件&#xff0c;也别做“三键”工程师。唯有自己动手&…...

江科大51单片机笔记【10】蜂鸣器(上)

一、蜂鸣器 1.原理 蜂鸣器是一种将电信号转换为声音信号的器件&#xff0c;常同来产生设备的按键音、报警音等提示信号蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器&#xff08;外观基本一样&#xff09;有源蜂鸣器&#xff1a;内部自带振荡源&#xff0c;将正负极接上直流…...

最新版本WebContext构造函数-避坑

import org.thymeleaf.context.IWebContext; import org.thymeleaf.context.WebContext; 当你想把页面信息全部获取出来存到redis缓存中使用时&#xff0c;SpringWebContext在Spring5中报错 SpringWebContext ctx new SpringWebContext(request, response,request.getServlet…...

Java基础系列:深入解析Object类与面向对象编程核心机制

目录 一、Object类&#xff1a;万物之源的方法解析 1. 核心方法全景图 2. 关键方法深度剖析 2.1 equals与hashCode的契约关系 2.2 clone方法的三重陷阱 2.3 finalize方法的死亡警告 二、面向对象三大支柱解析 1. 封装&#xff08;Encapsulation&#xff09;安全防线 2…...

Spring Boot API 项目中 HAProxy 与 Nginx 的选择与实践

在开发 Spring Boot 构建的 RESTful API 项目时&#xff0c;负载均衡和反向代理是提升性能与可用性的关键环节。HAProxy 和 Nginx 作为两种流行的工具&#xff0c;经常被用于流量分发&#xff0c;但它们各有侧重。究竟哪一个更适合你的 Spring Boot API 项目&#xff1f;本文将…...

C++ 数据结构详解及学习规划

C++数据结构详解及学习规划 一、C++常用数据结构详解与示例 以下是C++中核心数据结构的分类及具体实现示例: 1. 线性数据结构 a. 数组(Array) • 定义:存储固定大小、同类型元素的连续内存结构。 • 特点:快速随机访问(O(1)),但插入/删除效率低(O(n))。 • 应用场…...

Spring Boot启动流程及源码实现深度解析

Spring Boot启动流程及源码实现深度解析 一、启动流程概述 Spring Boot的启动流程围绕SpringApplication类展开&#xff0c;核心流程可分为以下几个阶段&#xff1a; 初始化阶段&#xff1a;推断应用类型&#xff0c;加载ApplicationContextInitializer和ApplicationListene…...

2025 开发AI软件的应用场景和优势

在人工智能技术持续突破的今天&#xff0c;AI软件开发已从实验室走向千行百业的核心战场。本文深入剖析医疗影像诊断、智能制造预测性维护、金融风控决策链等六大落地场景&#xff0c;揭示AI如何通过算法重构业务流程——某三甲医院通过病理AI系统将诊断效率提升4倍&#xff0c…...

忘记dedecms后台超级管理员账号和密码的解决方案

解决方案&#xff1a; 方案一、数据库修改&#xff1a; 1、前提是您能登录到数据库后台&#xff0c;登录MySQL数据库管理工具&#xff08;如phpMyAdmin&#xff09; 2、打开数据库中的 dede_admin 表&#xff0c;找到管理员记录&#xff0c;将 pwd 字段的值改成 f297a57a5a7…...

Kubernetes中的 iptables 规则介绍

#作者&#xff1a;邓伟 文章目录 一、Kubernetes 网络模型概述二、iptables 基础知识三、Kubernetes 中的 iptables 应用四、查看和调试 iptables 规则五、总结 在 Kubernetes 集群中&#xff0c;iptables 是一个核心组件&#xff0c; 用于实现服务发现和网络策略。iptables 通…...

标量、向量、矩阵与张量:从维度理解数据结构的层次

在数学和计算机科学中,维度描述了数据结构的复杂性,而标量、向量、矩阵、张量则是不同维度的数据表示形式。它们的关系可以理解为从简单到复杂的扩展,以下是详细解析: 1. 标量(Scalar):0维数据 定义:单个数值,没有方向,只有大小。 维度:0维(无索引)。 示例: 温度…...

OpenCV 颜色空间:原理与操作指南

颜色空间原理 RGB 颜色空间 RGB&#xff08;Red, Green, Blue&#xff09;是最常见的颜色空间&#xff0c;它通过红、绿、蓝三种颜色通道的不同强度组合来表示颜色。在 OpenCV 中&#xff0c;RGB 图像的每个像素由三个 8 位无符号整数&#xff08;0 - 255&#xff09;分别表示…...

Windows 11下Git Bash执行cURL脚本400问题、CMD/PowerShell不能执行多行文本等问题记录及解决方案

问题 在Postman里可成功执行的POST请求&#xff1a; 找到Postman的Code 因为cURL基本上算是行业标准&#xff0c;所以Postman默认选中cURL&#xff0c;支持切换不同的开发语言&#xff1a; 点击上图右上角的复制按钮&#xff0c;得到cURL脚本。 Windows 11家庭版&#xff…...

Mysql配置文件My.cnf(my.ini)配置参数说明

一、my.cnf 配置文件路径&#xff1a;/etc/my.cnf&#xff0c;在调整了该文件内容后&#xff0c;需要重启mysql才可生效。 1、主要参数 basedir path # 使用给定目录作为根目录(安装目录)。 datadir path # 从给定目录读取数据库文件。 pid-file filename # 为mysq…...

利用LLMs准确预测旋转机械(如轴承)的剩余使用寿命(RUL)

研究背景 研究问题:如何准确预测旋转机械(如轴承)的剩余使用寿命(RUL),这对于设备可靠性和减少工业系统中的意外故障至关重要。研究难点:该问题的研究难点包括:训练和测试阶段数据分布不一致、长期RUL预测的泛化能力有限。相关工作:现有工作主要包括基于模型的方法、数…...

【RAG】RAG 系统的基本搭建流程(ES关键词检索示例)

RAG 系统的基本搭建流程 搭建过程&#xff1a; 文档加载&#xff0c;并按一定条件切割成片段将切割的文本片段灌入检索引擎封装检索接口构建调用流程&#xff1a;Query -> 检索 -> Prompt -> LLM -> 回复 1. 文档的加载与切割 # !pip install --upgrade openai…...

记录小白使用 Cursor 开发第一个微信小程序(二):创建项目、编译、预览、发布(250308)

文章目录 记录小白使用 Cursor 开发第一个微信小程序&#xff08;二&#xff09;&#xff1a;创建项目、编译、预览、发布&#xff08;250308&#xff09;一、创建项目1.1 生成提示词1.2 生成代码 二、编译预览2.1 导入项目2.2 编译预览 三、发布3.1 在微信开发者工具进行上传3…...

游戏引擎学习第146天

音高变化使得对齐读取变得不可能&#xff0c;我们可以支持循环声音了。 我们今天的目标是完成之前一段时间所做的音频代码。这个项目并不依赖任何引擎或库&#xff0c;而是一个教育项目&#xff0c;目的是展示从头到尾运行一个游戏所需要的全部代码。无论你对什么方面感兴趣&a…...

nodejs关于后端服务开发的探究

前提 在当前的环境中关于web server的主流开发基本上都是java、php之类的&#xff0c;其中java spring系列基本上占了大头&#xff0c;而python之流也在奋起直追&#xff0c;但别忘了nodejs也是可以做这个服务的&#xff0c;只是位置有点尴尬&#xff0c;现在就来探究下nodejs…...

Java 大视界 -- Java 大数据在智能体育赛事运动员表现分析与训练优化中的应用(122)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

线性代数之矩阵特征值与特征向量的数值求解方法

文章目录 前言1. 幂迭代法&#xff08;Power Iteration&#xff09;幂法与反幂法求解矩阵特征值幂法求最大特征值编程实现补充说明 2. 逆幂迭代法&#xff08;Inverse Iteration&#xff09;移位反幂法 3. QR 算法&#xff08;QR Algorithm&#xff09;——稠密矩阵理论推导编程…...

SparkAi系统体验

DeepSeek-R1-671B大模型满血版私有化部署高可用教程-SparkAi系统集成图文教程 一、SparkAI是什么二、功能模块介绍系统快速体验 三、系统功能模块3.1 AI全模型支持/插件系统3.2 AI智能体应用3.3 AI专业绘画3.4 AI视频生成3.5 Dall-E2/E3/E4绘画3.6 智能思维导图生成3.7 AI绘画广…...

软件工程---构件

在软件工程中&#xff0c;构件是一个独立的、可复用的软件单元&#xff0c;它具有明确的功能、接口和行为&#xff0c;并且可以在不同的环境中加以集成和复用。构件的概念是软件架构和组件化开发的核心思想之一&#xff0c;其目的是促进软件系统的模块化、可维护性和可扩展性。…...

视频录像机视频通道是指什么

视频录像机的视频通道是指摄像机在监控矩阵或硬盘录像机设备上的视频输入的物理位置。 与摄像头数量关系&#xff1a;在视频监控系统中&#xff0c;有多少个摄像头就需要多少路视频通道&#xff0c;通道数量决定了视频录像机可接入摄像头的数量&#xff0c;一般硬盘录像机有4路…...

【Unity】 HTFramework框架(六十一)Project窗口文件夹锁定器

更新日期&#xff1a;2025年3月7日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 Project窗口文件夹锁定器框架文件夹锁定自定义文件夹锁定限制条件 Project窗口文件夹锁定器 在Project窗口中&#xff0c;文件夹锁定器能够为任何文件夹加…...

INFINI Labs 产品更新 | Easysearch 增加异步搜索等新特性

INFINI Labs 产品更新发布&#xff01;此次更新&#xff0c;Easysearch 增加了新的功能和数据类型&#xff0c;包括 wildcard 数据类型、Point in time 搜索 API、异步搜索 API、数值和日期字段的 doc-values 搜索支持&#xff0c;Console 新增了日志查询功能。 INFINI Easyse…...

3.6c语言

#define _CRT_SECURE_NO_WARNINGS #include <math.h> #include <stdio.h> int main() {int sum 0,i,j;for (j 1; j < 1000; j){sum 0;for (i 1; i < j; i){if (j % i 0){sum i;} }if (sum j){printf("%d是完数\n", j);}}return 0; }#de…...

基于Kubernetes部署MySQL主从集群

以下是一个基于Kubernetes部署MySQL主从集群的详细YAML示例&#xff0c;包含StatefulSet、Service、ConfigMap和Secret等关键配置。MySQL主从集群需要至少1个主节点和多个从节点&#xff0c;这里使用 StatefulSet 初始化脚本 实现主从自动配置。 1. 创建 Namespace (可选) ap…...

Docker基础篇——Ubuntu下Docker安装

大家好我是木木&#xff0c;在当今快速发展的云计算与云原生时代&#xff0c;容器化技术蓬勃兴起&#xff0c;Docker 作为实现容器化的主流工具之一&#xff0c;为开发者和运维人员带来了极大的便捷 。下面我们一起进行Docker安装。 Docker的官方Ubuntu安装文档&#xff0c;如…...

postman接口请求中的 Raw是什么

前言 在现代的网络开发中&#xff0c;API 的使用已经成为数据交换的核心方式之一。然而&#xff0c;在与 API 打交道时&#xff0c;关于如何发送请求体&#xff08;body&#xff09;内容类型的问题常常困扰着开发者们&#xff0c;尤其是“raw”和“json”这两个术语之间的区别…...