【STM32】TIM---基本定时器
Author:AXYZdong 自动化专业 工科男
有一点思考,有一点想法,有一点理性!
定个小小目标,努力成为习惯!在最美的年华遇见更好的自己!
- 开发板:
stm32f407VET6
- 开发环境:keil5 MDK
一、TIM 简介
定时器最基本功能:定时
- 定时发送 USART 数据
- 定时采集 AD 数据等
定时器与 GPIO 结合
- 测量输入信号脉冲宽度
- 产生输出波形 等
▲ 各个定时器的特性
二、基本定时器
基本定时器 :TIM6
和 TIM7
,基本功能完全一样,但所占资源彼此完全独立。
▲ 基本定时器的功能框图
- 基本定时器时钟只能来自内部时钟
- 基本定时器的内部时钟(CK_INT)频率为 84MHz
- 基 本定时器还专门用于 DAC 转换触发
- 只要设置
CK_PSC
和TIMx_ARR
这两个寄存器的值就可以控制事件生成的时间
三、定时器周期计算
- :溢出时间,即定时多长时间
- :定时器时钟频率
//定时器时钟源 TIMxCLK = 2 * PCLK1 25
// PCLK1 = HCLK / 4 26
// => TIMxCLK=HCLK/2=SystemCoreClock/2=84MHz
- :定时器周期,初始化结构体时用 TIM_Period 表示
uint32_t TIM_Period; /*!< Specifies the period value to be loaded into the active
Auto-Reload Register at the next update event.
This parameter must be a number between 0x0000 and 0xFFFF. */
- :预分频大小,初始化结构体时用 TIM_Prescaler 表示
uint16_t TIM_Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock.
This parameter can be a number between 0x0000 and 0xFFFF */
比如我们需要一个 1s 周期的定时器,具体这两个寄存器值该如何设置。
假设,我们先设置 TIMx_ARR寄存器值为 9999 ,即当 TIMx_CNT 从 0 开始计算,刚好等于 9999 时生成事件,总共计数 10000 次,那么如果此时时钟源周期 为 100us 即可得到刚好 1s 的定时周期。
接下来问题就是设置 TIMx_PSC 寄存器值使得 CK_CNT 输出为 100us 周期 (10000Hz) 的时钟。预分频器的输入时钟 CK_PSC 为 84MHz,所以设置预分频器值为 (8400-1) 即可满 足。
四、初始化结构体
typedef struct
{
//预分频器
uint16_t TIM_Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock.
This parameter can be a number between 0x0000 and 0xFFFF */
//计数模式
uint16_t TIM_CounterMode; /*!< Specifies the counter mode.
This parameter can be a value of @ref TIM_Counter_Mode */
//定时器周期
uint32_t TIM_Period; /*!< Specifies the period value to be loaded into the active
Auto-Reload Register at the next update event.
This parameter must be a number between 0x0000 and 0xFFFF. */
//时钟分频
uint16_t TIM_ClockDivision; /*!< Specifies the clock division.
This parameter can be a value of @ref TIM_Clock_Division_CKD */
//重复计算器
uint8_t TIM_RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter
reaches zero, an update event is generated and counting restarts
from the RCR value (N).
This means in PWM mode that (N+1) corresponds to:
- the number of PWM periods in edge-aligned mode
- the number of half PWM period in center-aligned mode
This parameter must be a number between 0x00 and 0xFF.
@note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef;
五、基本定时器实验
基本定时器循环定时 1s ,并使能定时器中断,每隔 1s 在定时器中断服务函数使 LED 状态翻转。
编程思路
- 初始化 LED
- 开启定时器时钟
- 设置定时器周期和预分频器
- 启动定时器中断,开启定时器
- 中断服务函数翻转 LED
time.h
// =============================================
# @Time : 2020-10-22
# @Author : AXYZdong
# @FileName: time.h
# @Software: keil5 MDK
// =============================================
#ifndef _TIME_H
#define _TIME_H
#include "stm32f4xx.h"
//宏定义
#define BASIC_TIM TIM6
#define BASIC_TIM_CLK RCC_APB1Periph_TIM6
#define BASIC_TIM_IRQn TIM6_DAC_IRQn
#define BASIC_TIM_IRQHandler TIM6_DAC_IRQHandler
void TIM_Config(uint16_t ARR , uint16_t PSC);
#endif
time.c
// =============================================
# @Time : 2020-10-22
# @Author : AXYZdong
# @FileName: time.c
# @Software: keil5 MDK
// =============================================
#include "time.h"
#include "bsp_led.h"
extern void TIM_Config(uint16_t ARR , uint16_t PSC);
void TIM_Config(uint16_t ARR , uint16_t PSC)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = BASIC_TIM_IRQn;//定时器中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
/*
*注意:TIM_TimeBaseInitTypeDef 结构体里面有 5 个成员,TIM6 和 TIM7 的寄存器里面只有
*TIM_Prescaler 和 TIM_Period,所以使用 TIM6 和 TIM7 的时候只需初始化这两个成员即可,
* 另外三个成员是通用定时器和高级定时器才有.
*-----------------------------------------------------------------------
* TIM_Prescaler 都有
* TIM_CounterMode TIMx,x[6,7]没有,其他都有(基本定时器)
* TIM_Period 都有
* TIM_ClockDivision TIMx,x[6,7]没有,其他都有(基本定时器)
* TIM_RepetitionCounter TIMx,x[1,8]才有(高级定时器)
*-----------------------------------------------------------------------
*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(BASIC_TIM_CLK, ENABLE); //开启 TIMx_CLK
TIM_TimeBaseInitStruct.TIM_Period = ARR; //累计 TIM_Period 个后产生一个更新或者中断
TIM_TimeBaseInitStruct.TIM_Prescaler = PSC; //设定定时器频率
TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseInitStruct); //初始化定时器 TIMx
TIM_ITConfig(BASIC_TIM, TIM_IT_Update, ENABLE); //开启定时器更新中断
TIM_Cmd(BASIC_TIM, ENABLE); //使能定时器
}
void BASIC_TIM_IRQHandler()
{
if(TIM_GetITStatus(BASIC_TIM , TIM_IT_Update) == SET)
{
LED0 = ~ LED0;
TIM_ClearITPendingBit(BASIC_TIM , TIM_IT_Update);
}
}
main.c
// =============================================
# @Time : 2020-10-22
# @Author : AXYZdong
# @FileName: main.c
# @Software: keil5 MDK
// =============================================
#include "stm32f4xx.h"
#include "time.h"
#include "bsp_led.h"
int main(void)
{
LED_GPIO_Config(); //初始化LED
TIM_Config(9999,8399); //初始化定时器
while(1)
{
}
}
六、总结
- 宏定义的使用可以便于代码移植
- LED 状态翻转使用了
位带
操作 - 软件设置的定时时间和 LED 闪烁时间不太一致,不清楚哪个地方出问题了?有知道的小伙伴可以 👇 下方留言告诉我哦
【参考文献】
[1] 《零死角玩转 STM32—基于野火 F407[霸天虎]开发板 》
本次的分享就到这里
好书不厌百回读,熟读自知其中意。将学习成为习惯,用知识改变命运,用博客见证成长,用行动证明努力。
如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏”
一键三连哦!
听说 👉 点赞 👈 的人运气不会太差,每一天都会元气满满呦!^ _ ^
**码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了👉关注👈我哦!
如果以上内容有任何错误或者不准确的地方,欢迎在下面👇留个言。或者你有更好的想法,欢迎一起交流学习~~~
- 点赞
- 收藏
- 关注作者
评论(0)