STM32 基本定时器


本文为野火学习笔记。

定时器分类

   stm32f1系列。除互联型设备,共有8个定时器,分为基本,通用,高级3种定时器。不同的定时器有不同的功能。
  基本定时器为 TIM6,TIM7 。其只能定时,没有外部IO,且16位计数器只能向上计数。
  通用定时器为 TIM2/3/4/5 , 可以定时;也可输出比较和输入捕捉,每个定时器有4个IO,16位计数器可上下计数。
  高级定时器为 TIM1/8 ,在通用的基础上多了互补输出信号的功能,每个定时器有8个IO口。

功能框图

  下图为基本定时器的结构框图:

  1. 时钟源
      定时器的时钟源名为 TIMxCLK,可以在时钟树中找到

  可见 TIMxCLK 时钟是来自于APB1 的,而 APB1 的预分频器一般选择2分频,使得 APB1 总线的时钟为36M;因此,TIMExCLK 的时钟为72M.

  1. 计数器时钟
      时钟接入触发控制器,经过 PSC 预分频器分频,驱动CNT计数器。 PSC 为16位分配器,可对时钟信号进行1~65536分频。最终计数器的时钟计算公式如下。
    C K _ C N T   =   T I M x C L K P S C + 1 CK\_CNT ~= ~\frac{TIMxCLK}{PSC+1} CK_CNT = PSC+1TIMxCLK
      公式中分母+1的操作是官方规定的。

  2. 计数器
       CNT 为16位计数器,只能向上计数,计数达到指定数时,更新事件,清零从头计数。

  3. 自动重载寄存器
      寄存器中储存着计数最大值,计到此数,若配置了中断,会产生中断。

  4. 影子寄存器
      自动重载寄存器ARR和预分频器PSC下有阴影,表示其有影子寄存器。影子寄存器起到缓冲的作用,若在计数器仍在计数时,修改ARR或PSC的值,如果直接写入,则计数器直接清零,重新开始计数。若向影子寄存器写入,则会在当前计数周期结束后,修改值,计数器不会被打断。

定时器时间计算

  每记一次耗费时间为 1 C K _ C L K \frac{1}{CK\_CLK} CK_CLK1,计数器计满一次所需时间为 A R R C K _ C L K \frac{ARR}{CK\_CLK} CK_CLKARR,即为: A R R P S C + 1 T I M x C L K ARR\frac{PSC+1}{TIMxCLK} ARRTIMxCLKPSC+1
  当计时器时钟为 72M,PSC预分频器为71,自动重装载ARR为1000时,计满一次的时间即为 1000 72 72 M   = 1 m s 1000\frac{72}{72M}~=1ms 100072M72 =1ms.

中断

  基本定时器只在溢出时才会产生中断,溢出时也可产生DMA请求。TIMx_DIER寄存器控制DMA和中断的使能,TIMx_EGR 寄存器记录溢出事件的产生。

固件库编程

定时器初始化结构体

typedef struct
{
  uint16_t TIM_Prescaler;            //预分频器
  uint16_t TIM_CounterMode;          //计数模式
  uint16_t TIM_Period;               //ARR
  uint16_t TIM_ClockDivision;        //时钟分频
  uint8_t TIM_RepetitionCounter;     //重复计数器
} TIM_TimeBaseInitTypeDef; 

   在这里,计数模式表示的是向上还是向下计数。最后两个参数是不是基本定时器的功能,不用配置。

开始编程

  基本寄存器十分简单,只能计时。这里编写一个使得LED以1秒间隔闪烁的程序。

初始化TIM6

void BASIC_TIM_Config(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
		
	//BASIC_TIM_NVIC_Config();   //后面加上这句
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
	
	TIM_TimeBaseStruct.TIM_Period     = 1000;
	TIM_TimeBaseStruct.TIM_Prescaler  = 71;
	
	TIM_TimeBaseInit(TIM6,&TIM_TimeBaseStruct);
	
	//清除中断标志位
	TIM_ClearFlag(TIM6,TIM_FLAG_Update);
	//使能中断请求
	TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
	//使能计数器
	TIM_Cmd(TIM6,ENABLE);
	//暂时关闭时钟,等待使用

}

  基本定时器只能向上计数,因此,初始化结果体中只需配置 PSC 和ARR。配置PSC=71,ARR=1000。即计数一次为1ms。
  接下来我们希望在计数完成发生中断,按照 中断应用总结 中的步骤,使能外设中断。
  使用 TIM_ClearFlag 清除中断标志位,计数溢出的事件被称为更新事件,对应固件库中的标志位叫 TIM_FLAG_Update。然后使用 TIM_ITConfig 使能更新事件的中断。
  最后使用 TIM_Cmd 使能定时器。这里我们完成了TIM6的初始化和外设中断使能,下面继续配置中断。

配置中断优先级分组

  因程序只有这一个中断,优先级分组并不重要,这里配置中断优先级分组为0;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

配置NVIC

static void BASIC_TIM_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	
	NVIC_InitStruct.NVIC_IRQChannel    = TIM6_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 3;
	
	NVIC_Init(&NVIC_InitStruct);
}

  配置主优先级为0,子优先级为3。在初始化 TIM6 中使用这个函数。

中断服务函数

  在 startup_stm32f10x_hd.s 中找到TIM6中断的函数名,在 stm32f10x_it.c 编写中断服务函数。

extern volatile uint16_t time;
void TIM6_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM6,TIM_IT_Update) != RESET)
	{
		time++;
		TIM_ClearITPendingBit(TIM6,TIM_IT_Update);//清除中断标志位
	}
}

进入中断后,检查是否真的中断,并设一个全局变量 time, 用来完成1s的记录。最后使用 TIM_ClearITPendingBit 清除中断标志位。

main函数

#define LED_G_GPIO_PIN   GPIO_Pin_0
#define LED_G_GPIO_PORT  GPIOB
#define LED_G_TEOOGLE   {LED_G_PPIO_RORT->ODR ^= LED_G_GPIO_PIN;}

volatile uint16_t time=0;

int main(void)
{
	LED_GPIO_Config();
	BASIC_TIM_Config();
	while(1)
	{
		if (time ==1000)//1s一进
		{
			time = 0;//计时归零
			LED_G_TEOOGLE;//led反转
		}
	}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值