打印
[应用相关]

STM32定时器实现计时功能

[复制链接]
302|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-11-8 16:48 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
前言
        本文章使用STM32F103C8T6标准库实现TIM1的定时功能,代码如下:

#include "stm32f10x.h"                  // Device header
#include "led_drv.h"

static void timInit(uint32_t periodUs)
{
        /*使能定时器时钟*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
        /*定时器复位*/
        TIM_DeInit(TIM1);
        /*定时器配置*/
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
        TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
        TIM_TimeBaseInitStruct.TIM_Prescaler = SystemCoreClock / 1000000 - 1;//输入给计数器的时钟频率为1Mhz,周期1us
        TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInitStruct.TIM_Period = periodUs - 1;
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
        TIM_ClearFlag(TIM1, TIM_FLAG_Update);
        /*使能定时器更新中断*/
        TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
        /*NVIC配置*/
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//一个工程只分组一次
       
        NVIC_InitTypeDef  NVIC_InitStruct;
        NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
        NVIC_Init(&NVIC_InitStruct);
        /*定时器使能*/
        TIM_Cmd(TIM1, ENABLE);
        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
}

/**
***********************************************************
* @brief        定时器驱动初始化
* @param
* @return
***********************************************************
*/
void TimDrvInit(void)
{
        timInit(1000);
}

/**
***********************************************************
* @brief        定时器1更新中断服务函数
* @param
* @return
***********************************************************
*/
void TIM1_UP_IRQHandler(void)
{
        if ( TIM_GetITStatus(TIM1, TIM_IT_Update) )
        {
//                static uint32_t s_counter;
//                static uint8_t flipFlag = 1;
//                s_counter ++;
//                if (s_counter >= 1000 && flipFlag)
//                {
//                        s_counter = 0;
//                        flipFlag = 0;
//                        TurnOnLed(LED_BLUE);
//                        TurnOnLed(LED_YELLOW);
//                        TurnOnLed(LED_WHITE);
//                }
//                else if (s_counter >= 1000 && flipFlag == 0)
//                {
//                        s_counter = 0;
//                        flipFlag = 1;
//                        TurnOffLed(LED_BLUE);
//                        TurnOffLed(LED_YELLOW);
//                        TurnOffLed(LED_WHITE);
//                }
                TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
        }
}

一 基本定时框图
        来自RCC的TIM1CLK的频率是72MHz,PSC预分频器是一个16位的寄存器,所以分频系数可以选择的范围是0~65535,假如设置预分频系数为0,那就是不分频(1分频),CK_CNT == TIM1CLK / 1;假如预分频系数PSC为71, 那就是72分频,CK_CNT == TIM1CLK / 72 == 1MHz。

        CNT计数器是一个周期计数器,CK_CNT每来一个时钟周期就±1,假如CK_CNT == 1MHz,那么周期t = 1/f = 1us,也就是说CNT计数器每计数一次就是1us。

        这时,如果自动重装载寄存器设置为999,那么每1000us即1ms产生一次更新中断,如此实现定时的功能。为什么是999重装值而不是1000呢, 假如我需要4us产生一次中断,那我设置重装寄存器的值为4, 计数器从0-1计数1次, 从1-2计数2次, 从2-3计数3次,从3-4计数4次, 从4-0计数5次,为0产生更新中断,所以需要减1。





二 代码实现
2.1 驱动初始化
        只讲一些要点,不逐一进行分析。

        ①TIM_TimeBaseStructInit这个函数是为了对结构体初始化,因为TIM_TimeBaseInitStruct是一个局部变量,我们实现定时器1的定时功能并不会用到它的所有成员,而局部变量不赋初值其值是不确定的,所以需要进行初始化。

        ②SystemCoreClock / 1000000 - 1;使用这个作为预分频系数,假如系统时钟是36MHz,同样得到CK_CNT为1MHz。

        ③TIM_CounterMode_Up为向上计数模式,关于计数模式网上资料很多,可自行查阅。

static void timInit(uint32_t periodUs)
{
        /*使能定时器时钟*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
        /*定时器复位*/
        TIM_DeInit(TIM1);
        /*定时器配置*/
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
        TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
        TIM_TimeBaseInitStruct.TIM_Prescaler = SystemCoreClock / 1000000 - 1;//输入给计数器的时钟频率为1Mhz,周期1us
        TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInitStruct.TIM_Period = periodUs - 1;
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);
        TIM_ClearFlag(TIM1, TIM_FLAG_Update);
        /*使能定时器更新中断*/
        TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
        /*NVIC配置*/
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//一个工程只分组一次
       
        NVIC_InitTypeDef  NVIC_InitStruct;
        NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
        NVIC_Init(&NVIC_InitStruct);
        /*定时器使能*/
        TIM_Cmd(TIM1, ENABLE);
        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
}

2.2 中断服务函数
        唯一要注意的就是更换定时器后记得更换中断服务函数,进入中断后,不要忘记清除中断标志位。

/**
***********************************************************
* @brief        定时器1更新中断服务函数
* @param
* @return
***********************************************************
*/
void TIM1_UP_IRQHandler(void)
{
        if ( TIM_GetITStatus(TIM1, TIM_IT_Update) )
        {
                /*实现功能*/
                TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
        }
}
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_73101636/article/details/143570022

使用特权

评论回复
沙发
caigang13| | 2024-11-8 19:03 | 只看该作者
属于定时器的最基础应用

使用特权

评论回复
板凳
AdaMaYun| | 2024-11-11 17:32 | 只看该作者
定时器预分频非常实用的讲解

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1931

主题

15611

帖子

11

粉丝