本帖最后由 Shuyang 于 2019-2-28 13:43 编辑
5.3 Timer_A定时器的比较/捕获模块
Timer_A的比较/捕获模块CCRx并不是独立的功能模块,它们都必须配合计数器才能工作。
捕获模块(capture)可以判断输入信号的边沿,并瞬间用TACCRx寄存器记录下边沿时刻(TAR值),用于精确测定脉宽或频率。
比较模块(comparator)可以将TAR寄存器值与TACCRx中的预设值比较,并自动按照“预设方案”翻转I/O电平,可以自动生成各种波形。
比较/捕获模块共用了TACCRx寄存器,所以不能同时使用,TACCTLx寄存器中的CAP位负责选择比较/捕获模式,CAP=0为比较,CAP=1为捕获。
5.3.1 捕获模块
将CAP设为1时,CCRx工作于捕获模式。计数器一般设置为连续计数模式,当CCRx检测到CCIx(带有捕获功能的I/O口)的电平边沿时,瞬间读取TAR寄存器的值并写入TACCRx中。
CCRx可以选择检测上升沿或下降沿,或者都检测。CCRx用于测定信号脉宽时,只需要分别记录信号上升沿时刻和下降沿时刻,二者相减就是脉宽;而测量频率时,连续记录两次上升沿时刻,相减就是周期。
使用捕获模式的一般步骤如下:
1) 把计数器设为连续计数模式,这样就有最长的“刻度尺”可用。如果“尺子”长度还不够用,可以设定尺子每溢出一次,中断服 务函数中给全局变量count+1,这样就能测量任意时间长度了。
2) 把TACCTLx寄存器中的CAP位设为1,捕获模式。
3) 选择CCRx模块的捕获源寄存器CCISx,也就是具体哪个引脚作为捕获输入口CCIx。
4) 设定CMx寄存器,决定是上升沿捕获、下降沿捕获,还是两者都捕获。
5) 设定SCS寄存器,决定是同步捕获还是异步捕获,一般都是设为同步捕获。
6) 等待捕获信号到来并读取CCRx的捕获值。
5.3.2 比较模块
当CAP=0时,CCRx工作于比较模式。CCR0在比较模式中用于设定计数器的周期,CCR1和CCR2负责设定比较值。
这8种规则和计时器的3种工作模式(连续计数、向上计数、向上/向下计数)组合起来,共有24种排列组合,看起来十分复杂。但其实最常用的功能就是用来生成PWM波。所谓PWM波是指“脉冲宽度调制”波形(PulseWidth Modulation),就是一定周期的方波,其高电平时间和低电平时间的比例(称为“占空比”)可以控制。PWM的应用十分广泛,例如要控制一个电机的转速,一般都是通过给出一定占空比的PWM波来实现的。
下面我们来分析一下模式2:Toggle/Reset,即OUTMODx=010。在此模式下,TAx引脚电平会按照下面规律变化:
- Toggle:当TAR=CCRx时,TAx引脚电平自动翻转;
- Reset:当TAR=CCR0时,TAx引脚电平自动变为0。
我们一般将计数器设为向上计数模式(up mode)来生成PWM波。根据上面的变化规律,可以推导出TAx引脚电平变化如下图所示。
可以看到引脚电平分别在TAR等于CCR0和CCR1两个时刻发生了变化。因此,只要改写CCR0和CCR1的值就可以设定PWM的周期和占空比。其中CCR0负责控制周期,CCR1负责控制占空比。
其他几种输出模式的作用请见下图。我们看到模式2/3/6/7其实都可以生成PWM波。为了在设置占空比时更直观,我们一般用模式7。此时可以看到CCRx与占空比成正比,CCRx的值越大,占空比越大。
比较模块产生的PWM波只能在特定引脚输出,且CCRx寄存器与TAx引脚一一对应。例如Timer_A0CCR1产生的PWM只能在TA0.1,Timer_A0 CCR2产生的PWM只能在TA0.2,以此类推。需要注意的是在比较模块中,CCR0是用来设定周期的,因此一个定时器最多可以产生2路不同的PWM波形。
5.3.3 用比较模块产生PWM波
本节中我们来详细介绍利用比较模块产生PWM波的步骤。
1) 设定PWM波的输出端口。
只有具备定时器输出功能的引脚才能输出PWM波。在MSP430中这些引脚用TA0.x或TA1.x来标明。TA0.0-TA0.2是Timer0的输出端口,TA1.0-TA1.2是Timer1的输出端口。
从MSP430G2553 datasheet中可以看到,20pin的G2553没有留出TA0.2输出端口,之前也介绍过CCR0在比较模式下不能输出PWM,因此真正能够输出PWM的端口就是TA0.1、TA1.1、TA1.2这3组。20pin的MSP430G2553共有3个TA0.1端口,以及2个TA1.0/TA1.1/TA1.2端口,所以极限情况下一共可以输出3组7路PWM波。
要将I/O口设为PWM输出口,需要按照第二章介绍的引脚复用方法设定相应的寄存器。除了P2.6(TA0.1)这个端口外,其他几组端口的寄存器设置基本类似,即DIR寄存器为1,PxSEL寄存器为1,PxSEL2寄存器为0。
例如下面我们来将P2.1/TA1.1引脚配置位PWM输出引脚。 - P2DIR |= BIT1; // Set P2.1 as TA1.1
- P2SEL |= BIT1;
复制代码
2) 设定CCR0和CCRx的值。
设定好PWM输出引脚之后,我们就要来确定PWM的周期和占空比了。周期由CCR0寄存器决定,CCR0的值乘以定时器时钟周期就是PWM的周期。占空比等于CCRx/CCR0,在输出模式7下,CCRx的值与占空比成正比。 - TA1CCR0 = 512; // PWM Period
- TA1CCR1 = 256; // PWM duty cycle
复制代码
3) 选择比较/捕获模块的输出模式。
根据上一节的介绍,我们一般选择输出模式7来生成PWM波。输出模式通过TACCTLx寄存器来设置。注意每个比较/捕获模块有自己的TACCTLx寄存器,例如要选择TA1.1引脚的输出模式,就需要配置TA1CCTL1寄存器。 - TA1CCTL1 = OUTMOD_7; // Set output mode to 7
复制代码
4) 选择定时器的时钟源和计数模式。
定时器的时钟源也决定了PWM的周期。Timer_A定时器可以使用SMCLK或者ACLK,并且可以分频。时钟和分频都由TACTL寄存器设定。另外这个寄存器也负责选择计数器的计数模式,我们一般选择向上计数模式(Up mode)。
设定好TACTL寄存器之后,定时器就开始工作了,将会产生PWM输出。因此我们一般将设置TACTL的指令放在最后。 - TA1CTL = TASSEL_2 + MC_1; // SMCLK, up mode
复制代码
5) MSP430开始自动生成PWM波,CPU可进入低功耗模式。
设置好上述步骤以后,比较模块就将开始生成PWM波。由于这样产生的PWM波完全是由定时器生成的,与CPU无关,因此现在CPU可以去处理更重要的任务,或是进入低功耗模式休息。 - _BIS_SR(CPUOFF); // Enter LMP0
复制代码
5.3.4 使用比较/捕获模块的捕获功能
本节中我们来介绍比较/捕获模块的捕获功能的使用。捕获功能的典型应用是用来测量外部输入信号的上升/下降沿之间的时间间隔。
1) 捕获输入端口
使用捕获功能时外部信号是通过MSP430的捕获引脚输入进来的。之前介绍过每个Timer_A定时器有3个比较/捕获模块,捕获和比较可以看作是对偶的功能。上一节中我们也列出了MSP430G2553中带有比较输出功能的引脚。但需要注意并非所有带比较输出功能的引脚都有捕获输入功能,下面我们来详细分析。
从比较/捕获模块(CCRx)的框图中可以看到,每一个CCRx模块其实有2个捕获输入,分别命名为CCIxA和CCIxB。比如CCR2模块的捕获输入叫做CCI2A和CCI2B。因此每个Timer_A定时器有6个捕获输入,对于20pin的MSP430G2553来说,有Timer0_A3和Timer1_A3两个定时器,因此理论上最多可以有12个捕获输入。
但需要注意的是,受引脚数量限制,并非所有的捕获输入都会在20pin的MSP430G2553上出现。具体需要查看MSP430G2553的datasheet,在datasheet第16页Timer_A3部分的表格里给出了具有捕获功能的引脚。
从表格中可以看出,在Timer0中只有2个捕获输入引脚,分别是P1.1(3号脚)和P1.2(4号脚),它们分别对应Timer0中的CCI0A和CCI1A。而Timer1中的捕获引脚比较齐全,6个捕获引脚无一缺席。Timer1中每一个CCRx会有2个比较输入,例如CCR0有P2.0和P2.3,分别为CCI0A和CCI0B。
具体每一个捕获引脚的位置请对照datasheet中的引脚描述。
我们可以根据datasheet中的介绍总结出以下的捕获功能引脚分布图(针对20pin的MSP430G2553)。
使用捕获功能的第一步就是选择捕获输入引脚,通过TACCTLx寄存器中的CCISx可以选择输入。共有CCIxA、CCIxB、GND、Vcc四种选择。
例如我们想用P1.1作为捕获输入,它对应的是Timer0的CCI0A。代码如下: - TA0CCTL0 |= CCIS_0; // CCI0A of Timer0 for capture input
复制代码
2) 上升沿/下降沿选择
可以选择捕获输入信号的上升沿、下降沿、或是二者都捕获。通过TACCTLx寄存器的CMx位可以选择。
继续接上面的例子,如果选择上升沿捕获,代码如下: - TA0CCTL0 |= CM_1; // Capture on rising edge
复制代码
3) 捕获中断
当比较/捕获模块处在捕获模式下,且输入信号的变化满足了捕获条件时(上升沿或者下降沿,由CMx决定),会产生一个中断信号CCIFG。如果需要使用这个中断,则需要在初始化时使能CCIE中断使能位。代码如下: - TA0CCTL0 |= CCIE; // Enable capture interrupt
复制代码
中断被使能后,单片机会在捕获条件达到时进入中断服 务函数。捕获中断和比较中断一样,都是使用CCRx的中断向量。请回忆5.2.2节在介绍定时器中断时讲到的CCR0中断与CCR1/CCR2中断的区别,CCR0使用单独的中断向量,CCR1、CCR2和TAIFG共用一个中断向量。二者的主要区别在于如果使用CCR1/CCR2中断,则需要在中断服 务函数函数中加入判断语句,确定是那一个中断信号触发了中断。
在中断服 务函数中,可以对捕获的结果进行用户所需要的计算。例如计算周期、频率或是时间间隔等。例如上面例子中,如果输入信号触发了CCR0中断,则中断服 务函数格式如下: - // Timer A0 CCR0 interrupt ser-vice routine
- #pragma vector=TIMER0_A0_VECTOR
- __interrupt void Timer_A(void)
- {
- ...
- }
复制代码
4) 开启捕获功能
上述初始化全部完成后,可以将寄存器TACCTLx中的CAP置为1,开启捕获功能。另外捕获模块中提供了一个输入信号同步功能,这是为了避免由于捕获信号和定时器时钟不同步而造成紊乱现象,一般建议将SCS置为1开启同步功能。 - TA0CCTL0 |= CAP + SCS; // TA0CCR1 Capture mode
复制代码
5) 开启定时器
上面1-4步只是初始化了捕获模块,最后不要忘记根据5.2.3节中介绍的步骤对定时器进行初始化,并打开定时器。定时器一旦打开,捕获模块就开始工作了。
上面1-4步的代码可以合并为一个语句,再加上一个定时器初始化语句,就成为下面一个完整的捕获模块初始化代码: - TA0CCTL0 = CAP + CM_1 + CCIE + SCS + CCIS_0; // TA0CCR0 Capture mode, CCI0A, Rising edge, interrupt enable
- TA0CTL |= TASSEL_2 + MC_2 + TACLR; // SMCLK, Cont Mode, start timer
复制代码
|