开发手册+标准库底层实现入门STM32三(基本定时器TIM)

定时器是用于测量或产生特定时间间隔的的外设。通过这个特定的时间间隔,我们可以实现1.定时中断,2.测量输入信号脉冲宽度,3.产生精确的输出波形(PWM)等功能。

STM32中拥有三种定时器,基本定时器、通用定时器、高级定时器。

基本定时器(TIM6、TIM7)

基本定时器包含一个16位(0-65535)的自动装载计数器(存储计数的最值)。可以通过内部时钟RCC和预分频器(PSC)提供计次频率。

使用规定的计次频率,通过递增、递减等方式,达到设定的数值后,定时器会产生事件或中断。

时基单元

时基单元用于配置定时器的计次频率、计数值。拥有三个寄存器

  1. 计数器寄存器(TIMx_CNT):用于存储定时器当前计数。

16位(0-65535)

当控制寄存器(TIMx_CR1)写入使能时,CNT会持续计数。

  1. 自动重装载寄存器(TIMx_ARR):用于存储设定的定时器计数值。

16位(0-65535)

在自动重装载寄存器之外还有个预加载寄存器,每次读写自动重装载寄存器中的数值时,实际是写入到预加载寄存器,当上次的定时周期结束后,才会在下一次定时周期中,将预加载寄存器的值写入到自动重装载寄存器中(也可设置直接写入,通过自动重装预加载器(ARPE)使能决定)。

  1. 预分频寄存器(TIMx_PSC):用于将内部时钟进行分频。

16位(0-65535)

可以对内部时钟信号进行分频,一般内部时钟信号位72MHZ,也就是每秒计数72000000次,很显然远大于65535,不够计数的,整个定时器都不能计次1s。因此需要对时钟信号进行分频。如果7200分频,那就是72MHZ/72000=1000次,每秒就会计次1000次,也就是1000HZ。如果希望定时器每一秒产生一次中断,那么只需再令ARR=1000。

时序图

现在来了解下预分频器变化的定时器时序图(以预分频系数从1变道4为例)

寄存器

TIM6和TIM7控制寄存器1(TIMx_CR1)

16位。

两个使能位,ARPE——使能自动重装载(ARR),CEN——使能计数器(CNT)。

OPM——在执行定时器事件时,CNT是否停止计数。

URS——选择更新事件的来源,是否是只设置计数器上溢/下溢可产生更新中断(是否使能 设置UG、从模式控制器 导致的更新中断)

UDIS——控制是否禁止更新事件发生。如果设置为1,则即使触发了更新事件,也不会更新定时器的影子寄存器。

标准库中与CR1寄存器相关的函数有

//ARPE位,自动重装载计数器使能
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState){
  if (NewState != DISABLE){
    TIMx->CR1 |= TIM_CR1_ARPE;//失能
  }
  else{
    TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_ARPE);//失能
  }
}
//URS位,设置更新请求源
void TIM_UpdateRequestConfig(TIM_TypeDef* TIMx, uint16_t TIM_UpdateSource)
{
  if (TIM_UpdateSource != TIM_UpdateSource_Global){
    TIMx->CR1 |= TIM_CR1_URS;
  }
  else{
    TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_URS);
  }
}
//UDIS位,使能或失能TIMx更新事件
void TIM_UpdateDisableConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
{
  if (NewState != DISABLE){
    TIMx->CR1 |= TIM_CR1_UDIS;
  }
  else{
    TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_UDIS);
  }
}
//OPM位,设置单脉冲模式
void TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode)
{
  TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_OPM);
  TIMx->CR1 |= TIM_OPMode;
}

都是很简单地直接对寄存器进行配置。但这么多函数,感觉通过标准库配置CR1寄存器整个配置下来还是很麻烦的。

TIM6和TIM7 DMA/中断 使能寄存器(TIMx_DIER)

16位

标准库中的定时器使能函数就是通过直接向DIER寄存器赋值

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
{  
  if (NewState != DISABLE){
    TIMx->DIER |= TIM_IT;//失能
  }
  else{
    TIMx->DIER &= (uint16_t)~TIM_IT;//使能
  }
}

TIM6和TIM7状态寄存器(TIMx_SR)

16位

当产生更新中断时,UIF(Update Interrupt Flag)位置1,并在执行完事件后,自动清零(不像EXTI一样需要手动清零)

在标准库中的函数:可直接读取SR的值

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)
{ 
  ITStatus bitstatus = RESET;  
  if ((TIMx->SR & TIM_FLAG) != (uint16_t)RESET){
    bitstatus = SET;
  }
  else{
    bitstatus = RESET;
  }
  return bitstatus;
}

TIM6和TIM7事件产生寄存器(TIMx_EGR)

更新事件是指,计数器达到了自动重装载值,于是计数器清零(CNT寄存器更新)、预分频器清零(ARR_CNT清零)

//设置 TIMx 事件由软件产生
void TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_EventSource)
{ 
  TIMx->EGR = TIM_EventSource;
}
//在基本定时器中,事件源只有TIM_EventSource_Update,更新事件源

TIM6和TIM7计数器(TIMx_CNT)

标准库函数:

void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter)
{
  TIMx->CNT = Counter;
}

TIM6和TIM7预分频器(TIMx_PSC)

标准库函数:

void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
{
  TIMx->PSC = Prescaler;
  TIMx->EGR = TIM_PSCReloadMode;
}

TIM6和TIM7自动重装载寄存器(TIMx_ARR)

在ARR之外还有个ARR_CNT,ARR是设置的ARR_CNT计数达到的最大值,同样,当ARR_CNT=ARR时,ARR_CNT清零。

标准库函数:

void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload)
{
  TIMx->ARR = Autoreload;
}

CNT、PSC、ARR都是16位寄存器,也是配置定时器最基本的参数。作为时基单元,它们可以使用一个结构体统一配置:

typedef struct
{
  uint16_t TIM_Prescaler;//预分频系数(PSC)
  uint16_t TIM_CounterMode;//计数模式(自增/自减等)
  uint16_t TIM_Period;//计数周期,也就是自动重装载置(ARR)
  uint16_t TIM_ClockDivision;//时钟分频,直接对RCC分频
  uint8_t TIM_RepetitionCounter;//重复计数器(仅高级定时器有效)
} TIM_TimeBaseInitTypeDef;
//将结构体值传给寄存器
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值