TI中文支持网
TI专业的中文技术问题搜集分享网站

MSP430F5529: 输入捕获

Part Number:MSP430F5529

我的问题是我设置两个定时器为输入捕获,但是我debug的时候发现两个寄存器的值是乱跳的,根本不是有规律的,至于网上说的溢出问题,我觉得在我这不存在,因为我输入的是VPP=3v,频率为1Hz的方波信号,而且在while(1)里面我尝试读取寄存器的值,发现edge_count1和edge_count2的值总是为零,不知道为什么,希望能得到回复,谢谢大家了。

#include "driverlib.h"

#define TIMER_PERIOD 12500
#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)))
volatile uint16_t edge_count1,edge_count2;
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);

//起振XT1
UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);

//XT2引脚复用
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);
GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);

//起振XT2
UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);

//XT2作为FLL参考时钟,先8分频,再50倍频 4MHz / 8 * 50 = 25MHz
UCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);
UCS_initFLLSettle(25000, 50);

//XT1作为ACLK时钟源 = 32768Hz
UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);

//DCOCLK作为MCLK时钟源 = 25MHz
UCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

//DCOCLK作为SMCLK时钟源 = 25MHz
UCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

//设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值
UCS_setExternalClockSource(32768, 4000000);
}
//timer0_A5
void Timer_LCapture_init(){
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,GPIO_PIN2);

Timer_A_initContinuousModeParam TimerA0_Init = {0};
TimerA0_Init.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
TimerA0_Init.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
TimerA0_Init.timerClear = TIMER_A_DO_CLEAR;
TimerA0_Init.startTimer = true;
Timer_A_initContinuousMode (TIMER_A0_BASE,&TimerA0_Init);

Timer_A_initCaptureModeParam Capture_Init = {0};
Capture_Init.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;
Capture_Init.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;
Capture_Init.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;
Capture_Init.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;
Capture_Init.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE;
Capture_Init.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;
Timer_A_initCaptureMode(TIMER_A0_BASE,&Capture_Init);

Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_1
);
}

/*Timer1_A3*/
void Timer_RCapture_init(){
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2,GPIO_PIN0);

Timer_A_initContinuousModeParam TIMERA1_Init = {0};
TIMERA1_Init.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
TIMERA1_Init.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
TIMERA1_Init.timerClear = TIMER_A_DO_CLEAR;
TIMERA1_Init.startTimer = true;
Timer_A_initContinuousMode (TIMER_A1_BASE,&TIMERA1_Init);

Timer_A_initCaptureModeParam Capture_Init = {0};
Capture_Init.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;
Capture_Init.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;
Capture_Init.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;
Capture_Init.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;
Capture_Init.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_DISABLE;
Capture_Init.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;
Timer_A_initCaptureMode(TIMER_A1_BASE,&Capture_Init);

Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE,
TIMER_A_CAPTURECOMPARE_REGISTER_1
);
}

void Timer_B_Init(){
Timer_B_initContinuousModeParam initContParam = {0};//定义连续模式结构体变量
initContParam.clockSource = TIMER_B_CLOCKSOURCE_SMCLK;//选择SMCLK
initContParam.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_5;//不分频
initContParam.timerInterruptEnable_TBIE = TIMER_B_TBIE_INTERRUPT_DISABLE;//暂时不使能中断
initContParam.timerClear = TIMER_B_DO_CLEAR;//清除定时器
initContParam.startTimer = false;//暂时不开始计时
Timer_B_initContinuousMode(TIMER_B0_BASE, &initContParam);

//Initiaze compare mode
Timer_B_clearCaptureCompareInterrupt(TIMER_B0_BASE,//清楚定时器的中断标志位
TIMER_B_CAPTURECOMPARE_REGISTER_4
);

Timer_B_initCompareModeParam initCompParam = {0};
initCompParam.compareRegister = TIMER_B_CAPTURECOMPARE_REGISTER_4;//选择对应的捕获比较寄存器
initCompParam.compareInterruptEnable = TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE;//使能定时器中断
initCompParam.compareOutputMode = TIMER_B_OUTPUTMODE_OUTBITVALUE;//选择输出模式
initCompParam.compareValue = 50000;//确定比较值
Timer_B_initCompareMode(TIMER_B0_BASE, &initCompParam);//初始化比较模式

Timer_B_startCounter( TIMER_B0_BASE,//开始计数
TIMER_B_CONTINUOUS_MODE
);
}

int main(){
WDT_A_hold(WDT_A_BASE); // 关闭看门狗
SystemClock_Init();
Timer_B_Init();
Timer_LCapture_init();
Timer_RCapture_init();
GPIO_setAsOutputPin(GPIO_PORT_P4,GPIO_PIN7);
while(1){
edge_count1 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);//将此时的上升沿计数值存入变量
edge_count2 = Timer_A_getCaptureCompareCount(TIMER_A1_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);//将此时的上升沿计数值存入变量
__bis_SR_register(LPM0_bits + GIE); //进入低功耗模式0,同时打开全局中断
}
}

#pragma vector=TIMER0_B1_VECTOR //中断 TIMER1_B1_VECTOR
__interrupt void TIMERB0_ISR (void)
{
static unsigned int CNT = 0;
switch(__even_in_range(TBIV,14))
{
case 8:{
GPIO_setOutputHighOnPin(GPIO_PORT_P4,GPIO_PIN7);
if(CNT % 2 == 0)//记录第一次的上升沿Counter计数值
{
edge_count1 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);//将此时的上升沿计数值存入变量
}
else if(CNT % 2 == 1)//检测到下降沿触发
{
edge_count2 = Timer_A_getCaptureCompareCount(TIMER_A1_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);//将此时的下降沿计数值存入变量
}
break;
}
}
CNT++;
_BIC_SR_IRQ(LPM0_bits);
}

每一张图片进行一次debug,可以明显的发现不正常!

Yale Li:

您好,低频捕获时TAxR一定会会溢出,这是正常的。具体原因您看一下这个帖子:https://e2echina.ti.com/support/microcontrollers/c2000/f/c2000-microcontrollers-forum/234596/tms320f28034-hrcap-50hz。这个帖子虽然是在C2000 HRCAP模块的基础上解释的,但是原因在MSP430的Timer上基本相同。简单来说的话就是,计数器的最大计数值65536(TAxR16bit)乘上每一次计数的时间0.00000004s(以您使用的SMCLK/1=25MHz为例)等于0.00262144,远小于0.5s(1Hz方波)。

baba Liang 说:而且在while(1)里面我尝试读取寄存器的值,发现edge_count1和edge_count2的值总是为零

您while(1)中的最后一行代码:

__bis_SR_register(LPM0_bits + GIE); //进入低功耗模式0,同时打开全局中断

关闭了CPU,主程序运行到这里就停在这儿了,我的推测是,如果在这之前没有捕获到,TAxCCRy的值为0,edge_count1和edge_count2的值当然也就是0了。

你上传的截图中我没有发现什么异样。比如程序暂停到第三张截图的时候,可以看到第二张截图的TA0R被成功的装载到TA0CCR1(0xE915),也就是您程序暂停到第二张截图前成功进行捕获。

,

baba Liang:

非常感谢你的回复,刚学嵌入式,不是很熟悉,能问一下为什么捕获和定时器的时钟源有关系,而且在配置捕获的时候我发现有一个参数是.synchronizeCaptureSource,不太懂它有什么作用。在后来的时候我尝试用P2.4,P2.5作为捕获口进入中断计数加一,这虽然在低频的时候可行但是会影响其他中断的进行,比如定时器B的中断。再后来我尝试令TimerA0和TimerA1的时钟源为外部时钟进行计数,发现我一旦接上外部信号他就不能计数,令它的时钟源为ACLK或SMCLK或MCLK都可以正常计数,我以为是频率太低的原因,我就试着把频率调高(1MHz),发现还是不行,后面我发现VPP是3V,以为太低,我就调到5V,还是不行我不知道为什么。今天我就是采用P2.5和P2.4进行捕获,在定时器中每隔100ms关闭一次P2.5和P2.4中断来保证主程序能够正常运行,但是发现它只能进入一次定时器中断,不知道为什么。希望能得到你的再次回复,非常感谢。

,

Yale Li:

baba Liang 说:为什么捕获和定时器的时钟源有关系

捕获的原理是记录特定信号(由用户指定)发生时刻的计数器数值,而计数器就是在时钟的基础上运行(其实MCU的所有模块都是在时钟的基础上运行,在Timer上体现的更明显),每过一个时钟周期,计数值+1。从框图中也可以看出来:

(slau208q_MSP430x5xx and MSP430x6xx Family User's Guide (Rev. Q)Figure 17-1. Timer_A Block Diagram)

baba Liang 说:synchronizeCaptureSource

关于这个参数的使用,你可以参考https://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430_Driver_Library/2_91_13_01/exports/driverlib/msp430_driverlib_2_91_13_01/doc/MSP430F5xx_6xx/html/struct_timer___a__init_capture_mode_param.html#ab13d728ec678df4614b482d28fc0889a:

当输入捕获信号与时钟同步时的时序图:

(slau208q_MSP430x5xx and MSP430x6xx Family User's Guide (Rev. Q)Figure 17-10. Capture Signal (SCS = 1) )

着重看我画红线的地方,CCI是输入捕获信号,Timer Clock是时钟,简单来说就是选择同步的话,画红线的两处会对齐。不同步的话会导致竞争。一般设置为同步:

baba Liang 说:尝试用P2.4,P2.5作为捕获口进入中断计数加一

我不太理解您具体是怎么使用的。捕获配置好后,是由Timer模块独立与CPU进行的,当捕获触发时,TAxR的值被Timer自动装载到TAxCCRy中,并触发中断,提醒CPU捕获完成,然后用户可以在该中断中对捕获值进行处理,比如计算信号的频率。

关于Timer的使用入门强烈推荐看一下这个帖子:https://bbs.nuedc-training.com.cn/thread-366-1-1.html

教程里面用的是G2553,但Timer模块基本相同。

建议您在例程的基础上来编写程序,您下载MSP430WARE并在默认安装路径安装以后,会在以下位置找到相应例程:

寄存器版:C:\ti\msp\MSP430Ware_3_80_14_01\examples\devices\MSP430F5xx_6xx\MSP430F55xx_Code_Examples\C

库函数版:C:\ti\msp\MSP430Ware_3_80_14_01\driverlib\examples\MSP430F5xx_6xx

,

baba Liang:

再次感谢你的回复,但是还没有解决我想要实现的功能,我想解决的是捕获带编码电机的脉冲数(上升沿和下降沿的数量),但是MSP430f5529没有编码器功能,刚开始我理解错定时器捕获功能的意思所以错了,所以我想着用P1和P2的引脚作为输入进行上升沿和下降沿的捕获(通过中断),捕获A、B相的脉冲数,(每进入相应引脚的中断,相应的Left_MotorCount、Right_MotorCount,加一)但是如果用引脚口去捕获编码器的脉冲数地话会一直进入中断,而且也不能保证进入中断的时候下一个脉冲是否到来,如果在中断中开启中断嵌套,我发现程序直接卡死(我先清除中断再开的中断嵌套)。如果说是我的程序有问题但我也不知道1秒产生800个脉冲以这个频率进入中断是不是会影响主程序的进行。就是再这种情况下我就想到了,定时器可以选择外部时钟源(编码器A、B相),(定时器会根据时钟源进行计数),来代替引脚中断进行计数,然后通过另一个一SMCLK为时钟源的定时器进行定时读取以外部时钟源的定时器的计数寄存器的值并清除计数值,以此来读取编码器脉冲数。这是我的思路,不知道你能不能理解,非常感谢你的回复!

,

Yale Li:

您参考一下这个帖子的思路:https://e2echina.ti.com/support/microcontrollers/msp430/f/msp-low-power-microcontroller-forum/263822/msp430f5529-msp430f5529

baba Liang 说:就是再这种情况下我就想到了,定时器可以选择外部时钟源(编码器A、B相)

您的意思是将编码器的脉冲作为外部时钟源?这样应该是行不通的,外部时钟源的输入是有具体要求的。

赞(0)
未经允许不得转载:TI中文支持网 » MSP430F5529: 输入捕获
分享到: 更多 (0)