目录
- 硬知识
- 定时器A 16位定时器原理
- (1)时钟源选择和分频器
- (2)Timer_A工作模式
- (3)捕获/比较模块
- (4)Timer_A中断(重要)
- 定时器A API (机翻)
- 定时器A配置和控制的函数
- 参数
- 定时器A 输出相关函数
- 参数
- 管理定时器A中断的程序
- 参数
- 中断向量
- 上机实战
- 定时器A 增计数模式CCR0中断
- 初始化函数
- 中断服务函数
- 实验结果
- 定时器A 增计数模式TAIE中断
- 初始化函数
- 中断服务函数
- 实验结果
- 输入捕获模式测量脉宽长度
- 初始化函数
- 中断服务函数
- 被测信号产生
- 实验结果
平台:Code Composer Studio 10.3.1
MSP430F5529 LaunchPad™ Development Kit
(MSP‑EXP430F5529LP)
硬知识
定时器A具有如下特点:
4种运行模式的异步16位定时/计数器;
参考时钟源可选择配置;
高达7个可配置的捕获/比较寄存器;
可配置的PWM输出;
异步输入和输出锁存;
具有可对Timer_A中断快速响应的中断向量寄存器。
定时器A的结构框图如图所示。
定时器A 16位定时器原理
16位定时器的计数值寄存器TAR在每个时钟信号的上升沿进行增加/减少,可利用软件读取TAR寄存器的计数值。此外,当定时时间到,产生溢出时,定时器可产生中断。置位定时器控制寄存器中的TACLR控制位,可自动清除TAR寄存器的计数值,同时,在增/减计数模式下,清除了时钟分频器和计数方向。
(1)时钟源选择和分频器
定时器的参考时钟源可以来自内部时钟ACLK、SMCLK或者来自TACLK引脚输入,可通过TASSEL控制位进行选择。选择的时钟源首先通过ID控制位进行1、2、4、8分频,对于分频后的时钟,可通过TAIDEX控制位进行1、2、3、4、5、6、7、8分频。
(2)Timer_A工作模式
Timer_A共有4种工作模式:停止模式、增计数模式、连续计数模式和增/减计数模式,具体工作模式可以通过MC控制位进行选择,具体配置如表所示。
① 停止模式。停止模式用于定时器暂停,并不发生复位,所有寄存器现行的内容在停止模式结束后都可用。当定时器暂停后重新计数时,计数器将从暂停时的值开始以暂停前的计数方向计数。例如,停止模式前,Timer_A定时器工作于增/减计数模式并且处于下降计数方向,停止模式后,Timer_A仍然工作于增/减计数模式下,从暂停前的状态开始继续沿着下降方向开始计数。若不想这样,则可通过TAxCTL中的TACLR控制位来清除定时器的计数及方向记忆特性。
② 增计数模式。比较寄存器TAxCCR0用作Timer_A增计数模式的周期寄存器。由于TAxCCR0为16位寄存器,所以在该模式下,定时器A连续计数值应小于0FFFFh。TAxCCR0的数值定义了定时的周期,计数器TAR可以增计数到TAxCCR0的值,当计数值与TAxCCR0的值相等(或定时器值大于TAxCCR0的值)时,定时器复位并从0开始重新计数。增计数模式下的计数过程如左图所示。
当定时器计数值计数到TAxCCR0时,置位CCR0中断标志位CCIFG。当定时器从TAxCCR0计数到0时,置位Timer_A中断标志位TAIFG。增计数模式下中断标志位设置过程如右图所示。
③ 连续计数模式。在连续计数模式下,Timer_A定时器增计数到0FFFFh之后从0开始重新计数,如此往复。连续计数模式下的计数过程如左图所示。
当定时器计数值从0FFFFh计数到0时,置位Timer_A中断标志位,连续计数模式下的中断标志位设置过程如右图所示。
连续计数模式的典型应用如下:
产生多个独立的时序信号:利用捕获比较寄存器捕获各种其他外部事件发生的定时器数据。
产生多个定时信号:在连续计数模式下,每完成一个TAxCCRn(其中n取值为0~6)计数间隔,将产生一个中断,在中断服务程序中,将下一个时间间隔计数值赋给TAxCCRn,如 图6.4.7表示了利用两个捕获比较寄存器TAxCCR0和TAxCCR1产生两个定时信号t0和t1。在这种情况下,定时完全通过硬件实现,不存在软件中断响应延迟的影响,具体实现示意图如图所示。
④ 增/减计数模式,需要对称波形的情况往往可以使用增/减计数模式。在该模式下,定时器先增计数到TAxCCR0的值,然后反方向减计数到0。计数周期仍由TAxCCR0定义,它是TAxCCR0值的2倍。增/减计数模式下的计数过程如左图所示。
在增/减计数模式下,TAxCCR0中断标志位CCIFG和Timer_A中断标志位TAIFG在一个周期内仅置位一次。当定时计数器增计数从TAxCCR0-1计数到TAxCCR0时,置位TAxCCR0中断标志位CCIFG,当定时计数器减计数从0001h到0000h时,置位Timer_A中断标志位TAIFG。增/减计数模式下中断标志位的设置过程如右图所示。
(3)捕获/比较模块
捕获/比较模块的逻辑结构如图所示,在此以捕获/比较模块TAxCCR6为例进行介绍。
① 捕获模式。当CAP控制位置为1时,捕获/比较模块配置为捕获模式。捕获模式被用于捕获事件发生的时间。捕获输入CCIxA和CCIxB可连接外部引脚或内部信号,这需通过CCIS控制位进行配置。可通过CM控制位将捕获输入信号触发沿配置为上升沿触发、下降沿触发或两者都触发。捕获事件在所选输入信号触发沿产生,如果产生捕获事件,定时器将完成以下工作:
主计数器计数值复制到TAxCCRn寄存器中;
置位中断标志位CCIFG。
输入信号的电平可在任意时刻通过CCI控制位进行读取。捕获信号可能会和定时器时钟不同步,并导致竞争条件的产生,将SCS控制位置位可在下一个定时器时钟使捕获同步。捕获信号示意图如左图所示。
如果第二次捕获在第一次捕获的值被读取之前发生,捕获/比较寄存器就会产生一个溢出逻辑,在此情况下,将置位COV标志位,如右图所示。注意COV标志位必须通过软件消除。
② 比较模式。当CAP控制位设为0时,捕获/比较模块工作在比较模式。比较模式用来产生PWM输出信号或者在特定的时间间隔产生中断。此时TAxCCRn的值可由软件写入,并通过比较器与主计数器的计数值TAR进行比较,当TAR计数到TAxCCRn时,将依次产生以下事件:
置位中断标志位CCIFG;
产生内部信号EQUn=1;
EQUn信号根据不同的输出模式触发输出逻辑;
输入信号CCI被锁存到SCCI。
每个捕获/比较模块都包含一个输出单元,用于产生输出信号,例如PWM信号等。每个输出单元都有8种工作模式,可产生EQUx的多种信号。输出模式可通过OUTMOD控制位进行定义,具体定义如表所示。
增计数模式下,定时器比较输出
在增计数模式下,当TAR增加到TAxCCRn或从TAxCCR0计数到0时,定时器输出信号按选择的输出模式发生变化。示例如图所示,该示例利用了TAxCCR0和TAxCCR1。
连续计数模式下,定时器比较输出
在连续计数模式下,定时器输出波形与增计数模式一样,只是计数器在增计数到TAxCCR0后还要继续增计数到0FFFFh,这样就延长了计数器计数到TAxCCR1数值的时间。在连续计数模式下的输出波形如图所示。在该示例中同样用到了TAxCCR0和TAxCCR1。
增/减计数模式下,定时器比较输出
在增/减计数模式下,各种输出模式与定时器工作在增计数模式或连续计数模式不同。当定时器计数值TAR在任意计数方向上等于TAxCCRn时或等于TAxCCR0时,定时器输出信号都按选定的输出模式发生改变。在增/减计数模式下的输出波形如图所示。该示例利用了TAxCCR0和TAxCCR2。
(4)Timer_A中断(重要)
16位定时器Timer_A具有两个中断向量,分别如下:
TAxCCR0的中断向量CCIFG0;
具有其余TAxCCRn的中断标志CCIFGn及TAIFG的中断向量TAIV。
在捕获模式下,当定时计数器TAR的值被捕获到TAxCCRn寄存器内时,置位相关的CCIFGn中断标志位。在比较模式下,当定时计数器TAR的值计数到TAxCCRn的值时,置位相关的CCIFGn中断标志位。也可利用软件置位或清除任意一个CCIFG中断标志位,当相关的CCIE中断允许位和GIE总中断允许位置位,CCIFGn中断标志位将请求产生中断。
① TAxCCR0中断
TAxCCR0中断标志位CCIFG0在Timer_A中断中具有最高的中断优先级,TAxCCR0中断产生逻辑如图所示。当相应的TAxCCR0中断请求被响应后,TAxCCR0中断标志位CCIFG0自动复位。
② TAIV中断
TAxIV中断主要包括TAxCCRn的中断标志CCIFGn和TAIFG中断标志。中断向量寄存器可被用来判断当前被挂起的Timer_A中断,之后通过查中断向量表得到中断服务程序的入口地址,并将其添加到程序计数器中,程序将自动转入中断服务程序。禁用Timer_A中断功能并不影响TAxIV中断向量寄存器的值。
对TAxIV中断向量寄存器的读或写,都将自动清除挂起的最高优先级中断标志位。如果同时也置位了其他中断标志位,在当前中断服务程序执行完毕后,将自动立即响应新的中断请求。
例如,当中断服务程序访问TAxIV中断向量寄存器时,同时TAxCCRI和TAxCCR2的CCIFG中断标志位置位。首先响应TAxCCRI的CCIFG中断请求,并且自动复位TAxCCR1的CCIFG中断标志位。当在中断服务程序中执行RETI断回执后,CPU响应TAXCCR2的CCIFG中断请求。
Timer_A具有丰富的寄存器资源供用户使用,详细列表如表所示
定时器A API (机翻)
定时器A APl被分成三组函数:
处理定时器配置和控制的函数,
处理定时器内容的函数,
以及处理中断的函数。
定时器A配置和控制的函数
Timer_A_startCounter(uint16_t baseAddress, uint16_t timerMode)
//定时器A开始计数
Timer_A_initUpMode(uint16_t baseAddress, Timer_A_initUpModeParam ∗param)
//配置定时器A为增计数模式
Timer_A_initUpDownMode(uint16_t baseAddress, Timer_A_initUpDownModeParam
∗param)
//配置定时器A为增/减计数模式
Timer_A_initContinuousMode(uint16_t baseAddress, Timer_A_initContinuousModeParam ∗param)
//配置定时器A为连续计数模式
Timer_A_initCaptureMode(uint16_t baseAddress, Timer_A_initCaptureModeParam ∗param)
//初始化为捕获模式。
Timer_A_initCompareMode(uint16_t baseAddress, Timer_A_initCompareModeParam ∗param)
//初始化为比较模式
Timer_A_clear(uint16_t baseAddress)
//复位/清除计时器时钟分频器,计数方向,计数值
Timer_A_stop(uint16_t baseAddress)
//停止计时器计时
参数
baseAddress
是TIMER_A模块的基地址
TIMER_A0_BASE
TIMER_A1_BASE
TIMER_A2_BASE
timerMode
TIMER_A_STOP_MODE
TIMER_A_UP_MODE
TIMER_A_CONTINUOUS_MODE // [Default]
TIMER_A_UPDOWN_MODE
Timer_A_initUpModeParam
//*****************************************************************************
//
//! \brief Used in the Timer_A_initUpMode() function as the param parameter.
//
//*****************************************************************************
typedef struct Timer_A_initUpModeParam {//! Selects Clock source.//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK [Default]//! - \b TIMER_A_CLOCKSOURCE_ACLK//! - \b TIMER_A_CLOCKSOURCE_SMCLK//! - \b TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLKuint16_t clockSource;//! Is the desired divider for the clock source//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_DIVIDER_1 [Default]//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_2//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_3//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_4//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_5//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_6//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_7//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_8//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_10//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_12//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_14//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_16//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_20//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_24//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_28//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_32//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_40//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_48//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_56//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_64uint16_t clockSourceDivider;//! Is the specified Timer_A period. This is the value that gets written//! into the CCR0. Limited to 16 bits[uint16_t]uint16_t timerPeriod;//! Is to enable or disable Timer_A interrupt//! \n Valid values are://! - \b TIMER_A_TAIE_INTERRUPT_ENABLE//! - \b TIMER_A_TAIE_INTERRUPT_DISABLE [Default]uint16_t timerInterruptEnable_TAIE;//! Is to enable or disable Timer_A CCR0 captureComapre interrupt.//! \n Valid values are://! - \b TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE//! - \b TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE [Default]uint16_t captureCompareInterruptEnable_CCR0_CCIE;//! Decides if Timer_A clock divider, count direction, count need to be//! reset.//! \n Valid values are://! - \b TIMER_A_DO_CLEAR//! - \b TIMER_A_SKIP_CLEAR [Default]uint16_t timerClear;//! Whether to start the timer immediatelybool startTimer;
} Timer_A_initUpModeParam;
Timer_A_initUpDownModeParam
//*****************************************************************************
//
//! \brief Used in the Timer_A_initUpDownMode() function as the param
//! parameter.
//
//*****************************************************************************
typedef struct Timer_A_initUpDownModeParam {//! Selects Clock source.//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK [Default]//! - \b TIMER_A_CLOCKSOURCE_ACLK//! - \b TIMER_A_CLOCKSOURCE_SMCLK//! - \b TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLKuint16_t clockSource;//! Is the desired divider for the clock source//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_DIVIDER_1 [Default]//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_2//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_3//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_4//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_5//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_6//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_7//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_8//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_10//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_12//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_14//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_16//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_20//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_24//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_28//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_32//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_40//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_48//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_56//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_64uint16_t clockSourceDivider;//! Is the specified Timer_A perioduint16_t timerPeriod;//! Is to enable or disable Timer_A interrupt//! \n Valid values are://! - \b TIMER_A_TAIE_INTERRUPT_ENABLE//! - \b TIMER_A_TAIE_INTERRUPT_DISABLE [Default]uint16_t timerInterruptEnable_TAIE;//! Is to enable or disable Timer_A CCR0 captureComapre interrupt.//! \n Valid values are://! - \b TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE//! - \b TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE [Default]uint16_t captureCompareInterruptEnable_CCR0_CCIE;//! Decides if Timer_A clock divider, count direction, count need to be//! reset.//! \n Valid values are://! - \b TIMER_A_DO_CLEAR//! - \b TIMER_A_SKIP_CLEAR [Default]uint16_t timerClear;//! Whether to start the timer immediatelybool startTimer;
} Timer_A_initUpDownModeParam;
Timer_A_initContinuousModeParam
//*****************************************************************************
//
//! \brief Used in the Timer_A_initContinuousMode() function as the param
//! parameter.
//
//*****************************************************************************
typedef struct Timer_A_initContinuousModeParam {//! Selects Clock source.//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK [Default]//! - \b TIMER_A_CLOCKSOURCE_ACLK//! - \b TIMER_A_CLOCKSOURCE_SMCLK//! - \b TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLKuint16_t clockSource;//! Is the desired divider for the clock source//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_DIVIDER_1 [Default]//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_2//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_3//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_4//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_5//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_6//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_7//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_8//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_10//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_12//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_14//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_16//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_20//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_24//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_28//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_32//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_40//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_48//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_56//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_64uint16_t clockSourceDivider;//! Is to enable or disable Timer_A interrupt//! \n Valid values are://! - \b TIMER_A_TAIE_INTERRUPT_ENABLE//! - \b TIMER_A_TAIE_INTERRUPT_DISABLE [Default]uint16_t timerInterruptEnable_TAIE;//! Decides if Timer_A clock divider, count direction, count need to be//! reset.//! \n Valid values are://! - \b TIMER_A_DO_CLEAR//! - \b TIMER_A_SKIP_CLEAR [Default]uint16_t timerClear;//! Whether to start the timer immediatelybool startTimer;
} Timer_A_initContinuousModeParam;
Timer_A_initCaptureModeParam
//*****************************************************************************
//
//! \brief Used in the Timer_A_initCaptureMode() function as the param
//! parameter.
//
//*****************************************************************************
typedef struct Timer_A_initCaptureModeParam {//! Selects the Capture register being used. Refer to datasheet to ensure//! the device has the capture compare register being used.//! \n Valid values are://! - \b TIMER_A_CAPTURECOMPARE_REGISTER_0//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_1//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_2//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_3//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_4//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_5//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_6uint16_t captureRegister;//! Is the capture mode selected.//! \n Valid values are://! - \b TIMER_A_CAPTUREMODE_NO_CAPTURE [Default]//! - \b TIMER_A_CAPTUREMODE_RISING_EDGE//! - \b TIMER_A_CAPTUREMODE_FALLING_EDGE//! - \b TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGEuint16_t captureMode;//! Decides the Input Select//! \n Valid values are://! - \b TIMER_A_CAPTURE_INPUTSELECT_CCIxA//! - \b TIMER_A_CAPTURE_INPUTSELECT_CCIxB//! - \b TIMER_A_CAPTURE_INPUTSELECT_GND//! - \b TIMER_A_CAPTURE_INPUTSELECT_Vccuint16_t captureInputSelect;//! Decides if capture source should be synchronized with timer clock//! \n Valid values are://! - \b TIMER_A_CAPTURE_ASYNCHRONOUS [Default]//! - \b TIMER_A_CAPTURE_SYNCHRONOUSuint16_t synchronizeCaptureSource;//! Is to enable or disable timer captureComapre interrupt.//! \n Valid values are://! - \b TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE [Default]//! - \b TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLEuint16_t captureInterruptEnable;//! Specifies the output mode.//! \n Valid values are://! - \b TIMER_A_OUTPUTMODE_OUTBITVALUE [Default]//! - \b TIMER_A_OUTPUTMODE_SET//! - \b TIMER_A_OUTPUTMODE_TOGGLE_RESET//! - \b TIMER_A_OUTPUTMODE_SET_RESET//! - \b TIMER_A_OUTPUTMODE_TOGGLE//! - \b TIMER_A_OUTPUTMODE_RESET//! - \b TIMER_A_OUTPUTMODE_TOGGLE_SET//! - \b TIMER_A_OUTPUTMODE_RESET_SETuint16_t captureOutputMode;
} Timer_A_initCaptureModeParam;
Timer_A_initCompareModeParam
//*****************************************************************************
//
//! \brief Used in the Timer_A_initCompareMode() function as the param
//! parameter.
//
//*****************************************************************************
typedef struct Timer_A_initCompareModeParam {//! Selects the Capture register being used. Refer to datasheet to ensure//! the device has the capture compare register being used.//! \n Valid values are://! - \b TIMER_A_CAPTURECOMPARE_REGISTER_0//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_1//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_2//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_3//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_4//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_5//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_6uint16_t compareRegister;//! Is to enable or disable timer captureComapre interrupt.//! \n Valid values are://! - \b TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE [Default]//! - \b TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLEuint16_t compareInterruptEnable;//! Specifies the output mode.//! \n Valid values are://! - \b TIMER_A_OUTPUTMODE_OUTBITVALUE [Default]//! - \b TIMER_A_OUTPUTMODE_SET//! - \b TIMER_A_OUTPUTMODE_TOGGLE_RESET//! - \b TIMER_A_OUTPUTMODE_SET_RESET//! - \b TIMER_A_OUTPUTMODE_TOGGLE//! - \b TIMER_A_OUTPUTMODE_RESET//! - \b TIMER_A_OUTPUTMODE_TOGGLE_SET//! - \b TIMER_A_OUTPUTMODE_RESET_SETuint16_t compareOutputMode;//! Is the count to be compared with in compare modeuint16_t compareValue;
} Timer_A_initCompareModeParam;
定时器A 输出相关函数
Timer_A_getSynchronizedCaptureCompareInput((uint16_t baseAddress, uint16_t
captureCompareRegister, uint16_t synchronized)
//获取同步的capturecompare输入
Timer_A_getOutputForOutputModeOutBitValue(uint16_t baseAddress, uint16_t
captureCompareRegister)
//为输出模式获取输出位
Timer_A_setOutputForOutputModeOutBitValue(uint16_t baseAddress, uint16_t
captureCompareRegister, uint8_t outputModeOutBitValue)
//为输出模式设置输出位
Timer_A_outputPWM(uint16_t baseAddress, Timer_A_outputPWMParam ∗param)
//计时器A运行在增计数模式产生PWM
Timer_A_getCaptureCompareCount(uint16_t baseAddress, uint16_t
captureCompareRegister)
//获取当前capturecompare计数值
Timer_A_setCompareValue(uint16_t baseAddress, uint16_t compareRegister, uint16_t
compareValue)
//设置捕获比较寄存器的值
Timer_A_getCounterValue(uint16_t baseAddress)
//读取当前计时器A计数值
参数
baseAddress
是TIMER_A模块的基地址
TIMER_A0_BASE
TIMER_A1_BASE
TIMER_A2_BASE
captureCompareRegister
TIMER_A_CAPTURECOMPARE_REGISTER_0
TIMER_A_CAPTURECOMPARE_REGISTER_1
TIMER_A_CAPTURECOMPARE_REGISTER_2
TIMER_A_CAPTURECOMPARE_REGISTER_3
TIMER_A_CAPTURECOMPARE_REGISTER_4
TIMER_A_CAPTURECOMPARE_REGISTER_5
TIMER_A_CAPTURECOMPARE_REGISTER_6
compareRegister
TIMER_A_CAPTURECOMPARE_REGISTER_0
TIMER_A_CAPTURECOMPARE_REGISTER_1
TIMER_A_CAPTURECOMPARE_REGISTER_2
TIMER_A_CAPTURECOMPARE_REGISTER_3
TIMER_A_CAPTURECOMPARE_REGISTER_4
TIMER_A_CAPTURECOMPARE_REGISTER_5
TIMER_A_CAPTURECOMPARE_REGISTER_6
synchronized
TIMER_A_READ_SYNCHRONIZED_CAPTURECOMPAREINPUT
TIMER_A_READ_CAPTURE_COMPARE_INPUT
outputModeOutBitValue
TIMER_A_OUTPUTMODE_OUTBITVALUE_HIGH
TIMER_A_OUTPUTMODE_OUTBITVALUE_LOW
Timer_A_outputPWMParam
//*****************************************************************************
//
//! \brief Used in the Timer_A_outputPWM() function as the param parameter.
//
//*****************************************************************************
typedef struct Timer_A_outputPWMParam {//! Selects Clock source.//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_EXTERNAL_TXCLK [Default]//! - \b TIMER_A_CLOCKSOURCE_ACLK//! - \b TIMER_A_CLOCKSOURCE_SMCLK//! - \b TIMER_A_CLOCKSOURCE_INVERTED_EXTERNAL_TXCLKuint16_t clockSource;//! Is the desired divider for the clock source//! \n Valid values are://! - \b TIMER_A_CLOCKSOURCE_DIVIDER_1 [Default]//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_2//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_3//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_4//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_5//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_6//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_7//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_8//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_10//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_12//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_14//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_16//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_20//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_24//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_28//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_32//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_40//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_48//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_56//! - \b TIMER_A_CLOCKSOURCE_DIVIDER_64uint16_t clockSourceDivider;//! Selects the desired timer perioduint16_t timerPeriod;//! Selects the compare register being used. Refer to datasheet to ensure//! the device has the capture compare register being used.//! \n Valid values are://! - \b TIMER_A_CAPTURECOMPARE_REGISTER_0//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_1//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_2//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_3//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_4//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_5//! - \b TIMER_A_CAPTURECOMPARE_REGISTER_6uint16_t compareRegister;//! Specifies the output mode.//! \n Valid values are://! - \b TIMER_A_OUTPUTMODE_OUTBITVALUE [Default]//! - \b TIMER_A_OUTPUTMODE_SET//! - \b TIMER_A_OUTPUTMODE_TOGGLE_RESET//! - \b TIMER_A_OUTPUTMODE_SET_RESET//! - \b TIMER_A_OUTPUTMODE_TOGGLE//! - \b TIMER_A_OUTPUTMODE_RESET//! - \b TIMER_A_OUTPUTMODE_TOGGLE_SET//! - \b TIMER_A_OUTPUTMODE_RESET_SETuint16_t compareOutputMode;//! Specifies the dutycycle for the generated waveformuint16_t dutyCycle;
} Timer_A_outputPWMParam;
compareValue
是比较模式下需要比较的计数值
管理定时器A中断的程序
Timer_A_enableInterrupt(uint16_t baseAddress)
//使能定时器中断
Timer_A_disableInterrupt(uint16_t baseAddress)
//禁用定时器中断
Timer_A_getInterruptStatus(uint16_t baseAddress)
//获取定时器中断状态
Timer_A_enableCaptureCompareInterrupt(uint16_t baseAddress, uint16_t
captureCompareRegister)
//启用捕获比较中断
Timer_A_disableCaptureCompareInterrupt(uint16_t baseAddress, uint16_t
captureCompareRegister)
//禁用捕获比较中断
Timer_A_getCaptureCompareInterruptStatus(uint16_t baseAddress, uint16_t
captureCompareRegister, uint16_t mask)
//返回捕获比较中断状态
Timer_A_clearCaptureCompareInterrupt(uint16_t baseAddress, uint16_t
captureCompareRegister)
//清除捕获比较中断标志
Timer_A_clearTimerInterrupt(uint16_t baseAddress)
//清除Timer TAIFG中断标志
参数
baseAddress
是TIMER_A模块的基地址
TIMER_A0_BASE
TIMER_A1_BASE
TIMER_A2_BASE
captureCompareRegister
TIMER_A_CAPTURECOMPARE_REGISTER_0
TIMER_A_CAPTURECOMPARE_REGISTER_1
TIMER_A_CAPTURECOMPARE_REGISTER_2
TIMER_A_CAPTURECOMPARE_REGISTER_3
TIMER_A_CAPTURECOMPARE_REGISTER_4
TIMER_A_CAPTURECOMPARE_REGISTER_5
TIMER_A_CAPTURECOMPARE_REGISTER_6
mask
TIMER_A_CAPTURE_OVERFLOW
TIMER_A_CAPTURECOMPARE_INTERRUPT_FLAG
中断向量
TIMERx_A0_VECTOR 是 CCR0 的中断向量
TIMERx_A1_VECTOR 是 TAIV 的中断向量
#define TIMER2_A1_VECTOR (43 * 1u) /* 0xFFD6 Timer2_A5 CC1-4, TA */
#define TIMER2_A0_VECTOR (44 * 1u) /* 0xFFD8 Timer2_A5 CC0 */
#define TIMER1_A1_VECTOR (48 * 1u) /* 0xFFE0 Timer1_A3 CC1-2, TA1 */
#define TIMER1_A0_VECTOR (49 * 1u) /* 0xFFE2 Timer1_A3 CC0 */
#define TIMER0_A1_VECTOR (52 * 1u) /* 0xFFE8 Timer0_A5 CC1-4, TA */
#define TIMER0_A0_VECTOR (53 * 1u) /* 0xFFEA Timer0_A5 CC0 */
上机实战
定时器A 增计数模式CCR0中断
初始化函数
void Timer_A_Init(void)
{Timer_A_initUpModeParam htim = {0};htim.clockSource = TIMER_A_CLOCKSOURCE_ACLK; //时钟源选为ACLK = 32768Hzhtim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_64; //64分频htim.timerPeriod = 512 - 1; //计数值设为512 - 1htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE; //使能CCR0中断htim.timerClear = TIMER_A_DO_CLEAR; //把定时器的定时计数器,分频计数器的计数值清零htim.startTimer = true; //初始化后立即启动定时器//中断频率=32768Hz / 64 / 512 = 1HzTimer_A_initUpMode(TIMER_A0_BASE, &htim);//配置定时器A0为增计数模式
}
中断服务函数
#pragma vector=TIMER0_A0_VECTOR
__interrupt
void TIMER0_A0_ISR (void)
{GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7); //翻转P4.7
}
整个源文件如下
#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 SystemClock_Init(void)
{PMM_setVCore(PMM_CORE_LEVEL_3); //高主频工作需要较高的核心电压//XT1引脚复用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);//起振XT1UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);//XT2引脚复用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);//起振XT2UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);//XT2作为FLL参考时钟,先8分频,再50倍频 4MHz / 8 * 50 = 25MHzUCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);UCS_initFLLSettle(25000, 50);//XT1作为ACLK时钟源 = 32768HzUCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作为MCLK时钟源 = 25MHzUCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作为SMCLK时钟源 = 25MHzUCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值UCS_setExternalClockSource(32768, 4000000);
}void Timer_A_Init(void)
{Timer_A_initUpModeParam htim = {0};htim.clockSource = TIMER_A_CLOCKSOURCE_ACLK;htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_64;htim.timerPeriod = 512 - 1;htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;htim.timerClear = TIMER_A_DO_CLEAR;htim.startTimer = true;Timer_A_initUpMode(TIMER_A0_BASE, &htim);//配置定时器A为增计数模式
}int main(void)
{WDT_A_hold(WDT_A_BASE);SystemClock_Init();GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN7);Timer_A_Init();//interrupts enabled__bis_SR_register(GIE);while(1){}
}#pragma vector=TIMER0_A0_VECTOR
__interrupt
void TIMER0_A0_ISR (void)
{GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);
}
实验结果
如图,成功得到脉宽为1s的方波
定时器A 增计数模式TAIE中断
初始化函数
void Timer_A_Init(void)
{Timer_A_initUpModeParam htim = {0};htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; //时钟源选为SMCLK = 25MHzhtim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_5; //5分频htim.timerPeriod = 25000 - 1; //计数值设为25000 - 1htim.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; //初始化后立即启动定时器Timer_A_initUpMode(TIMER_A0_BASE, &htim); //配置定时器A为增计数模式
}
中断服务函数
#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_PIN7);break;default:break;}
}
整个源文件如下
#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 SystemClock_Init(void)
{PMM_setVCore(PMM_CORE_LEVEL_3); //高主频工作需要较高的核心电压//XT1引脚复用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);//起振XT1UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);//XT2引脚复用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);//起振XT2UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);//XT2作为FLL参考时钟,先8分频,再50倍频 4MHz / 8 * 50 = 25MHzUCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);UCS_initFLLSettle(25000, 50);//XT1作为ACLK时钟源 = 32768HzUCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作为MCLK时钟源 = 25MHzUCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作为SMCLK时钟源 = 25MHzUCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值UCS_setExternalClockSource(32768, 4000000);
}void Timer_A_Init(void)
{Timer_A_initUpModeParam htim = {0};htim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_5;htim.timerPeriod = 25000 - 1;htim.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;htim.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_DISABLE;htim.timerClear = TIMER_A_DO_CLEAR;htim.startTimer = true;//设得中断频率为25MHz / 5 / 25000 = 200HzTimer_A_initUpMode(TIMER_A0_BASE, &htim);//配置定时器A为增计数模式
}int main(void)
{WDT_A_hold(WDT_A_BASE);SystemClock_Init();GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN7);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_PIN7);break;default:break;}
}
实验结果
如图所示,得到100Hz的方波,为所设定时器中断频率的一半。
输入捕获模式测量脉宽长度
初始化函数
先将Timer_A2初始化为连续计数模式
时钟源为SMCLK
将P2.5/TA2.2复用为输入捕获模式
TA2.2对应TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2
检测上升沿和下降沿
uint32_t Sign_Counts = 0;
void Timer_A2_Capture_Init()
{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);GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN5);Timer_A_initCaptureModeParam capture_htim = {0};capture_htim.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;capture_htim.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;capture_htim.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;capture_htim.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;capture_htim.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;capture_htim.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;Timer_A_initCaptureMode(TIMER_A2_BASE,&capture_htim);
}
中断服务函数
TA2.2对应TA2IV_TACCR2
检测到上升沿时记下初始计数值
检测到下降沿后记下结束时计数值,并将溢出次数清零
当被测信号为高电平时,每溢出一次,溢出次数增1,
最终信号长度即溢出次数*计时周期数+结束时计数值-初始计数值
#pragma vector=TIMER2_A1_VECTOR
__interrupt
void TIMER2_A1_ISR (void)
{static uint16_t Overflow_Times = 0;static uint16_t Sign_Begin = 0, Sign_End = 0;switch(TA2IV){case TA2IV_TACCR2:if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN5)){Sign_Begin = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);}else{Sign_End = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);if(!Overflow_Times)Sign_Counts = Sign_End - Sign_Begin;else{Sign_Counts = (uint32_t)65536 * Overflow_Times + Sign_End - Sign_Begin;Overflow_Times = 0;}}Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);break;case TA2IV_TAIFG:if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN5)){++Overflow_Times;}elseOverflow_Times = 0;Timer_A_clearTimerInterrupt(TIMER_A2_BASE);break;default:break;}
}
被测信号产生
信号产生引脚为P1.2
频率=25MHz/12500/40=50Hz
占空比为1/20=5%
脉宽长度为1/50*5%=1ms
将产生信号的P1.2接至检测信号的P2.5
#define TIMER_PERIOD 12500
void Timer_A0_PWM_Init(void)
{Timer_A_outputPWMParam htim = {0};//P1.2复用输出GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2);//时钟源选为SMCLK = 25MHzhtim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//分频系数设为40htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_40;//装载值设为12500 - 1htim.timerPeriod = TIMER_PERIOD - 1;//P1.2 对应 TA0.1 故设为TIMER_A_CAPTURECOMPARE_REGISTER_1htim.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;htim.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//脉宽为1mshtim.dutyCycle = TIMER_PERIOD / 20 ;//P1.2 对应 TA0.1 为TIMER_A0_BASETimer_A_outputPWM(TIMER_A0_BASE, &htim);
}
整个源文件如下
#include "driverlib.h"
#include "MSP430F5529_UART.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 SystemClock_Init(void)
{PMM_setVCore(PMM_CORE_LEVEL_3); //高主频工作需要较高的核心电压//XT1引脚复用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);//起振XT1UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);//XT2引脚复用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);//起振XT2UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);//XT2作为FLL参考时钟,先8分频,再50倍频 4MHz / 8 * 50 = 25MHzUCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);UCS_initFLLSettle(25000, 50);//XT1作为ACLK时钟源 = 32768HzUCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作为MCLK时钟源 = 25MHzUCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作为SMCLK时钟源 = 25MHzUCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值UCS_setExternalClockSource(32768, 4000000);
}#define TIMER_PERIOD 12500
void Timer_A0_PWM_Init(void)
{Timer_A_outputPWMParam htim = {0};//P1.2复用输出GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2);//时钟源选为SMCLK = 25MHzhtim.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//分频系数设为40htim.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_40;//装载值设为12500 - 1htim.timerPeriod = TIMER_PERIOD - 1;//P1.2 对应 TA0.1 故设为TIMER_A_CAPTURECOMPARE_REGISTER_1htim.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;htim.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//脉宽为1mshtim.dutyCycle = TIMER_PERIOD / 20 ;//P1.2 对应 TA0.1 为TIMER_A0_BASETimer_A_outputPWM(TIMER_A0_BASE, &htim);
}uint32_t Sign_Counts = 0;
void Timer_A2_Capture_Init()
{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);GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN5);Timer_A_initCaptureModeParam capture_htim = {0};capture_htim.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;capture_htim.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;capture_htim.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;capture_htim.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;capture_htim.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;capture_htim.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;Timer_A_initCaptureMode(TIMER_A2_BASE,&capture_htim);
}int main(void)
{WDT_A_hold(WDT_A_BASE);SystemClock_Init();UART_Init(USCI_A1_BASE, 115200);Timer_A0_PWM_Init();Timer_A2_Capture_Init();//interrupts enabled__bis_SR_register(GIE);while(1){delay_ms(1000);UART_printf(USCI_A1_BASE, "Pulse width: %fms\r\n", 1000.*Sign_Counts/UCS_getSMCLK());}
}#pragma vector=TIMER2_A1_VECTOR
__interrupt
void TIMER2_A1_ISR (void)
{static uint16_t Overflow_Times = 0;static uint16_t Sign_Begin = 0, Sign_End = 0;switch(TA2IV){case TA2IV_TACCR2:if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN5)){Sign_Begin = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);}else{Sign_End = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);if(!Overflow_Times)Sign_Counts = Sign_End - Sign_Begin;else{Sign_Counts = (uint32_t)65536 * Overflow_Times + Sign_End - Sign_Begin;Overflow_Times = 0;}}Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);break;case TA2IV_TAIFG:if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN5)){++Overflow_Times;}elseOverflow_Times = 0;Timer_A_clearTimerInterrupt(TIMER_A2_BASE);break;default:break;}
}
MSP430F5529_UART.c
/** MSP430F5529_UART.c** Created on: 2021年7月25日* Author: Royic*/
#include "driverlib.h"#include <string.h>
#include <stdarg.h>
#include <stdio.h>
void UART_printf(uint16_t baseAddress, const char *format,...)
{uint32_t length;va_list args;uint32_t i;char TxBuffer[128] = {0};va_start(args, format);length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer)+1, (char*)format, args);va_end(args);for(i = 0; i < length; i++)USCI_A_UART_transmitData(baseAddress, TxBuffer[i]);
}bool UART_Init(uint16_t baseAddress, uint32_t Baudrate)
{float UART_Temp = 0;USCI_A_UART_initParam huart = {0};if(baseAddress == USCI_A0_BASE) //P3.3, P3.4 = USCI_A0 TXD/RXD{GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3, GPIO_PIN3);GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3, GPIO_PIN4);}else if(baseAddress == USCI_A1_BASE) //P4.4, P4.5 = USCI_A1 TXD/RXD{GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN4);GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5);}if(Baudrate <= 9600){huart.selectClockSource = USCI_A_UART_CLOCKSOURCE_ACLK;UART_Temp = (float)UCS_getACLK()/Baudrate;}else{huart.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;UART_Temp = (float)UCS_getSMCLK()/Baudrate;}if(UART_Temp < 16)huart.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;else{huart.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;UART_Temp /= 16;}huart.clockPrescalar = (int)UART_Temp;if(huart.overSampling == USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION){huart.secondModReg = (int)((UART_Temp - huart.clockPrescalar) * 8);}else{huart.firstModReg = (int)((UART_Temp - huart.clockPrescalar) * 16);}huart.parity = USCI_A_UART_NO_PARITY;huart.msborLsbFirst = USCI_A_UART_LSB_FIRST;huart.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;huart.uartMode = USCI_A_UART_MODE;if (STATUS_FAIL == USCI_A_UART_init(baseAddress, &huart)){return STATUS_FAIL;}//Enable UART module for operationUSCI_A_UART_enable(baseAddress);//Enable Receive InterruptUSCI_A_UART_clearInterrupt(baseAddress, USCI_A_UART_RECEIVE_INTERRUPT);USCI_A_UART_enableInterrupt(baseAddress, USCI_A_UART_RECEIVE_INTERRUPT);return STATUS_SUCCESS;
}//******************************************************************************
//
//This is the USCI_A0 interrupt vector service routine.
//
//******************************************************************************
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR (void)
{uint8_t receivedData = 0;switch (__even_in_range(UCA0IV,4)){//Vector 2 - RXIFGcase 2:receivedData = USCI_A_UART_receiveData(USCI_A0_BASE);USCI_A_UART_transmitData(USCI_A0_BASE,receivedData);break;default:break;}
}//******************************************************************************
//
//This is the USCI_A1 interrupt vector service routine.
//
//******************************************************************************
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR (void)
{uint8_t receivedData = 0;switch (__even_in_range(UCA1IV,4)){//Vector 2 - RXIFGcase 2:receivedData = USCI_A_UART_receiveData(USCI_A1_BASE);USCI_A_UART_transmitData(USCI_A1_BASE,receivedData);break;default:break;}
}
MSP430F5529_UART.h
/** MSP430F5529_UART.h** Created on: 2021年7月25日* Author: Royic*/#ifndef MSP430F5529_UART_H_
#define MSP430F5529_UART_H_#include "driverlib.h"void UART_printf(uint16_t baseAddress, const char *format,...);
bool UART_Init(uint16_t baseAddress, uint32_t Baudrate);#endif /* MSP430F5529_UART_H_ */