这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 高校专区» 坤创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这个型号,内部有2Timer_A定时器,分别叫做Timer0_A3Timer1_A3,或简称TA0TA1。 在MSP430系列定时器的命名规则中,Timer后面的数字表示定时器的编号;而下划线后面的AB表示定时器的类型;A后面的数字3表示定时器中包含3个比较/捕获单元。

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

二,定时器的功能

1.计数功能

(1)计数原理介绍

其实定时就是跟时间有关,时间也是又数字一个一个累积出来的,而Timer_A的核心是一个16位的计数器,其最大计数值是216次方,即从065535之间计数。 在每个定时器的时钟周期, 计数器的值会自动加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寄存器将从065535连续增加,到65535后则清零重新计数。在连续计数模式下,定时器的周期仅由时钟源的频率决定,频率越高,则越快计数到65535,定时器周期越短。

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


1563184910164879.pngimage.png

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

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

1563185770686781.pngimage.png

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

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

1563186633562685.pngimage.png

(2)定时器中断功能

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

1) CCR0中断
当计数器的值达到
CCR0时,定时器会产生CCR0中断。CCR0中断是定时器所有中断中优先级最高的,并且单独拥有一个中断向量。而CCR1CCR2与定时器溢出中断共用一个中断向量。CCR0中断的使能位CCIE和标志位CCIFG都在TACCTL0寄存器中,其中断向量名是TIMER0_A0_VECTOR。要使用CCR0中断,首先要使能CCIE使能位,然后最关键的一步就是设置CCR0寄存器的值。 无论是在向上计数模式还是向上/向下计数模式, 当计数器的值到达CCR0CCIFG都会被置位。 当进入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的读/写操作都会使当前优先级最高的一个中断标志位自动复位。如果此时还有其他中断在等待,那么该中断会在当前中断结束后执行。例如当前TACCR1TACCR2标志位都被
置位,那么读写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),常用的时钟来源有ACLKSMCLK,此外也可以用外部时钟输入到TACLK引脚作为时钟源。

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

1563188409398630.png1563188534157858.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 跳转至

回复

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