四轴飞行器DIY活动征集报名中!更有现金奉送哦~→ 立即报名 ←
电子产品世界 » 论坛首页 » 高校专区 » 坤创E-Geek/天科大新电社 » 3队MSP-EXP430G2ET学习(六)

共2条 1/1 1 跳转至

3队MSP-EXP430G2ET学习(六)

菜鸟
2019-07-15 19:11:55    评分

MSP-EXP430G2ET定时器学习笔记

     写在前面:我只能说,这块开发板真的不错,虽然比不过32,但是还是有它独特的优点的,虽然有关资料少了些,但是真要是认真学,还真不是太难。为了能更好的理解定时器,我做一张有关定时器的思维导图,希望能帮助大家更好的认识定时器。

       1563181860763546.png 

 一,定时器的介绍

         在所有单片机中,定时器都具有极其重要的作用。因为单片机 CPU 是单线程的,所有任务必须按照顺序执行(除非有中断发生)。像是之前闪烁 LED 程序中的延时就是用 CPU 完成的,这相当于让 CPU 什么也不干,只是掰着手指头数秒,这无疑是对 CPU 的极大浪费。定时器的功能就像是一个可以定时的闹钟,可以帮 CPU 完成延时等重复的劳动,把 CPU 解放出来去完成更重要的工作,如运算、控制等。可以说有了定时器, CPU 才真正成为了一个完整的自由人。MSP430G2 系列单片机的定时器叫做 Timer_A 模块。具体到 MSP430G2553 这个型号,内部有 2 Timer_A 定时器,分别叫做 Timer0_A3 Timer1_A3,或简称 TA0 TA1。 在MSP430 系列定时器的命名规则中, Timer 后面的数字表示定时器的编号;而下划线后面的 A B 表示定时器的类型; A 后面的数字 3 表示定时器中包含 3 个比较/捕获单元。

       Timer_A 定时器是带有中断功能的,当定时器计数值到达设定的值时,将自动产生一个定时器中断信号。我们可以利用这个功能方便地制造一个周期性的中断,这样就可以每隔一段事件执行一个指令。利用这个中断也可以进行延时,并且这样的延时是不需要消耗 CPU 资源的。Timer_A 定时器除了完成计数以外,还“附赠”了一个重要的功能模块,叫做比较/捕获单元。顾名思义,这个单元有捕获和比较这两个功能。捕获功能的作用是可以自动捕捉一个外部信号的电平变化,并记录下该变化发生的时刻。例如一个周期性的方波,可以通过捕获单元分别记录两次上升沿(电平由低变高)或是下降沿(电平由高变低)的时刻,并将二者相减来计算出波形的周期。而比较功能最大的作用是可以自动产生脉宽调制波形(PWM) , 目前各种数字控制信号中很多都是通过 PWM 波来实现的,利用比较功能可以在不消耗 CPU 资源的情况下产生多路 PWM波形。 但需要注意的是,在同一时刻下,一个比较/捕获单元中只能在比较和捕获功能中选择一个进行使用,两个功能是无法同时使用的。 

 二,定时器的功能

     1.计数功能

       (1)计数原理介绍

        其实定时就是跟时间有关,时间也是又数字一个一个累积出来的,而Timer_A 的核心是一个 16 位的计数器,其最大计数值是 2 16 次方,即从 0 65535 之间计数。 在每个定时器的时钟周期, 计数器的值会自动加 1(或减 1,取决于计数模式) , 我们可以通过配置寄存器来选择定时器的时钟周期。 计数器的计数值存在一个名为 TAR 的寄存器当中。 默认状态下, 当计数器的值达到 65535之后,计数器会自动回到 0 并重新开始计数——这叫做计数器溢出。当计数器溢出时,定时器可以产生一个溢出中断, Timer_A 的溢出中断标志位 TAIFG 会被置为 1。 这时如果我们开启了定时器中断使能位 TAIE 以及全局中断使能位,则 MSP430 会自动进入到定时器溢出中断服务函数中。从计数器的工作过程可以看出,只要定时器的时钟源保持精准,那么我们就可以通过计数器来完成精确的时间控制。计数器的值乘以时钟周期就等于真正的时间间隔。 1s=10^-3ms=10^-6um=10^-9nm

         (2)计数器的模式

        计数器共有 4 种工作模式,通过 TACTL 寄存器中的 MCx 位可以配置,其中 MCx=00 为停止,另外 3 种模式分别是:连续计数模式(continuous mode)、向上计数模式(up mode)、向上/向下计数模式(up/down mode)。

            1)停止模式

          设置MCx=00,用于定时器的暂停,并不发生复位,所有寄存器现行类容在停止模式结束后可用。当定时器暂停后重新计数时,计数器将从暂停前的计数方向计数。

            2)连续计数模式(continuous mode

        设置 MCx=10,计数器将工作在连续计数模式下。在此模式下, TAR 寄存器将从 0 65535连续增加,到 65535 后则清零重新计数。在连续计数模式下,定时器的周期仅由时钟源的频率决定,频率越高,则越快计数到 65535,定时器周期越短。 

  TACTL |= MC_2; //选择模式——连续计数


       1563184910164879.pngimage.png

               3) 向上计数模式(up mode
           设置
MCx=01,计数器将工作在向上计数模式。与连续计数模式不同的是, 向上计数模式时计数器的溢出值是由 TACCR0 寄存器设定的,计数器达到设定值后将自动清零。例如将TACCR0 设为 40959,则 TAR 的值只能在 0 40959 之间计数。在向上计数模式下,定时器周期不仅与时钟源有关,还与 TACCR0 的设定值有关。

 TACTL |= MC_2; //选择模式——向上计数
 TACCR0 = 10000;

1563185770686781.pngimage.png

             4) 向上/向下计数模式(up/down mode
           设置
MCx=11,计数器将工作在向上/向下计数模式。与向上计数不同的是,当计数器到达TACCR0 的设定值之后,计数器不清零,而是从递增变成递减,直到计数器的值回到 0。在向上/向下计数模式下,定时器的周期是向上计数模式的两倍。 

 TACTL |= MC_3; //选择模式——向上/下计数
 TACCR0 = 10000;

1563186633562685.png    image.png    

           (2)定时器中断功能

            从上述 3 中工作模式的描述中可以看到,计数器工作时有 2 个关键节点,分别是计数达到CCR0 65535。与之对应的,定时器可以产生 2 个中断,分别是 CCR0 中断和溢出中断,它们对应的中断标志位分别是 CC0IFG TA0IFG。

              1) CCR0 中断
         当计数器的值达到
CCR0 时,定时器会产生 CCR0 中断。 CCR0 中断是定时器所有中断中优先级最高的,并且单独拥有一个中断向量。而 CCR1 CCR2 与定时器溢出中断共用一个中断向量。 CCR0 中断的使能位 CCIE 和标志位 CCIFG 都在 TACCTL0 寄存器中,其中断向量名是TIMER0_A0_VECTOR。要使用 CCR0 中断,首先要使能 CCIE 使能位,然后最关键的一步就是设置 CCR0 寄存器的值。 无论是在向上计数模式还是向上/向下计数模式, 当计数器的值到达 CCR0 CCIFG 都会被置位。 当进入 CCR0 的中断服务函数以后, CCIFG 标志位会自动复位,不需要手动设置。下面是一个 CCR0 中断的示例程序:

int main(void)
{
...
TACCTL0 = CCIE; // CCR0 interrupt enabled 
TACCR0 = 1000; // Set CCR0 value
...
}
// Timer A0 CCR0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A(void)
{
...
}

             2) 定时器溢出中断
             除了
CCR0 中断之外, 计数器还可以产生一个溢出中断。 需要注意的是溢出中断发生的时刻并不是 TAR 的计数值等于溢出值的时刻,而是 TAR 的值返回到 0 的时刻。例如在向上计数模式下, CCR0 中断信号产生的时刻是 TAR 等于 CCR0 的时刻,而溢出中断产生的时刻是 TAR 溢出后返回 0 的时刻,二者相差了一个时钟周期。溢出中断的使能位 TAIE 和标志位 TAIFG 都在 TACTL 寄存器中。溢出中断与CCR1CCR2中断共同分享一个中断向量,向量名是 TIMER0_A1_VECTOR。 那么如果同时开启了溢出中断和CCR1/CCR2 中断, 如何区分究竟是哪一个中断触发了中断向量呢? 在定时器中有一个寄存器TAIV, 它的第 1-3 位包含了中断源的信息。 在中断服务函数中读取 TAIV 寄存器的值可以判断究竟是哪一个中断信号触发了中断。TAIV 的读/写操作都会使当前优先级最高的一个中断标志位自动复位。如果此时还有其他中断在等待,那么该中断会在当前中断结束后执行。例如当前 TACCR1 TACCR2 标志位都被
置位,那么读写 TAIV 之后, TACCR1 的标志位会被自动复位,但 TACCR2 不会。当前中断服务函数执行完之后会直接进入 TACCR2 的中断。

1563187035869229.png

      下面是一个定时器溢出中断的示例程序。与 CCR0 中断相比,主要是多了读取 TAIV 来判断中断源的语句。

int main(void)
{
...
TACTL = TASSEL_2 + MC_2 + TAIE; // smclk、contmode、中断
...
}
// 计时器中断向量(TA0IV)处理程序
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer_A(void)
{
switch( TA0IV )
{   
case     2:     break;     // CCR1未使用
case     4:     break;     // CCR2未使用   
case     10: P1OUT |= 0x01;  break;// 溢出 
 }
}

三,计数器使用的程序流程

   1) 选择定时器的时钟来源(TASSELx)及分频值(IDx),常用的时钟来源有 ACLK SMCLK,此外也可以用外部时钟输入到 TACLK 引脚作为时钟源。

 //内部时钟
  TACTL |= TASSEL_1;//定时器时钟源选择-辅助时钟ACLK 
  TACTL |= ID_0;//定时器A输入分配器 0
 //外部时钟
  TACLK |= TASSEL_2;//定时器时钟源选择-子系统时钟SMCLK
  TACLK |= ID_0;//定时器A输入分配器 0

     1563188409398630.png  1563188534157858.png

       2) 确定定时器工作模式(MCx),即连续计数、向上计数、向上/向下计数,见上图。 

 TACTL |= MC_1; //选择模式——向上计数

      3) 根据定时器工作模式确定使用哪个中断,并进行初始化。如果是 CCR0 中断需要打开使能位并设置 CCR0 的值;如果是溢出中断只要打开使能位即可。

 TACCTL0 |= CCIE;//CCR0中断
 TACCTL1 |= CCIE;//CCR1
 TACCTL2 |= CCIE;//CCR2

    4) 编写对应的中断服务函数。

#pragma vector = TIMER0_A0_VECTOR
__interrupt void Time0(void)
{
   P1OUT ^= 0x41;
}

   根据上面步骤就可以写一个简单的定时器中断程序了

    实验:LED灯一秒的闪烁变换。

#include "MSP430G2553.h"


int main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  //时钟设置
BCSCTL1=CALBC1_1MHZ;//将DCO设置为1MHZ
DCOCTL=CALDCO_1MHZ;
BCSCTL3 = LFXT1S_2;//ACLK设置为VLO
 // BCSCTL2 |= DIVA_2;//设置为2分频
  //方向寄存器指向
  P1DIR |= 0x41;
  P2DIR |= 0x22;
  P2DIR |= 0x08;
  //TACLK设置
   TACLK |= TASSEL_1;
  TACTL |= TASSEL_1;//定时器时钟源选择-辅助时钟
  TACTL |= ID_0;//定时器A输入分配器 0
  TACTL |= MC_1; //选择模式——向上计数
  TACTL |= TACLR; //计数器清除
  TACTL |= TAIE;//计数器A计数器中断启用
  //
  TACCTL0 |= CCIE;//CCR0中断
  TACCTL1 |= CCIE;//CCR1
  TACCTL2 |= CCIE;//CCR2
  
  TACCR0 = 10000;
  TACCR1 = 10000;
  TACCR2 = 10000;

  _EINT();//使能总中断
  LPM3;//进入低功耗模式3
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Time0(void)
{
   P1OUT ^= 0x41;
}

#pragma vector = TIMER0_A1_VECTOR
__interrupt void Time1(void)
{
   switch(TAIV)
   {
     case 2 : P2OUT ^= 0x02; break;
     case 4 : P2OUT ^= 0x08; break;
     case 10 : P2OUT ^= 0x20; break;
   }
}

    下一个帖子更新Timer_A 定时器的比较/捕获模块的使用和pwm调整灯光亮度。




菜鸟
2019-08-03 00:36:16    评分
2楼

什么时候更新啊,坐等楼主的分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]