STM32学习(七)定时器

定时器的基本知识

定时器的功能

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);
	}
}

 

 

书签工具

从左到右:添加书签(删除书签),跳到上一个书签,跳到下一个书签,删除全部书签 

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值