What
顾名思义,定时器的基本工作就是根据一定的时钟间隔来计数,当计数值到达一定数值时就开始进行相应的操作。
在MSP430系列单片机中,都带有2个16位定时器Timer_A,用于精确定时、计时或计数。在普通的定时/计数器的基础上,还添加了3路(某些型号5路)捕获/比较模块,G2553具有两个定时器A,能够在无需CPU干预的情况下自动根据触发条件捕获定时器计数值,或自动产生各种输出波形(如PWM调制、单稳态脉冲等)。输出的PWM波1可用于步进电机的调速、控制灯的亮度和开关电源等。
定时器Timer_A分为两个部分:主计数器和比较/捕获模块。主计数器负责定时、计时或计数。计数值(TAR寄存器的值)被送到各个比较/捕获模块中,它们可以在无需CPU干预的情况下根据触发条件与计数器值自动完成某些测量和输出功能。只需要定时、计数功能时,可以只使用主计数器部分,在PWM调制等应用中还需要比较/捕获模块的配合。
定时器的本质位计数器,所以其共有以下四种计数模式
而定时器A又有两种工作模式,捕捉工作模式和比较工作模式。
当 CAP=1 时,捕捉模式被选用。捕捉模式被用于记录时间事件。它可被用于速度估计或时间测量。 捕捉输入 CCIxA 和 CCIxB 被连接到外部引脚或内部信号并且由CCISx 位选择。 CMx 位选择输入信号的捕捉沿作为上升沿,下降沿或两者都是。 捕捉发生在选择的输入信号沿上。 如果发生捕捉:
- 定时器的值被复制仅 TACCRx 寄存器
- 中断标志 CCIFG 被置位
当 CAP=0 时,选用比较模式。比较模式被用于产生 PWM输出信号或在特定的时间间隔上产生中断。 当
TAR计数到 TACCRx 中的值时:
- 中断标志 CCIFG 被置位
- 内部信号 EQUx=1
- EQUx 根据输出模式来影响输出信号
- 输入信号 CCI 锁存到 SCCI
How
- 配置时钟源
- 选择时钟信号
- 配置相应管脚
- 选择定时器工作模式和计数模式
- 设置定时器计数值
定时器默认使用比较工作模式
举例
编写LED闪灯程序,编写延迟函数,延时时间1s,实现循环间隔1s的亮灭。
方案一:定时器查询
#include <msp430.h>
#include "stdint.h"
/*
* main.c
*/
int main(void)
{
uint8_t cnt = 0;
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
/*配置DCO频率为1MHz*/
DCOCTL = CALDCO_1MHZ;
BCSCTL1 = CALBC1_1MHZ;
/*设置P1.0为输出*/
P1DIR |= BIT0;
/*设置时钟源为SMCLK*/
TA1CTL |= TASSEL_2;//如果是TACTL默认为Timer_A0,等价于TA0CTL
/*设置工作模式为Up Mode*/
TA1CTL |= MC_1;//Up Mode模式下,16bit Timer计数器 TAR会从0递增到TACCR0,然后回到0,重复这个过程
/*设置定时间隔*/
TA1CCR0 = 49999;//1MHz 计 50000个数,1/1MHz * 50000 20Hz 0.05s
while(1)
{
if(TA1CTL & TAIFG)
{
cnt ++;
TA1CTL &= ~TAIFG;
if(cnt == 20)//0.05s * 20 = 1s
{
P1OUT ^= BIT0;
cnt = 0;
}
}
}
}
方案二:定时器中断
#include <msp430.h>
#include "stdint.h"
/*
* @fn: void InitSystemClock(void)
* @brief: 初始化系统时钟
* @para: none
* @return: none
* @comment:初始化系统时钟
*/
void InitSystemClock(void)
{
/*配置DCO为1MHz*/
DCOCTL = CALDCO_1MHZ;
BCSCTL1 = CALBC1_1MHZ;
/*配置SMCLK的时钟源为DCO*/
BCSCTL2 &= ~SELS;
/*SMCLK的分频系数置为1*/
BCSCTL2 &= ~(DIVS0 | DIVS1);
}
/*
* main.c
*/
uint8_t flag = 0;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
InitSystemClock();
/*设置P1.0为输出*/
P1DIR |= BIT0;
/*设置时钟源为SMCLK*/
TA1CTL |= TASSEL_2;
/*设置工作模式为Up Mode*/
TA1CTL |= MC_1;
/*设置定时间隔*/
TA1CCR0 = 49999;// 50ms 1MHz 1/1MHz 1ns 50ms / 1ns = 50000 50000 - 1 = 49999,若用CCIFG作为中断标志,侧不应减1
/*开启TAIFG中断*/
TA1CTL |= TAIE;
/*打开全局中断*/
__bis_SR_register(GIE);
while(1)
{
if(flag == 1)
{
flag = 0;
P1OUT ^= BIT0;
}
}
}
#pragma vector = TIMER1_A1_VECTOR
__interrupt void Time_Tick(void)
{
static uint8_t cnt = 0;
switch(TA1IV)//该处中断标志位不用软件清零
{
case 0x02:
break;
case 0x04:
break;
case 0x0A:
cnt ++;
if(cnt == 20)
{
cnt = 0;//清零计数器
flag = 1;//1s 到了
}
break;
default:
break;
}
}
Task
利用pwm输出控制LED,实现LED的亮度由低至高的循环变化
定时器在工作时如果触发中断会在一定的管教上输出电信号,其输出模式可以选择
通过选择合适的输出模式和适当的计数模式可以实现pwm波的产生,举一个小例子,代码如下:
#include <msp430.h>
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗
P1DIR |= 0x0C; // P1.2 and P1.3 设置为输出
P1SEL |= 0x0C; // P1.2 and P1.3 为TA1/2模式
CCR0 = 512-1; // CCR0为PWM周期
CCTL1 = OUTMOD_7; // CCR1为reset/set模式,CCR1时变为低电平,CCR0变为高电平
CCR1 = 85; // CCR1为PWM占空时间
TACTL = TASSEL_2 + MC_1; // 定时器时钟为SMCLK, 向上计数模式
_BIS_SR(CPUOFF); // 进入LPM0模式
}
通过改变CCR1的大小可以控制LED的亮度
因此:
#include <msp430.h>
/*
* main.c
*/
int main(void)
{
unsigned int cnt = 0;
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
/*配置DCO频率为1MHz*/
DCOCTL = CALDCO_1MHZ;
BCSCTL1 = CALBC1_1MHZ;
/*初始化P1.0为输入*/
P1DIR &= ~BIT0;//因为TA1.2在P2.5上,需要将P2.5与P1.0或P1.6相连,为防止短路,需要设置其为输入口
/*设置时钟源为SMCLK*/
TA1CTL |= TASSEL1;
/*设置工作模式为Up&Down*/
TA1CTL |= MC0|MC1;
/*设置TA1CCR0为0x00FF*/
TA1CCR0 = 0x00FF;
/*设置TA1CCR2为0x00FF*/
TA1CCR2 = 0x00FF;//占空比(TACCR0 - TACCR2) / TACCR0,频率=SMCLK/(TACCR0+1)/2
/*设置为比较模式*/
TA1CCTL0 &= ~CAP;
TA1CCTL2 &= ~CAP;
/*设置比较输出模式*/
TA1CCTL2 |= OUTMOD_6;
/*设置IO复用*/
P2SEL |= BIT5;
P2DIR |= BIT5;
while(1)
{
for(cnt = 0;cnt < 0x00FF;cnt ++)
{
TA1CCR2 = cnt;
__delay_cycles(5000);
}
for(cnt = 0x00FF;cnt > 0;cnt --)
{
TA1CCR2 = cnt;
__delay_cycles(5000);
}
}
}
pwm LED
sao话一下
人这一辈子,就怕有遗憾,而我最大的遗憾就怕你的遗憾与我有关…林深时见鹿,海蓝时见鲸,梦醒时见你。 可实际, 林深时雾起,海蓝时浪涌,梦醒时夜续。 未见鹿,未见鲸,亦未见你。 但, 鹿踏雾而来,鲸随浪而起,你没回头 又怎知我没来。然……林深时雾起,不知归处; 海蓝时浪涌,望而却步; 梦醒时夜续,惊慌失措。 鹿不在侧,鲸不予游,亦不见你。 等…风吹深林雾,海映晴空蓝,你唤我梦醒,便可见鹿见鲸,亦见你。喜欢 合适 在一起 走下去 是四件事.我对你仍向往,但不抱任何期待
PWM波可以比较通俗地解释为周期性的高低电平输出,而高低电平在一个周期中所占的时间为定值。 ↩︎