STM32标准库-TIM定时器

news2025/6/7 6:30:38

文章目录

  • 一、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;            // 抢占优先级2
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;                   // 子优先级1
    NVIC_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;  // 抢占优先级:2
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;         // 子优先级:1
    NVIC_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.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2401247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka 如何保证顺序消费

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

【算法题】算法一本通

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

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

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

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

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

【JVM】Java类加载机制

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

《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)是一种轻量级的数据交换格式,易于人阅读…

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

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

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

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

C++中单例模式详解

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

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

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

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

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

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

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

若依框架修改模板,添加通过excel导入数据功能

版本:我后端使用的是RuoYi-Vue-fast版本,前端是RuoYi-Vue3 需求: 我需要每个侧边栏功能都需要具有导入excel功能,但是若依只有用户才具备,我需要代码生成的每个功能都拥有导入功能。​ 每次生成一个一个改实在是太麻烦了。索性…

web全栈开发学习-01html基础

背景 最近在付费网站学习web全栈开发,记录一下阶段性学习。今天刚好学完html基础,跟着教程画了个基础的网站。 样品展示: 开发工具 vscode Visual Studio Code - Code Editing. Redefined 常用插件 Prettier:格式优化 Live Sever:实时调…

多线程环境中,如果多个线程同时尝试向同一个TCP客户端发送数据,添加同步机制

原代码 public async Task SendToClientAsync(TcpClient targetClient, byte[] data, int offset, int length) {try{// 1. 检查客户端是否有效if (targetClient null || !targetClient.Connected){Console.WriteLine("Cannot send: client is not connected");ret…

【含文档+PPT+源码】基于微信小程序的旅游论坛系统的设计与实现

项目介绍 本课程演示的是一款基于微信小程序的旅游论坛系统的设计与实现,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含:项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 …

贝叶斯优化+LSTM+时序预测=Nature子刊!

贝叶斯优化与LSTM的融合在时间序列预测领域取得了显著成效,特别是在处理那些涉及众多超参数调整的复杂问题时。 1.这种结合不仅极大提高了预测的精确度,还优化了模型训练流程,提升了效率和成本效益。超参数优化的新篇章:LSTM因其…