美文网首页
STM32定时器学习---基本定时器

STM32定时器学习---基本定时器

作者: 呼啦啦的爱 | 来源:发表于2020-02-12 15:00 被阅读0次

      STM32F1系列的产品,除了互联网产品外,工作8个,3种定时器,其中一种就是基本定时器。那么STM32单片机的基本定时器如何操作以及编程呢?

      下面我们就来详细的了解一下

      STM32F1系列的产品,除了互联型产品外,工位8个定时器

      TIM6、TIM7:基本定时器

      TIM2/3/4/5:通用定时器

      TIM1、TIM8:高级定时器

      三种定时器的区别:

      基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。简单的说两个定时器是从0计数到N(由自动装载计数器来确定N的具体值),然后复位回0

    重新计数。每次复位到0 的时候可以产生对应的中断信号,或者产生DMA 请求,还可以触发DAC 同步电路。不过这次笔记不讨论触发DAC 的问题,等写到DAC

    的使用时在讲解如何用这两定时器驱动DAC。

      基本定时器TIM6和TIM7挂载在APB1总线上,在使用之前需要先使能对应的时钟信号。对应的语句如下:

      [cpp] view plaincopy

      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);

      APB1

    总线上的时钟信号在进入定时器之后第一件事情是被预分频器TIMx_PSC分频。程序中随时都可以更改TIMx_PSC的值,但是TIMx_PSC是有缓冲的,只有发生了更新事件时新的预分频值才会生效。

      另外有一点必须要特别注意:如果我们想对 CK_PSC 时钟信号N 分频的话,TIMx_PSC 中应该写入 M - 1,而不是 M。

      对应的语句如下:

      [cpp] view plaincopy

      TIMx->PSC = M - 1;

      如果我们希望立刻更新预分频器也是有办法的,那就是软件触发一次更新事件。TIM6和TIM7有个事件产生寄存器(TIMx_EGR)

    就是起这个作用的。TIMx_EGR 只有最低位有用,称之为 UG 位,向这一位写入 1 则产生更新事件,定时器的计数器被归零。

      对应的语句如下:

      [cpp] view plaincopy

      TIMx->EGR = 0x0001;

      自动重装载寄存器TIMx_ARR决定了CNT

    计数器最高记到多少就会归零。自动重装载寄存器也是带缓存的。如果TIMx_CR1寄存器中的自动重装载预加载使能位(ARPE)为0,则写入自动重装载寄存器的值立即起作用。如果ARPE

    = 1,则要等到发生了更新事件后才会起作用。举例来说,当前自动重装载寄存器的值为20000,CNT 计数器的值为1000,ARPE =

    1,这时我们向自动重装载寄存器写个 5000,CNT 计数器记到 5000

    时并不会归零,它还要继续直到记到20000然后归零,在归零的同时产生计数器溢出事件,计数器溢出事件可以产生更新事件,之后自动重装载寄存器的值才真的变为5000了。

      这里出现了两个事件:计数器溢出事件和更新事件。这两个实际是不同的。每次当计数器溢出时都会产生计数器溢出事件,但是不一定产生更新事件。

      TIM6和TIM7控制寄存器1(TIMx_CR1) 有一位UDIS:禁止更新 (Update disable)位。

      如果这位被设置为1,则计数器溢出事件不会产生更新事件。不产生更新事件则预分频器的系数不能被更新,自动重装载寄存器的值也可能不能更新(ARPE =

    1)。

      只是产生更新事件是没有用的,我们最终需要的是产生中断或DMA请求。这里先说中断的产生。

      TIM6和TIM7 DMA/中断使能寄存器(TIMx_DIER) 有一位为UIE。只有这一位为1时才能产生更新中断。

      对应的语句如下:

      [cpp] view plaincopy

      TIMx->DIER |= 0x0001;

      TIM6和TIM7状态寄存器(TIMx_SR) 中也只有一位是有用的,位于这个寄存器的最低位,称之为UIF位。这一位为1

    标志着产生了更新中断。什么时候这一位才能为1呢?简单的说就是产生更新事件这一位会被置位为1,不过也有特殊情况,我们知道有两种情况会产生更新事件:计数器溢出事件和

    UG=1。如果TIMx_CR1的URS位被设为了1,则UG=1 产生的更新事件不会将UIF位置位1。

      一般来说我们都不希望UG=1时产生中断,所以多数时间我们会设置URS位为1。

      对应的语句如下:

      [cpp] view plaincopy

      TIMx->CR1 |= 0x0004;

      下面是一个例子程序,使用TIM6,产生一个5Hz的定时中断。时钟频率为72MHz。

      [cpp] view plaincopy

      void TIM6_Init(void)

      {

      NVIC_InitTypeDef NVIC_InitStructure;

      NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_Init(&NVIC_InitStructure);

      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

      TIM6->PSC = 7200 - 1; // 分频之后的时钟频率为10KHz

      TIM6->ARR = 2000 - 1; // 5Hz 定时频率

      TIM6->CR1 = 0x0004 + 0x0001; // URS = 1 CEN = 1

      TIM6->DIER = 0x0001; // 使能更新中断

      }

      void TIM6_IRQHandler(void)

      {

      LED_Flash(GPIO_LED2);

      TIM6->SR=0x0000;//清标志位

      }

      还可以完全用STM32F10x Standard Peripherals Firmware Library 来写这个程序。下面用TIM7

    实现类似的功能。

      [cpp] view plaincopy

      void TIM7_Init(void)

      {

      TIM_TimeBaseInitTypeDef TIM7_TimeBaseStructure;

      NVIC_InitTypeDef NVIC_InitStructure;

      NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

      NVIC_Init(&NVIC_InitStructure);

      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);

    //RCC_APB1Periph_TIM7

      TIM_TimeBaseStructInit(&TIM7_TimeBaseStructure);

      TIM7_TimeBaseStructure.TIM_Prescaler = 36000 - 1; // 分频之后的时钟频率为2KHz

      TIM7_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

      TIM7_TimeBaseStructure.TIM_Period = 400 - 1; // 5Hz 定时频率

      TIM7_TimeBaseStructure.TIM_ClockDivision = 0;

      TIM_TimeBaseInit(TIM7, &TIM7_TimeBaseStructure);

      TIM_UpdateRequestConfig(TIM7, TIM_UpdateSource_Regular);

      TIM_Cmd(TIM7, ENABLE);

      TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);

      }

      void TIM7_IRQHandler(void)

      {

      if(TIM_GetITStatus(TIM7, TIM_IT_Update)== SET)

      {

      LED_Flash(GPIO_LED3);

      TIM_ClearITPendingBit(TIM7 , TIM_FLAG_Update);

      }

      }

      程序写完了,这里说几点注意事项。

      (1)在对TIMx 进行设置之前一定要打开APB1总线上对应的时钟,否则所有的设置都不起作用。

      (2)一定要设置NVIC,因为默认情况下这些外设的中断都是被禁用的。

      stm32相关的学习资料

      (stm32 USART串口应用)

      http://www.makeru.com.cn/live/1392_1164.html?s=45051

      (定时器)

      http://www.makeru.com.cn/live/1392_1199.html?s=45051

      STM32定时器深藏不露的绝技

      http://www.makeru.com.cn/live/3523_1495.html?s=45051

      stm32 如何用DMA搬运数据

      http://www.makeru.com.cn/live/detail/1484.html?s=45051

      (STM32中断系统)

      http://www.makeru.com.cn/live/1392_1124.html?s=45051

      (时钟系统)

      http://www.makeru.com.cn/live/1392_1082.html?s=45051

      STM32中断系统

      http://www.makeru.com.cn/live/3523_1745.html?s=45051

      STM32可以这样玩

      http://www.makeru.com.cn/live/4034_1460.html?s=45051

    相关文章

      网友评论

          本文标题:STM32定时器学习---基本定时器

          本文链接:https://www.haomeiwen.com/subject/cuccfhtx.html