一、基本定时器的介绍:
STM32F1 系列中(除了互联型的系列),一共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。在本文章仅介绍基本定时器的使用。STM32F1 系列中,基本都定时器是TIM6 和TIM7 ,他们俩个都是一个 16 位的只能向上计数的定时器,只能定时,没有外部IO。
二、基本定时器的功能
TIM6
和
TIM7
定时器的主要功能包括:
(1)16
位自动重装载累加计数器.
(2)
16
位可编程
(
可实时修改
)
预分频器,用于对输入的时钟按系数为
1
~
65536
之间的任意数值
分频。
(3)触发
DAC
的同步电路。
(4) 在更新事件
(
计数器溢出
)
时产生中断
/DMA
请求。
三、基本定时器的框图:
框图说明:
带有阴影的方框, 方框内容一般是一个寄存器名称,比如图中主体部分的自动重载寄存器 (TIMx_ARR) 或
PSC 预分频器 (TIMx_PSC)
,这里要特别突出的是阴影这个标志的作用,它表示这个寄存器还自带有 影子寄存器,在硬件结构上实际是有两个寄存器,源寄存器是我们可以进行读写操作,而影子寄 存器我们是完全无法操作的,有内部硬件使用。影子寄存器是在程序运行时真正起到作用的,源 寄存器只是给我们读写用的,只有在特定时候 (
特定事件发生时
)
才把源寄存器的值拷贝给它的 影子寄存器。多个影子寄存器一起使用可以到达同步更新多个寄存器内容的目的。
指向右下角的图标,它表示一个事件,而一个指向右上角的图标表示中断和 DMA 输出。
四、时钟源
定时器时钟 TIMxCLK
,即内部时钟
CK_INT
,经
APB1
预分频器后分频提供,如果
APB1
预分频 系数等于 1
,则频率不变,否则频率乘以
2
,库函数中
APB1
预分频的系数是
2
,即
PCLK1=36M
, 所以定时器时钟 TIMxCLK=36*2=72M
。
五、计数器时钟
定时器时钟经过 PSC
预分频器之后,即
CK_CNT
,用来驱动计数器计数。
PSC
是一个
16
位的预分频器,可以对定时器时钟 TIMxCLK
进行
1~65536 之间的任何一个数进行分频。公式为:CK_CNT=TIMxCLK/(PSC+1)
。
六、定时器周期计算
定时事件生成时间主要由 TIMx_PSC
和
TIMx_ARR
两个寄存器值决 定,这个也就是定时器的周期。比如我们需要一个 1s
周期的定时器,具体这两个寄存器值该如 何设置内。假设,我们先设置 TIMx_ARR
寄存器值为
9999
,即当
TIMx_CNT
从
0
开始计算, 刚好等于 9999
时生成事件,总共计数
10000
次,那么如果此时时钟源周期为
100us
即可得到刚 好 1s 的定时周期。我们的系统频率默认为74MHz,所以设置预分频器值为
(7200-1)
即可满足。
七、定时器结构体的初始化
typedef struct
{
uint16_t TIM_Prescaler; // 预分频器
uint16_t TIM_CounterMode; // 计数模式
uint32_t TIM_Period; // 定时器周期
uint16_t TIM_ClockDivision; // 时钟分频
uint8_t TIM_RepetitionCounter; // 重复计算器
}TIM_TimeBaseInitTypeDef;
虽然定时器基本初始化结构体有 5
个成员,但对于基本定时器只需设置其中两个(第一和第三个)就可以。
八、在OLED上显示计数器的值与定时器的主函数
定时器的
#include "stm32f10x.h" // Device header
//时钟初始化
void Timer_Init(void)
{
//开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//选择内部时钟
TIM_InternalClockConfig(TIM2);
//TIM_TimeBaseInitTypeDef结构体
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_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InittStructure;
NVIC_InittStructure.NVIC_IRQChannel =TIM2_IRQn ;
NVIC_InittStructure.NVIC_IRQChannelCmd =ENABLE ;
NVIC_InittStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InittStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InittStructure);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
主函数的
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "LED.h"
#include "Timer.h"
uint16_t Num;
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
Timer_Init();
/*OLED显示*/
//OLED_ShowString(1, 3, "HelloWorld!"); //1行3列显示字符串HelloWorld!
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);
}
}