定时器的基本知识
定时器的功能
TIM(Timer)定时器
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能
根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
定时器的分类
基本定时器的结构
分频器:预分频器的值+1=分频值 分频值为2,二分频:频率=72MHz/2 三分频:频率=72MHz/3
预分频器是16位的。计数器不断与自动重装载寄存器比较,直到相等
DAC功能:能够将主模式映射到TRGO,不需要中断就可以完成DAC
通用计数器结构
基本定时器只支持向上计数(自增)模式,其他两种定时器支持向下计时(自减)和中央对齐模式。
高级计数器结构
定时中断基本结构
结构框图
预分频器时序
第一个是72MHz内部时钟,第二个使能信号
推断自动重装值为FC,到达FC时产生更新时间并重置为0
预分频器控制寄存器:计数一半时改变预分频器频率,必须等到下一个周期再改变频率
预分频器计数器是分频的原理
计数器时序
更新中断标志需要再中断函数中手动清零
计数器预装功能
有引入影子计数器的情况,让这个计数周期结束之后再修改自动重装值
时钟树
定时器程序部分
在System组中新建一个Timer的C文件和相应的H文件
extern可以跨文件使用变量
定时器Timer.h头文件
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
#endif
定时器.C文件
#include "stm32f10x.h" // Device header
extern uint16_t NUM;
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//这个定时器是挂靠在APB1线上的外设,上面有这个TIM2的设备
TIM_InternalClockConfig(TIM2);//选择时钟为内部时钟
//下面配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//声明一个结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//分频模式用于滤波,几个值区别不大
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//这个在库函数time.c的最上方,找一下这个MODE,选计数方式向上,向下,对齐
TIM_TimeBaseInitStructure.TIM_Period=10000-1;//一共要计10000个数再重装一次
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//对72MHz的时钟进行分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//高级定时器参数
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清楚标志位,因为程序启动时会自动清除触发一次中断
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//配置中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//更新中断通路
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//优先级分组
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//通过多重搜索找到定时器2
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//响应优先级和抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);//启动定时器2
}
//编写中断函数
void TIM2_IRQHandler(void)//其实中断函数可以在任意位置
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//检查中断标志位,SET是中断开启
{
NUM++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除标志位
}
}
主程序
#include "stm32f10x.h" // Device header
#include "Delay.h"//需要引用延时函数
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "Timer.h"
uint16_t NUM;
int main()
{
LED_Init();
Key_Init();
Timer_Init();
OLED_Init();
OLED_ShowString(1,1,"NUM:");//通过加入空格字符可以局部删除,注意字符串时双引号
while(1)
{
OLED_ShowNum(1,5,NUM,5);
// OLED_ShowNum(2,1,TIM_GetCounter(TIM2),5);//显示计数器值
}
}
利用外部中断进行定时
.h文件
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
uint16_t Time_GetCounter(void);
#endif
.c文件
#include "stm32f10x.h" // Device header
extern uint16_t NUM;
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//这个定时器是挂靠在APB1线上的外设,上面有这个TIM2的设备
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;//配置GPIO口A0
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0X00);//选择外部时钟
//参数值为:哪个时钟,是否分频,正向/反向,滤波数值
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//声明一个结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//分频模式用于滤波,几个值区别不大
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//这个在库函数time.c的最上方,找一下这个MODE,选计数方式向上,向下,对齐
TIM_TimeBaseInitStructure.TIM_Period=10-1;//一共要计10个数再重装一次
TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//对72MHz的时钟进行分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//高级定时器参数
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清楚标志位,因为程序启动时会自动清除触发一次中断
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
//配置中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//更新中断通路
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//优先级分组
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;//通过多重搜索找到定时器2
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//响应优先级和抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);//启动定时器2
}
//编写中断函数
void TIM2_IRQHandler(void)//其实中断函数可以在任意位置
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)//检查中断标志位,SET是中断开启
{
NUM++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除标志位
}
}
//查看计数值函数
uint16_t Time_GetCounter(void)
{
return TIM_GetCounter(TIM2);
}
main函数
#include "stm32f10x.h" // Device header
#include "Delay.h"//需要引用延时函数
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "Timer.h"
uint16_t NUM;
int main()
{
LED_Init();
Key_Init();
Timer_Init();
OLED_Init();
OLED_ShowString(1,1,"NUM:");//通过加入空格字符可以局部删除,注意字符串时双引号
OLED_ShowString(2,1,"CNT:");
while(1)
{
OLED_ShowNum(1,5,NUM,5);
// OLED_ShowNum(2,1,TIM_GetCounter(TIM2),5);//显示计数器值
OLED_ShowNum(2,5,Time_GetCounter(),5);
}
}
书签工具
从左到右:添加书签(删除书签),跳到上一个书签,跳到下一个书签,删除全部书签