STM32定时器-基本定时器
实验芯片:STM32F103
更新日期:2021年8月17日
声明:部分图文来自互联网公开资料,转载注明出处
一、基本定时器简介
TIM6和TIM7是一个16位向上递增的定时器。
1.基本定时器主要功能
功能一:基本定时功能,生成时基。
功能二:专门用于驱动,模数转换DAC。
2.基本定时器功能表
定时器类型 | 定时器编号 | 计数模式 | 分辨率 | DMA | 预分频系数 | 通道 | 互补输出 | 逻辑引脚 | 时钟 |
---|---|---|---|---|---|---|---|---|---|
基本定时器 | TIM6、TIM7 | UP | 16bit | YES | 1~65536(0-0xFFFF) | 0 | 0 | NO | APB1 |
注意STM32F103只有大容量256-512K Flash才有基本定时器
基本定时器只有向上计数模式。
二、基本定时器功能框图
首先先看图中绿色框内容,第一个是带有阴影的方框,方框内容一般是一个寄存器名称,比如图中主体部分的自动重载寄存器 (TIMx_ARR) 或 PSC 预分频器 (TIMx_PSC),这里要特别突出的是阴影这个标志的作用,它表示这个寄存器还自带有影子寄存器,在硬件结构上实际是有两个寄存器,源寄存器是我们可以进行读写操作,而影子寄存器我们是完全无法操作的,有内部硬件使用。影子寄存器是在程序运行时真正起到作用的,源寄存器只是给我们读写用的,只有在特定时候 (特定事件发生时) 才把源寄存器的值拷贝给它的影子寄存器。多个影子寄存器一起使用可以到达同步更新多个寄存器内容的目的。接下来是一个指向右下角的图标,它表示一个事件,而一个指向右上角的图标表示中断和 DMA 输出。这个我们把它放在图中主体更好理解。图中的自动重载寄存器有影子寄存器,它左边有一个带有“U”字母的事件图标,表示在更新事件生成时就把自动重载寄存器内容拷贝到影子寄存器内,这个与上面分析是一致。寄存器右边的事件图标、中断和 DMA 输出图标表示在自动重载寄存器值与计数器寄存器值相等时生成事件、中断和 DMA 输出。
1.时基单元
16位计数器TIMx_CNT
16位分频器TIMx_PSC
16位自动重装载寄存器TIM_ARR
影子寄存器-用户读写操作实际操作的寄存器
预分频寄存器TIMx_PSC
自动重装载寄存器TIMx_ARR
计数器时钟CK_CNT
定时器 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 (0~0xFFFF)之间的任何一个数进行分频。具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。
计数器CNT
计数器 CNT 是一个 16 位的计数器,只能往上计数,从0开始计数,最大计数值为 65535(0xFFFF)。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
自动重装载寄存器
自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
2.时钟源
定时器实现计数功能必须有个时钟源,基本定时器时钟TIMxCLK只能来自内部时钟CK_INT(经APB1预分频器分频后提供,若APB1预分频系数位1,则频率不变,否则频率乘以2,库函数中APB1预分频的系数是2,PCLK1=32M,则TIMxCLK=36*2=72M),高级定时器和通用定时器还可以选择外部时钟源或直接来自其他定时器等待模式。
我们可以通过 RCC 专用时钟配置寄存器 (RCC_DCKCFGR) 的 TIMPRE 位设置所有定时器的时钟频率,我们一般设置该位为默认值 0,即 TIMxCLK 为总线时钟的两倍,中可选的最大定时器时钟为 84MHz,即基本定时器的内部时钟 (CK_INT) 频率为 84MHz。基本定时器只能使用内部时钟,当 TIM6 和TIM7 控制寄存器 1(TIMx_CR1) 的 CEN 位置 1 时,启动基本定时器,并且预分频器的时钟来源就是 CK_INT。
3.控制器
定时器控制器控制实现定时器功能,控制定时器复位、使能、计数其基础功能,基本定时器还专门用于 DAC 转换触发。
4.计数器
基本定时器计数过程主要涉及到三个寄存器内容,分别是计数器寄存器 (TIMx_CNT)、预分频器寄存器 (TIMx_PSC)、自动重载寄存器(TIMx_ARR),这三个寄存器都是 16 位有效数字,即可设置值为 0 至 65535(0~0XFFFF)。
预分频器PSC,有一个输入时钟CK_PSC和一个输出时钟CK_CNT。输入时钟CK_PSC来源于控制器部分,基本定时器只有内部时钟源,因此CK_PSC=CK_INT。输出频率F(CK_CNT)=F(CK_PSC)/(PSC+1)。
计时时更改PSC时,不会马上更新CK_CNT输出频率,而是等到更新事件发生时。把PSC寄存器的值更新到影子寄存器中,这才真正产生效果。
如下图。PSC由1变为4过程。
在定时器使能 (CEN 置 1) 时,计数器 COUNTER 根据 CK_CNT 频率向上计数,即每来一个CK_CNT 脉冲,TIMx_CNT 值就加 1。当 TIMx_CNT 值与 TIMx_ARR 的设定值相等时就自动生成事件并 TIMx_CNT 自动清零,然后自动重新开始计数,如此重复以上过程。为此可见,我们只要设置 CK_PSC 和 TIMx_ARR 这两个寄存器的值就可以控制事件生成的时间,而我们一般的应用程序就是在事件生成的回调函数中运行的。在 TIMx_CNT 递增至与 TIMx_ARR 值相等,我们叫做为定时器上溢。
自动重载寄存器 TIMx_ARR 用来存放于计数器值比较的数值,如果两个数值相等就生成事件,将相关事件标志位置位,生成 DMA 和中断输出。TIMx_ARR 有影子寄存器,可以通过 TIMx_CR1寄存器的 ARPE 位控制影子寄存器功能,如果 ARPE 位置 1,影子寄存器有效,只有在事件更新时才把 TIMx_ARR 值赋给影子寄存器。如果 ARPE 位为 0,修改 TIMx_ARR 值马上有效。
三、定时时间计算
定时器的定时时间等于计数器的中断周期乘以中断的次数。
计数器在CK_CNT的驱动下,计1个数的时间是CK_CNT的倒数,1/(TIMxCLK/(PSC+1))。
产生一次中断的时间等于1/(CK_CLK*ARR)
四、定时器初始化结构体
用于定时器基础参数设置于TIM_TimeBaseInit ()函数配合使用完成配置。
typedef struct
{
uint16_t TIM_Prescaler;//指定TIM时钟的预分频值,范围0x0000-0xFFFF
uint16_t TIM_CounterMode;//指定计数模式,基本定时器只能向上计数,无需初始化
uint16_t TIM_Period;//指定自动装载值,即定时器周期,范围0x0000-0xFFFF
uint16_t TIM_ClockDivision;//指定定时器时钟于数字滤波器采样时钟分频比,基本定时器无此功能
uint8_t TIM_RepetitionCounter;//指定重复计数器的值,基本定时器无需设置
} TIM_TimeBaseInitTypeDef;
基本定时器只需用到TIM_Prescaler和TIM_Period即可。
五、基本定时器配置实例
注意STM32F103只有大容量256-512K Flash才有基本定时器
void Basic_TIM6_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 设置中断组为 0
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
// 设置中断来源
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
// 设置主优先级为 0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// 设置抢占优先级为 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Basic_TIM6_Init(uint16_t arr, uint16_t pre)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //定时器时钟CK_INT=2*PCLK1=2*32MHz=72MHz
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = pre; //CK_CNT=CKINT/(pre+1)
// 时钟分频因子 ,基本定时器没有,不用管
//TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //定时器6、7没有
// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
//TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//定时器6、7没有
// 重复计数器的值,基本定时器没有,不用管
//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;//定时器1、8、15、16、17才有
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); //初始化定时器
Basic_TIM6_NVIC_Config(); //中断配置
TIM_ClearFlag(TIM6, TIM_FLAG_Update); //清除计数器中断标志位
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); //开启计数器更新中断(上溢中断)
TIM_Cmd(TIM6, ENABLE); //使能计数器
}
void TIM6_IRQHandler(void)
{
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update);
/*
your code!
*/
}
}