TIM

singlemouse 发布于 2023-08-11 1284 次阅读


Table of Contents

TIM笔记

TIM简介

•TIM(Timer)定时器

•定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

•16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时

•不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能

•根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型

定时器类型

不同型号拥有的定时器数量不同,详情参考手册

正点原子精英版V2有八个定时器(TIM1~TIM8)

定时器框图

简单了解即可

通用定时器框图


定时中断基本结构

打通步骤

一、RCC开启时钟

此举能同时打开定时器基准时钟和整个外设的工作时钟

RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE);

二、选择时基单元的时钟源

定时中断--选择内部时钟源(上电后默认使用内部时钟,所以该步骤可省略)

TIM_InternalClockConfig(TIM2); // 选择内部时钟

三、配置时基单元

配置预分频器、自动重装器、计数模式

公式
计数器计数频率:CK_CNT = CK_PSC / (PSC + 1)
计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
                           = CK_PSC / (PSC + 1) / (ARR + 1)
经典三步

即定义结构体,结构体变量赋值,结构体初始化

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIVx; // x分频(x为1,2或4)
    TIM_TimeBaseInitStruct.TIM_CounterMode = ; // 计数器模式
    TIM_TimeBaseInitStruct.TIM_Period = ; // 这玩意是ARR(范围0~65535)
    TIM_TimeBaseInitStruct.TIM_Prescaler = ;  // 这玩意是PSC (范围0~65535)
    // ARR取10000-1,PSC取7200-1的情况下为1s
    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = ; // 重复计时器(高级定时器才有)
    TIM_TimeBaseInit(TIMx,&TIM_TimeBaseInitStruct);

四、配置输出中断控制

允许更新中断输出到NVIC

    TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);

五、配置NVIC

经典三步+一个优先级分组

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_x); // 优先级分组

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = ; // 定时器在NVIC里的通道
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 开启/关闭
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ; // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = ; // 响应优先级
    NVIC_Init(&NVIC_InitStructure);

六、运行控制

启动定时器
TIM_Cmd(TIMx, ENABLE);
编写中断函数
void TIM2_IRQHandler(void) // 名字固定(以TIM2为例)(在启动文件里找)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) // 获取中断标志位(以更新中断标志位为例)
    {

        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除标志位
    }
}

部分API

最终实验

定时器定时中断计数

实验现象详情看江协科技stm32-6-2

TIM模块
#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    TIM_InternalClockConfig(TIM2);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
    TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM2, ENABLE);
}

/*
void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {

        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}
*/
主函数模块
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num; // 全局变量

int main(void)
{
    OLED_Init();
    Timer_Init();

    OLED_ShowString(1, 1, "Num:");

    while (1)
    {
        OLED_ShowNum(1, 5, Num, 5);
    }
}

void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {
        Num ++; // 计数
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}
此作者没有提供个人介绍
最后更新于 2023-08-27