STM32笔记 (十)定时器(基本定时器)利用基本定时器实现毫秒延时

简介

定时器的主要功能是用来定时,不过STM32中有多种类型的定时器-----基本定时器、通用定时器、高级控制定时器,以STM32F103ZET6为例,有有 8 个16位定时器,其中 TIM6 和 TIM7 是基本定时器TIM2/3/4/5是通用定时器TIM1/8是高级定时器,本篇主要讲基本定时器。

寄存器

  • TIM6 和TIM7 控制寄存器 1(TIMx_CR1)
  • TIM6 和TIM7 控制寄存器 1(TIMx_CR1)
  • TIM6 和TIM7 控制寄存器 1(TIMx_CR1)
  • TIM6 和TIM7 状态寄存器(TIMx_SR)
  • TIM6 和TIM7 事件产生寄存器(TIMx_EGR)
  • TIM6 和TIM7 计数器(TIMx_CNT)
  • TIM6 和TIM7 计数器(TIMx_CNT)
  • TIM6 和TIM7 计数器(TIMx_CNT)

功能框图

在这里插入图片描述

  • 这里的CK_CNT也就是计数器时钟,是TIMxCLK经过PSC预分频器分频后得到的,PSC预分频器可以设置的分频范围为: 1~65536 ,具体计算方式为: CK_CNT=TIMxCLK/(PSC+1),注意这里的PSC要加一,因为不可能有0分频存在,至少是1分频
  • 对于基本定时器只能向上计数,也就是只能从小加到大,加到多少主要由自动重装载寄存器 ARR决定,ARR是一个16位的寄存器,里面装着计数器能加到的最大值,如果计数器加到了这个值并且使能了中断的话就会产生溢出中断(更新中断)
    在这里插入图片描述
  • 由于基本定时器向上计数是从0开始的,因此计数的初始值为0,所以我们设置ARR的值的时候要减去1,也就是ARR-1,比如我们要计数十次,那么久设置ARR的值为9,因为计数是从0开始的,0计数到9就是计数了十次

定时时间的计算

每次计数加1的时候所需要的时间为:1/CK_CNT,而CK_CNT=TIMxCLK/(PSC+1),对于STM32F1系列,基本定时器的TIMxCLK的频率为72MHz,为了方便计算,我们把PSC+1设置成72,刚好可以得到一个整数的CK_CNT,这时候每一次计数+1所需的时间为:1us,一微秒,所以如果要计时1ms,就把ARR的值设置成999,也就是1us计数一千次

基本定时器的结构体

 typedef struct {
 
	TIM_Prescaler // PSC分频因子
	
	TIM_CounterMode // 计数模式,基本定时器只能向上计数,不用设置
	
	IM_Period //自动重转载寄存器ARR的值
	
	TIM_ClockDivision // 外部输入时钟分频因子,基本定时器没有,其他都有
	
	TIM_RepetitionCounter // 重复计数器,基本定时器没有
	
 } TIM_TimeBaseInitTypeDef;

由此可知,对于基本定时器我们只需配置

  • PSC分频因子 TIM_Prescaler
  • 自动重转载寄存器ARR的值 IM_Period

利用基本定时器6实现500ms延时

首先先来计算一下产生1ms的延时要怎么配置ARR和PSC
首先把PSC预分频设置成72分频,也就是TIM_Prescaler =71,这时候每次计数所用时间为1us,我们计数1000次就是1ms,所以ARR的值要设置成999,也就是IM_Period = 999
配置流程图:
在这里插入图片描述
代码:

#include "stm32f10x.h"
#include "bsp_led.h"

uint16_t time=0;//定义全局变量time

//TIM6定时器NVIC配置
void TIM_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;//中断源
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//主优先级为 0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//NVIC使能
	
	NVIC_Init(&NVIC_InitStructure);
}

//TIM6初始化
void BasicTIM_Config(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);//使能定时器时钟
	
	TIM_TimeBaseStructure.TIM_Period = 999;   //自动重转载寄存器
	TIM_TimeBaseStructure.TIM_Prescaler = 71; //PSC分频因子
	
	TIM_TimeBaseInit(TIM6,&TIM_TimeBaseStructure);
	
	TIM_ClearFlag(TIM6, TIM_FLAG_Update);	//清除中断标志

	TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);// 开启计数器中断
	
	TIM_Cmd(TIM6, ENABLE);// 使能计数器
	
	TIM_NVIC_Config();//TIM6定时器NVIC配置
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,DISABLE);//暂时关闭定时器的时钟 需要使用时再打开
}

//开启定时器6
void TIM6_ON()
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
}

//关闭定时器6
void TIM6_OFF()
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,DISABLE);
}
int main(void)
{	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//由于使用到了中断,因此这里需要设置优先级分组
	
	LED_Config();//初始化LED
	
	BasicTIM_Config();//初始化TIM6
	
	TIM6_ON();//开启定时器6
	
	while(1)
	{
		if(time >= 500) //如果时间到了500ms
		{
			time = 0;
			LED1(TOGGLE);//LED亮或灭
		}
	}
}

//TIM6中断服务函数
void TIM6_IRQHandler(void)
{
	
	if(TIM_GetITStatus( TIM6, TIM_IT_Update) != RESET )//如果TIM6产生了更新中断
	{	
		time++; //通过前面的运算,每产生一次更新中断的时间是1ms(计数器每次溢出为1ms)
		TIM_ClearITPendingBit(TIM6 , TIM_FLAG_Update);//清除中断标志位
	}
	
}

原创文章 12 获赞 0 访问量 1100

猜你喜欢

转载自blog.csdn.net/zcy_cyril/article/details/106024485