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

STM32标准库-TIM定时器

文章目录

  • 一、TIM定时器
    • 1.1定时器
    • 1.2定时器类型
      • 1.1.1 高级定时器
      • 1.1.2通用定时器
      • 1.1.3基本定时器
  • 二、定时中断基本结构
    • 预分频器时器
    • 计时器时序
    • 计数器无预装时序
    • 计数器有预装时序
    • RCC时钟树
  • 三、定时器定时中断
    • 3.1 接线图
    • 3.2代码
    • 3.3效果:
  • 四、定时器外部中断
    • 4.1接线图
    • 4.2代码
    • 4.3效果:

一、TIM定时器

1.1定时器

  • TIM(Timer)定时器
  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
  • 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

1.2定时器类型

在这里插入图片描述
== STM32F103C8T6定时器资源:TIM1、TIM2、TIM3、TIM4==

1.1.1 高级定时器

在这里插入图片描述

1.1.2通用定时器

在这里插入图片描述

1.1.3基本定时器

在这里插入图片描述

二、定时中断基本结构

在这里插入图片描述

预分频器时器

在这里插入图片描述

预分频器作用:通过分频降低定时器时钟频率,公式为 CK_CNT = CK_PSC / (PSC + 1)(PSC 是预分频器寄存器值)

  • 时序关键节点:

CK_PSC:输入时钟(高频);
CNT_EN:计数器使能信号;
CK_CNT:分频后的计数器时钟(低频,驱动CNT计数);
更新事件(UEV):预分频器参数变更后,触发定时器更新,使新分频值生效。
流程:修改TIMx_PSC寄存器值→预分频缓冲器暂存→更新事件触发时,新值加载到实际计数器,改变CK_CNT频率。

计时器时序

在这里插入图片描述

计数器无预装时序

在这里插入图片描述

计数器有预装时序

在这里插入图片描述

RCC时钟树

在这里插入图片描述

三、定时器定时中断

3.1 接线图

在这里插入图片描述

3.2代码

main.c

#include "stm32f10x.h"                  // 包含STM32F10x系列设备头文件,访问寄存器和外设
#include "Delay.h"                       // 延时功能(未使用,可忽略)
#include "OLED.h"                        // OLED显示驱动,实现屏幕初始化和显示
#include "CountSensor.h"                 // 计数传感器(未使用,可忽略)
#include "Timer.h"                       // TIM2定时器初始化(内部时钟,1秒中断一次)uint16_t Num = 0;                        // 记录定时器中断次数(每秒+1)int main(void)
{		OLED_Init();                          // 初始化OLED(配置通信,如I2C/SPI)Timer_Init();                         // 初始化TIM2(内部时钟,周期1秒)OLED_ShowString(1, 1, "Num:");        // 第1行显示"Num:",标识计数while(1) // 主循环,持续更新显示{ OLED_ShowNum(1, 5, Num, 5);       // 显示中断次数(右对齐,5位)OLED_ShowNum(2, 5, TIM_GetCounter(TIM2), 5); // 显示TIM2当前计数值(0~9999循环)}
}// TIM2更新中断服务函数(每秒触发一次)
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update)) { // 检查中断标志Num++;                                // 计数+1(每秒更新)TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除标志}
}

Timer.

#include "stm32f10x.h"                  // 包含STM32F10x系列设备头文件,访问寄存器和外设功能extern uint16_t Num;  // 外部声明计数变量(主程序中定义)// 定时器TIM2初始化(内部时钟,1秒中断一次)
void Timer_Init(void)
{// 1. 使能TIM2时钟(APB1总线)RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);// 2. 配置内部时钟源TIM_InternalClockConfig(TIM2);// 3. 时基单元配置(72MHz系统时钟下,1秒周期)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;          // 时钟分频(无分频)TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;      // 向上计数TIM_TimeBaseInitStruct.TIM_Period = 9999;                         // 自动重装值(0~9999,共10000次计数)TIM_TimeBaseInitStruct.TIM_Prescaler = 7199;                      // 预分频(7200分频,72MHz/7200=10kHz)TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;                 // 重复计数(通用定时器不用)TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);                  // 初始化时基// 4. 清除初始更新标志(避免误触发)TIM_ClearFlag(TIM2, TIM_FLAG_Update);// 5. 使能更新中断TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);// 6. NVIC配置(中断优先级)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                   // 分组:2位抢占,2位子优先级NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;                      // TIM2中断通道NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;                      // 使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;            // 抢占优先级2NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;                   // 子优先级1NVIC_Init(&NVIC_InitStruct);                                      // 初始化NVIC// 7. 启动定时器TIM_Cmd(TIM2, ENABLE);
}/*
// TIM2中断服务函数(需取消注释以更新Num)
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {                // 检查更新中断标志Num++;                                                       // 计数变量递增(每秒+1)TIM_ClearITPendingBit(TIM2, TIM_IT_Update);                   // 清除中断标志}
}
*/

3.3效果:

Num 变化:每秒递增 1(如:0 → 1 → 2 → …)
CNT 变化:每秒内从 0 递增到 9999,然后归零,Num+1。

四、定时器外部中断

4.1接线图

在这里插入图片描述

4.2代码

Timer.c

#include "stm32f10x.h"                  // 包含STM32F10x系列外设寄存器定义extern uint16_t Num;  // 外部声明的计数变量(需在主程序中定义)/*** @brief  定时器TIM2初始化(ETR外部时钟模式)* @note   存在3处关键问题:*         1. PA0被配置为上拉输入,与ETR复用功能冲突;*         2. 中断服务函数被注释,无法响应溢出中断;*         3. 时基参数过于激进(周期9、预分频0),计数过快。*/
void Timer_Init(void)
{// 1. 使能时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // 使能TIM2时钟(APB1总线)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟(APB2总线)// 2. 配置PA0(冲突点:ETR模式下应自动复用,手动配置输入模式会冲突)GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         // 上拉输入(与ETR功能冲突,建议移除)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     // 输入模式下速度设置无效,仅语法要求GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;             // 配置PA0引脚GPIO_Init(GPIOA, &GPIO_InitStructure);                // 初始化GPIOA// 3. 配置ETR外部时钟模式2//    参数:不分频、上升沿触发(NonInverted对应上升沿)、无滤波TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF,            // ETR预分频器关闭TIM_ExtTRGPolarity_NonInverted, // 极性:非反相(上升沿触发)0x00);                        // 滤波系数0(无滤波)// 4. 配置时基单元(参数问题:周期9 + 预分频0 → 每10个脉冲触发一次中断)TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频(不影响计数频率)TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数TIM_TimeBaseInitStruct.TIM_Period = 10 - 1;             // 自动重装值:计数到9时溢出TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1;           // 预分频值:0(不分频)TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;       // 重复计数器(通用定时器无效)TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);        // 初始化时基// 5. 清除更新标志(避免初始化时误触发中断)TIM_ClearFlag(TIM2, TIM_FLAG_Update);// 6. 使能更新中断TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);              // 允许TIM2的更新中断// 7. 配置NVIC中断优先级NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         // 分组:2位抢占优先级 + 2位子优先级NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;            // 中断通道:TIM2全局中断NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;            // 使能中断通道NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;  // 抢占优先级:2NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;         // 子优先级:1NVIC_Init(&NVIC_InitStruct);                            // 初始化NVIC// 8. 启动定时器TIM_Cmd(TIM2, ENABLE);                                  // 启动TIM2计数器
}/*** @brief  获取TIM2当前计数值* @retval TIM2的计数器值(0 ~ TIM_Period)*/
uint16_t Timer_GetCounter(void)
{return TIM_GetCounter(TIM2);  // 读取TIM2的CNT寄存器值
}/*
// 【关键缺失】TIM2中断服务函数(当前被注释,导致Num无法递增)
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) { // 检查更新中断标志Num++;                                        // 计数变量递增TIM_ClearITPendingBit(TIM2, TIM_IT_Update);   // 清除中断标志(必须操作)}
}
*/

main.c

#include "stm32f10x.h"                  // 包含STM32F10x系列设备的寄存器定义和外设库函数#include "Delay.h"                      
#include "OLED.h"                       
#include "CountSensor.h"               
#include "Timer.h"                       // 定时器驱动头文件(包含TIM2初始化逻辑)uint16_t Num = 0;                        // 全局计数变量,记录定时器中断次数int main(void)
{		OLED_Init();                          // 初始化OLED显示屏(配置通信接口,如I2C/SPI)Timer_Init();                         // 初始化TIM2定时器(ETR外部时钟模式,需PA0输入外部信号)OLED_ShowString(1, 1, "Num:");  // 在OLED第1行第1列显示字符串"Num:",标识计数结果OLED_ShowString(2, 1, "CNT:");  // 在OLED第2行第1列显示字符串"CNT:",标识定时器当前计数值while(1) // 主循环,持续更新显示内容{ OLED_ShowNum(1, 5, Num, 5);     // 在OLED第1行第5列显示Num(右对齐,占5位)OLED_ShowNum(2, 5, Timer_GetCounter(), 5);   // 在OLED第2行第5列显示TIM2当前计数值(右对齐,占5位)}
}void TIM2_IRQHandler(void)// TIM2定时器中断服务函数(处理更新中断,每TIM_Period+1个脉冲触发一次)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)    // 检查TIM2的更新中断标志是否置位{Num++;                 // 计数变量递增(记录中断次数)TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中断标志,避免重复触发}
}
  • 定时器配置(Timer.c):

使能 TIM2 和 GPIOA 时钟(PA0 为 ETR 引脚)。
配置 ETR 外部时钟模式(上升沿触发,不分频)。
时基参数:TIM_Period(自动重载值)和TIM_Prescaler(预分频值,需根据外部信号频率调整)。
使能更新中断,配置 NVIC 优先级。

  • 中断处理:

每次 TIM2 计数溢出(达到TIM_Period)时,Num加 1,用于统计中断次数。
OLED 实时显示Num(总计数)和TIM2->CNT(当前计数值,0~TIM_Period循环)。

4.3效果:

  • 当 PA0 接入外部脉冲信号(如方波)时,TIM2 计数器CNT随脉冲上升沿递增。
  • 每计数到 9(即收到 10 个脉冲)时,触发更新中断,Num加 1。
  • 计数器每触发一次CNT+1,加到9时,Num+1.

相关文章:

STM32标准库-TIM定时器

文章目录 一、TIM定时器1.1定时器1.2定时器类型1.1.1 高级定时器1.1.2通用定时器1.1.3基本定时器 二、定时中断基本结构预分频器时器计时器时序计数器无预装时序计数器有预装时序RCC时钟树 三、定时器定时中断3.1 接线图3.2代码3.3效果: 四、定时器外部中断4.1接线图…...

【算法训练营Day05】哈希表part1

文章目录 哈希表理论基础有效的字母异位词两个数组的交集快乐数两数之和 哈希表理论基础 几个值得关注的知识点: hash表用于快速的判断元素是否存在(空间换时间)其原理就是将数据通过散列函数映射到bucket中,如果发生hash碰撞&a…...

CMap应用场景和例子

CMap 详解 CMap 是 MFC (Microsoft Foundation Classes) 库中的一个模板类,用于实现键值对的映射关系(类似哈希表或字典)。它提供了高效的数据存储和检索功能,适用于需要通过键快速查找值的场景。 基本模板参数 cpp 运行 tem…...

Kafka 如何保证顺序消费

在消息队列的应用场景中,保证消息的顺序消费对于一些业务至关重要,例如金融交易中的订单处理、电商系统的库存变更等。Kafka 作为高性能的分布式消息队列系统,通过巧妙的设计和配置,能够实现消息的顺序消费。接下来,我…...

【算法题】算法一本通

每周更新至完结,建议关注收藏点赞。 目录 待整理文章已整理的文章方法论思想总结模版工具总结排序 数组与哈希表栈双指针(滑动窗口、二分查找、链表)树前缀树堆 优先队列(区间/间隔问题、贪心 )回溯图一维DP位操作数学…...

Modbus转Ethernet IP赋能挤出吹塑机智能监控

在现代工业自动化领域,小疆智控Modbus转Ethernet IP网关GW-EIP-001与挤出吹塑机的应用越来越广泛。这篇文章将为您详细解读这两者的结合是如何提高生产效率,降低维护成本的。首先了解什么是Modbus和Ethernet IP。Modbus是一种串行通信协议,它…...

C++中如何遍历map?

文章目录 1. 使用范围for循环(C11及以上)2. 使用迭代器3. 使用反向迭代器注意事项 在C中, std::map 是一种关联容器,它存储的是键值对(key-value pairs),并且按键的顺序进行排序。遍历 std::m…...

什么是终端安全管理系统(终端安全管理软件2024科普)

在当今数字化迅速发展的时代,企业面临着越来越多的信息安全威胁。为了应对这些挑战,保障公司数据的安全性和完整性,终端安全管理系统(Endpoint Security Management System)应运而生。 本文将为您深入浅出地科普2024年…...

书籍转圈打印矩阵(8)0604

题目 给定一个整型矩阵matrix,请按照转圈的方式打印它。 例如: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 打印结果为:1,2,3&#xff…...

【JVM】Java类加载机制

【JVM】Java类加载机制 什么是类加载? 在 Java 的世界里,每一个类或接口在经过编译后,都会生成对应的 .class 字节码文件。 所谓类加载机制,就是 JVM 将这些 .class 文件中的二进制数据加载到内存中,并对其进行校验…...

Elasticsearch中的自定义分析器(Custom Analyzer)介绍

在 Elasticsearch 中,自定义分析器(Custom Analyzer) 是一种可配置的文本处理组件,允许用户通过组合分词器(Tokenizer)、过滤器(Token Filter)和字符过滤器(Character Filter)来定义特定的文本分析逻辑。这使得 Elasticsearch 能够针对不同语言、业务场景或特殊需求,…...

《C++初阶之入门基础》【C++的前世今生】

【C的前世今生】目录 前言:---------------起源---------------一、历史背景二、横空出世---------------发展---------------三、标准立世C98:首个国际标准版本C03:小修订版本 四、现代进化C11:现代C的开端C14:对C11的…...

Apache APISIX

目录 Apache APISIX是什么? Lua Lua 的主要特点: Lua 的常见应用: CVE-2020-13945(Apache APISIX默认API Token导致远程Lua代码执行) ​编辑Lua脚本解析 CVE-2021-45232(Apache APISIX Dashboard API权限绕过导致RCE) Apache …...

如何在 git dev 中创建合并请求

先将 自己的代码 推到 自己的远程的 分支上 在 创建 合并请求 根据提示 将 自己的远程的 源码 合并到 对应的分支上 然后 创建 合并请求 等待 对应的 人 来 进行合并就行...

基于nlohmann/json 实现 从C++对象转换成JSON数据格式

C对象的JSON序列化与反序列化 基于JsonCpp库实现C对象序列化与反序列化 JSON 介绍 JSON作为一种轻量级的数据交换格式,在Web服务和应用程序中广泛使用。 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读…...

Java枚举类映射MySQL的深度解析与实践指南

Java枚举类映射MySQL的深度解析与实践指南 一、枚举类型映射的四大核心策略 1. 序数映射法(ordinal映射) ​​实现原理​​:存储枚举值的下标顺序 public enum OrderStatus {PENDING, // 存储为0PROCESSING, // 存储为1SHIPPED, //…...

代码训练LeetCode(21)跳跃游戏2

代码训练(21)LeetCode之跳跃游戏2 Author: Once Day Date: 2025年6月4日 漫漫长路,才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 45. 跳跃游戏 II - 力扣(LeetCode)力扣 (LeetCode) 全球极客挚爱…...

【HarmonyOS 5】鸿蒙APP使用【团结引擎Unity】开发的案例教程

以下是基于团结引擎开发鸿蒙Unity应用的详细案例教程,整合环境配置、工程适配、跨语言通信等核心环节 一、环境配置(关键前置步骤) 1. ‌工具安装‌ ‌工具‌‌版本要求‌‌作用‌团结引擎Hub≥1.2.3Unity鸿蒙项目构建管理DevEco Studio≥…...

《T/CI 404-2024 医疗大数据智能采集及管理技术规范》全面解读与实施分析

规范背景与详细信息 《T/CI 404-2024 医疗大数据智能采集及管理技术规范》是由中国国际科技促进会联合河南科技大学、河南科技大学第一附属医院、深圳市人民医院等十余家医疗机构与企业共同制定的团体标准,于2024年5月正式发布实施。该规范是我国医疗大数据领域的重要技术标准…...

国产三维CAD皇冠CAD在「金属压力容器制造」建模教程:蒸汽锅炉

面对蒸汽锅炉设计中复杂的曲面封头、密集的管板开孔、多变的支撑结构以及严格的强度与安全规范(如GB150、ASME等),传统二维设计手段往往捉襟见肘,易出错、效率低、协同难。国产三维CAD皇冠CAD(CrownCAD)凭借…...

Mysql避免索引失效

1. 在索引列上使用函数或表达式 问题描述 SELECT * FROM users WHERE YEAR(create_time) 2023; 如果create_time列上有索引,上述查询会导致索引失效,因为MySQL无法直接利用索引的B树结构。 解决方法 将函数应用于条件值,而不是列&#…...

python爬虫:Ruia的详细使用(一个基于asyncio和aiohttp的异步爬虫框架)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Ruia概述1.1 Ruia介绍1.2 Ruia特点1.3 安装Ruia1.4 使用案例二、基本使用2.1 Request 请求2.2 Response - 响应2.3 Item - 数据提取2.4 Field 提取数据2.5 Spider - 爬虫类2.6 Middleware - 中间件三、高级功能3.1 …...

C++中单例模式详解

在C中,单例模式 (Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。这在需要一个全局对象来协调整个系统行为的场景中非常有用。 为什么要有单例模式? 在许多项目中,某些类从逻辑上讲只需要一个实…...

舆情监控系统爬虫技术解析

之前我已经详细解释过爬虫在系统中的角色和技术要点,这次需要更聚焦“如何实现”这个动作。 我注意到上次回复偏重架构设计,这次应该拆解为更具体的操作步骤:从目标定义到数据落地的完整流水线。尤其要强调动态调度这个容易被忽视的环节——…...

Windows上用FFmpeg采集摄像头推流 → MediaMTX服务器转发流 → WSL2上拉流播放

1. Windows上 FFmpeg 推流(摄像头采集) 设备名称可用 ffmpeg -list_devices true -f dshow -i dummy 查询,假设为Integrated Camera 采集推流示例(推RTMP到MediaMTX): ffmpeg -rtbufsize 100M -f dshow …...

cpp多线程学习

1.thread std::thread是 C11 引入的跨平台线程管理类,封装了操作系统的线程 API(如 pthread、Windows 线程),提供统一的线程操作接口。线程的生命周期由join()和detach()控制。 thread在创建时就开始执行 join():阻…...

Vue3中Ant-design-vue的使用-附完整代码

前言 首先介绍一下什么是Ant-design-vue Ant Design Vue 是基于 Vue 3 的企业级 UI 组件库(同时兼容 Vue 2),是蚂蚁金服开源项目 Ant Design 的 Vue 实现版本。它遵循 Ant Design 的设计规范,提供丰富的组件和高质量的设计体系&…...

k8s热更新-subPath 不支持热更新

文章目录 k8s热更新-subPath 不支持热更新背景subPath 不支持热更新1. 为什么 subPath 不支持热更新?2. 挂载整个目录为何支持热更新?使用demo举例:挂载整个目录(不使用 subPath) k8s热更新-subPath 不支持热更新 背景…...

Redis Sorted Set 深度解析:从原理到实战应用

Redis Sorted Set 深度解析:从原理到实战应用 在 Redis 丰富的数据结构家族中,Sorted Set(有序集合)凭借独特的设计和强大的功能,成为处理有序数据场景的得力工具。无论是构建实时排行榜,还是实现基于时间的…...

docker中组合这几个命令来排查 import 模块失败 的问题

pwd ls echo $PYTHONPATH这三个命令是你在 Linux 或 Docker 容器中常用来「查看环境状态」的基础命令。 ✅ 1. echo $PYTHONPATH 🔍 含义 这是在查看当前的 Python 模块搜索路径。 🧠 分解解释: echo:打印某个变量的值&#x…...