目录
MSP430F5529的定时器有定时器A与定时器B,定时器B比定时器A强大一点。这里先只简单介绍定时器A,主要是教你使用库函数,详细资料请看用户手册,其他博客,视频教程。
定时器A可以硬件输出PWM,脉冲捕获,定时中断。本文只讲定时中断部分
定时器A介绍
(1)资源简介
定时器 A 是一个十六位的定时/计数器,MSP430F5529 中包含有 3 个定时器 A 的子模块 和 7 个捕捉/比较模块。定时器 A 支持多重捕获/比较,PWM 输出和内部定时。定时器还有 扩展中断功能,中断可以由定时器溢出产生或由捕获/比较寄存器产生。定时器 A 的特性包括:
四种运行模式的异步 16 位定时/计数器
可选择配置的时钟源
可配置的 PWM 输出
异步输入和输出锁存
对所有 TA 中断快速响应的中断向量寄存器
(2)定时器A时钟选择
MSP430F5529定时器时钟 TACLK 可以选择 ACLK,SMCLK 或者来自外部的 TAxCLK。SMCLK系统默认 1048576Hz,ACLK系统默认为32768Hz。
(3)Timer_A工作模式
看手册,我们知道有四中工作模式,第一个是停止状态,不计数,所以不讲。
【1】增计数模式(01)
此模式下,从0开始计数,可通过TAxCCR0的数值定义定时的周期。TAxCCR0数值小于0FFFFh。
一般用于软件PWM,定时中断。这个用到应该是最多的。
【2】连续计数模式(10)
从0开始计数,直至计数到0FFFFh之后从0开始重新计数。与增计数模式不同的是,不能被提前结束,必须是从0计数到0FFFFh。定时周期只能由时钟源频率决定。
一般用于捕获脉冲。
【3】增减计数模式(11)
从0开始计数,增加到TAxCCR0,再从TAxCCR0减少到0。
(4)Timer_A中断
Timer_A有两个中断向量,CCIFG0中断和TAIV中断。后面会有介绍
TIMERx_A0_VECTOR // CCR0 的中断向量
TIMERx_A1_VECTOR // TAIV 的中断向量
函数介绍
Timer_A_startCounter()
函数声明
void Timer_A_startCounter (uint16_t baseAddress, uint16_t timerMode);
作用
指定定时器A中的3个子定时器,并且以指定方式开始计数。
参数
baseAddress
TIMER_A0_BASE
TIMER_A1_BASE
TIMER_A2_BASE
timerMode
TIMER_A_STOP_MODE
TIMER_A_UP_MODE //增计数模式
TIMER_A_CONTINUOUS_MODE //连续计数模式
TIMER_A_UPDOWN_MODE //增减计数模式
Timer_A_initUpMode()
函数声明
void Timer_A_initContinuousMode (uint16_t baseAddress,Timer_A_initContinuousModeParam ∗param)
作用
配置指定的3个子定时器为增计数模式
参数
baseAddress与上面一样
Param的值为如下
(1)clockSource:选择时钟源
TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK [Default]
TIMER_A_CLOCKSOURCE_ACLK
TIMER_A_CLOCKSOURCE_SMCLK
TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLK
(2)clockSourceDivider:选择时钟分频次数
TIMER_A_CLOCKSOURCE_DIVIDER_1 [Default]
TIMER_A_CLOCKSOURCE_DIVIDER_2
TIMER_A_CLOCKSOURCE_DIVIDER_3
TIMER_A_CLOCKSOURCE_DIVIDER_4
TIMER_A_CLOCKSOURCE_DIVIDER_5
TIMER_A_CLOCKSOURCE_DIVIDER_6
TIMER_A_CLOCKSOURCE_DIVIDER_7
TIMER_A_CLOCKSOURCE_DIVIDER_8
TIMER_A_CLOCKSOURCE_DIVIDER_10
TIMER_A_CLOCKSOURCE_DIVIDER_12
TIMER_A_CLOCKSOURCE_DIVIDER_14
TIMER_A_CLOCKSOURCE_DIVIDER_16
TIMER_A_CLOCKSOURCE_DIVIDER_20
TIMER_A_CLOCKSOURCE_DIVIDER_24
TIMER_A_CLOCKSOURCE_DIVIDER_28
TIMER_A_CLOCKSOURCE_DIVIDER_32
TIMER_A_CLOCKSOURCE_DIVIDER_40
TIMER_A_CLOCKSOURCE_DIVIDER_64
TIMER_A_CLOCKSOURCE_DIVIDER_48
TIMER_A_CLOCKSOURCE_DIVIDER_56
(3)timerPeriod:指定的Timer_A时间段。这是写入的值进入CCR0。限制为16位[uint16_t]
(4)timerInterruptEnable_TAIE:使能还是失能定时器中断
TIMER_A_TAIE_INTERRUPT_ENABLE //使能定时器中断
TIMER_A_TAIE_INTERRUPT_DISABLE //失能定时器中断
(5)captureCompareInterruptEnable_CCR0_CCIE:选择中断响应
TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE //CCR0中断
TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE //TAIE中断
(6)timerClear:选择是否把定时器的定时计数器,分频计数器的计数值清零
TIMER_A_DO_CLEAR //清除
TIMER_A_SKIP_CLEAR //不清除
(7)startTimer:选择初始化之后是否立即启动定时器
true //初始化后立即启动定时器
false //初始化后不启动定时器
中断
当定时器计数到CCR0的值的时候,置为标志位CCIFG。当定时器的值从CCR0计数到0的瞬间,置为TAIFG。
使用
我们定时0.5s
首先我们选择SMCLK作为主时钟,32分频之后就是32750HZ,计数16375次数(写入值要-1)。
然后打开中断,最后两个设置与我一致即可,不用变化。
void Timer_A_Init(void)
{
Timer_A_initUpModeParam htim = {0};
htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; //时钟源选为SMCLK = 1048576 HZ
htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_32; //32分频 32768
htim.timerPeriod = 16384 - 1; //计数值设为16374(32768/2=16374),定时0.5s
htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE; //使能TALE中断
htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;
htim.timerClear = TIMER_A_DO_CLEAR; //把定时器的定时计数器,分频计数器的计数值清零
htim.startTimer = true; //初始化后立即启动定时器
//配置定时器A为增计数模式
Timer_A_initUpMode(TIMER_A0_BASE, &htim);
}
Timer_A_initContinuousMode()
函数声明
void Timer_A_initContinuousMode (uint16_t baseAddress,Timer_A_initContinuousModeParam ∗ param )
作用
配置定时器A为连续计数模式
参数
baseAddress与上面一样
与Timer_A_initUpModeParam相比,Timer_A_initContinuousModeParam 少了(3)timerPeriod,因为连续计数模式是从0到0FFFFh的,所以不需要配置周期。
也少了(5)captureCompareInterruptEnable_CCR0_CCIE,因为当定时值从FFFFh到0的瞬间,回设置TAIFG的标志位。所以他没有CCIFG0中断。
使用
Timer_A_initContinuousModeParam htim = {0};
htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
htim.timerClear = TIMER_A_DO_CLEAR;
htim.startTimer = true;
Timer_A_initContinuousMode(TIMER_A2_BASE, &htim);
Timer_A_initUpDownMode()
函数声明
void Timer_A_initUpDownMode (uint16_t baseAddress,Timer_A_initUpDownModeParam ∗ param )
作用
配置定时器A为增/减计数模式
参数
baseAddress与上面一样
与Timer_A_initUpModeParam相比,Timer_A_initUpDownModeParam 一摸一样。
使用
Timer_A_initUpDownModeParam htim = {0};
htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; //时钟源选为SMCLK = 1.048MHz
htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_32; //64分频 32750
htim.timerPeriod = 16374 - 1; //计数值设为16374 - 1
htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE; //使能TALE中断
htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;
htim.timerClear = TIMER_A_DO_CLEAR; //把定时器的定时计数器,分频计数器的计数值清零
htim.startTimer = true; //初始化后立即启动定时器
//配置定时器A为增计数模式
Timer_A_initUpDownMode(TIMER_A0_BASE, &htim);
实验
因为增计数模式最简单,且使用方便,所以我以下都使用增计数模式。连续计数模式是在后续捕获实验中讲解。增减模式这个我也想不到有啥应用场景,知道的可以在评论区评论。
实验为软件模拟实现PWM。周期为1S,占空比为50%
TALE中断
因为TALE的中断向量被公用,所以需要使用Switch语句,
#include "driverlib.h"
#define MCLK_IN_HZ 25000000
#define delay_us(x) __delay_cycles((MCLK_IN_HZ/1000000*(x)))
#define delay_ms(x) __delay_cycles((MCLK_IN_HZ/1000*(x)))
void Timer_A_Init(void)
{
Timer_A_initUpModeParam htim = {0};
htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; //时钟源选为SMCLK = 1048576 HZ
htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_32; //32分频 32768
htim.timerPeriod = 16384 - 1; //计数值设为16374(32768/2=16374),定时0.5s
htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE; //使能TALE中断
htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;
htim.timerClear = TIMER_A_DO_CLEAR; //把定时器的定时计数器,分频计数器的计数值清零
htim.startTimer = true; //初始化后立即启动定时器
//配置定时器A为增计数模式
Timer_A_initUpMode(TIMER_A0_BASE, &htim);
}
void main (void)
{
//Stop WDT
WDT_A_hold(WDT_A_BASE);
//P4.1为输出
GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN1);
Timer_A_Init();
//interrupts enabled
__bis_SR_register(GIE);
while(1)
{
}
}
#pragma vector=TIMER0_A1_VECTOR
__interrupt
void TIMER0_A1_ISR (void)
{
switch(TA0IV)
{
case TA0IV_NONE:
break;
case TA0IV_TACCR1:
break;
case TA0IV_TACCR2:
break;
case TA0IV_TACCR3:
break;
case TA0IV_TACCR4:
break;
case TA0IV_5:
break;
case TA0IV_6:
break;
case TA0IV_TAIFG:
GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN1);
break;
default:
break;
}
}
CCIFG0中断
看注释掉的部分,就是要改的地方。
#include "driverlib.h"
#define MCLK_IN_HZ 25000000
#define delay_us(x) __delay_cycles((MCLK_IN_HZ/1000000*(x)))
#define delay_ms(x) __delay_cycles((MCLK_IN_HZ/1000*(x)))
void Timer_A_Init(void)
{
Timer_A_initUpModeParam htim = {0};
htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; //时钟源选为SMCLK = 1048576 HZ
htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_32; //32分频 32768
htim.timerPeriod = 16384 - 1; //计数值设为16375(32768/2=16375),定时0.5s
// htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE; //使能TALE中断
// htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;
htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE; //失能TALE中断
htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;
htim.timerClear = TIMER_A_DO_CLEAR; //把定时器的定时计数器,分频计数器的计数值清零
htim.startTimer = true; //初始化后立即启动定时器
//配置定时器A为增计数模式
Timer_A_initUpMode(TIMER_A0_BASE, &htim);
}
void main (void)
{
//Stop WDT
WDT_A_hold(WDT_A_BASE);
//P4.1为输出
GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN1);
Timer_A_Init();
//interrupts enabled
__bis_SR_register(GIE);
while(1)
{
}
}
//#pragma vector=TIMER0_A1_VECTOR
//__interrupt
//void TIMER0_A1_ISR (void)
//{
// switch(TA0IV)
// {
// case TA0IV_NONE:
// break;
// case TA0IV_TACCR1:
// break;
// case TA0IV_TACCR2:
// break;
// case TA0IV_TACCR3:
// break;
// case TA0IV_TACCR4:
// break;
// case TA0IV_5:
// break;
// case TA0IV_6:
// break;
// case TA0IV_TAIFG:
// GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN1);
// break;
// default:
// break;
// }
//}
#pragma vector=TIMER0_A0_VECTOR
__interrupt
void TIMER0_A0_ISR (void)
{
GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN1);
}