使用捕获功能对频率信号进行测量,捕获到第一个上升沿时对TBCCR1寄存器值进行读取,赋值给SMCLK_Count_Num_start变量,设置当TBR寄存器在连续模式下连续溢出11次时停止捕获,将此时TBCCR1寄存器的值赋予SMCLK_Count_Num_stop变量,按如下公式进行计算:
SMCLK_Count_Num = 65535*overflow_Num + SMCLK_Count_Num_stop – SMCLK_Count_Num_start
Frequency = ((CaptureNum-1)*SMCLK_Frequency)/SMCLK_Count_Num
在调试过程中,出现现象为待测频率高于80kHz时 TIMERB1中断case14无法进入,溢出次数变量无法更新,导致程序卡死
请各位帮忙分析解答问题所在。
主程序如下:
#include <msp430fg439.h>
#include "main.h"
void main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
SetupClock();
Capture_Pos();
__enable_interrupt();//中断使能
while(1)
{
if (cap_finish_flag ==1)
{
cap_finish_flag = 0;
SMCLK_Count_Num = 65535*overflow_Num + SMCLK_Count_Num_stop – SMCLK_Count_Num_start;
Frequency = ((CaptureNum-1)*SMCLK_Frequency)/SMCLK_Count_Num;
CaptureNum = 0;
overflow_Num = 0;
TB0CTL |= MC_2;
TBCTL |= TBCLR + TBIE;
TBCCTL1 |= CCIE;
}
}
}
void SetupClock()
{
uint16_t tmpv;
FLL_CTL1 &= ~XT2OFF; //开启外部振荡器
do
{
IFG1 &= ~OFIFG; //清除晶振失效标志
for (tmpv = 0xff; tmpv > 0; tmpv–);
}
while((IFG1 & OFIFG)!=0); //*等待外部晶振就绪
IFG1 &= ~OFIFG;
FLL_CTL1 |= SELM_XT2+SELS; //选择MCLK,选择SMCLK //+DIVM_1
}
void Capture_Pos()//TIMER_B 捕获/比较寄存器 0
{
P2SEL |= BIT2; //TIMER B1通道
P2DIR &= ~BIT2;
//SMCLK做时钟源,16位计数器,不分频,连续计数模式,开中断
TB0CTL |= TBSSEL_2 + CNTL_0 + ID_0 + MC_2 + TBCLR + TBIE;
TBCCTL1 = CM_1+ CCIS_1 + SCS + CAP + CCIE;//上升沿触发,同步捕获,使能中断CCI1B
}
#pragma vector = TIMERB1_VECTOR
__interrupt void Timer_B1 (void)
{
switch(TBIV) {
case 2:
TBCCTL1 &= ~COV ;
CaptureNum++;
if(CaptureNum== 1)
{
SMCLK_Count_Num_start = TBCCR1;
overflow_Num = 0;
}
if(overflow_Num== 11)
{
SMCLK_Count_Num_stop = TBCCR1;
cap_finish_flag = 1;
TB0CTL |= MC_0;
TBCTL &= ~TBIE;
TBCCTL1 &=~CCIE;
}
break;
case 4:
break;
case 14:
overflow_Num ++ ;
break;
default:
break;
}
}
Susan Yang:
待测频率80Khz是可以测量的,在数据手册内有相关的说明 www.ti.com.cn/…/msp430fg439.pdf 5.6 Inputs Px.y, TAx, TBx 在G2553有相关的测试例程,您可以参考一下写法 dev.ti.com/…/node 抱歉,目前手边没有MSP430FG系列的板子,我回头找一下其他板子来测试一下
user5960447:
回复 Susan Yang:
已参考该例程进行测试,DEBUG时,程序会在如下程序不断循环:
if (TB0CCTL1 & COV) // Check for Capture Overflow while(1);
测试程序如下:
#include <msp430fg439.h>#include "main.h"unsigned long SMCLK_Count_Num = 0;unsigned long Frequency = 0;unsigned char Count = 0x0;unsigned int REdge1, REdge2;void main(void){ WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer SetupClock(); Capture_Pos();// __enable_interrupt();//中断使能 while(1) {// __enable_interrupt();//中断使能 __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 __no_operation(); // For debugger if (TB0CCTL1 & COV) // Check for Capture Overflow while(1); SMCLK_Count_Num = REdge2 – REdge1; Frequency = (Count*SMCLK_Frequency)/SMCLK_Count_Num;// TBCTL |= TBCLR + TBIE;// TBCCTL1 |= CCIE; }}void SetupClock(){ uint16_t tmpv; FLL_CTL1 &= ~XT2OFF; //开启外部振荡器 do { IFG1 &= ~OFIFG; //清除晶振失效标志 for (tmpv = 0xff; tmpv > 0; tmpv–); } while((IFG1 & OFIFG)!=0); //*等待外部晶振就绪 IFG1 &= ~OFIFG; FLL_CTL1 |= SELM_XT2+SELS; //选择MCLK,选择SMCLK //+DIVM_1}void Capture_Pos()//TIMER_B 捕获/比较寄存器 0{ P2SEL |= BIT2; //TB1端口 P2DIR &= ~BIT2; //SMCLK做时钟源,16位计数器,不分频,连续计数模式,开中断 TB0CTL |= TBSSEL_2 + MC_2 + TBCLR ; TBCCTL1 = CM_1+ CCIS_1 + SCS + CAP + CCIE;//上升沿触发,同步捕获,使能中断CCI1B}#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)#pragma vector = TIMERB1_VECTOR__interrupt void TIMER0_B1_ISR (void)#elif defined(__GNUC__)void __attribute__ ((interrupt(TIMER0_B1_VECTOR))) TIMER0_B1_ISR (void)#else#error Compiler not supported!#endif//__interrupt void Timer_B1 (void){ switch(__even_in_range(TB0IV,0x0A)) //需要判断中断的类型 { case TB0IV_NONE: break; case TB0IV_TBCCR1: if (!Count) { REdge1 = TB0CCR1; Count++; } else { REdge2 = TB0CCR1; Count=0x0;// TBCTL &= ~TBIE;// TBCCTL1 &=~CCIE; __bic_SR_register_on_exit(LPM0_bits + GIE); // Exit LPM0 on return to main } break; case TB0IV_TBCCR2: break; case TBIV_3: break; case TBIV_4: break; case TBIV_5: break; case TBIV_6: break; case TB0IV_TBIFG: break; default: break; }}
Susan Yang:
回复 user5960447:
好的,谢谢反馈 我手边没有这个板子,拿G2553的板子来测试一下后回复
Susan Yang:
回复 user5960447:
我用G2553的板子测试了一下例程是没有问题的,抱歉没有直接FG439的板子来测试
您使用您自己之前的程序是可以测量频率的?只是当待测频率高于80kHz时会有问题?您现在SMCLK 是多少?可以适当增大一下频率
Timer 用作Capture模式时,测量频率及精度取决于Timer的时钟源以及主频。
需要有足够快的时钟源进行边沿捕获,同时还需要有足够快的响应时间进中断进行数据保存和计算。
user5960447:
回复 Susan Yang:
之前的程序目前还没有低功耗模式切换,没有对COV标志位进行判断,会出现高于80kHz无法测量频率。
第二次测试程序是根据FG439芯片修改例程配置而来,程序会一直运行在检查捕获是否溢出的语句中,从我个人的理解4MHz时钟对80kHz频率捕获,应该不会有太大问题。
测试时频率信号来源为信号发生器。
目前测试用开发板为TI官方的MSP-FET430U80目标板搭配FG439芯片,使用32.768kHz和4MHz两个时钟晶振,是否与硬件有关?
我这边会再次检查程序,希望发现问题。
user5960447:
回复 user5960447:
例程已经可以在开发板跑通,尝试在此程序运行基础上,将更大频率的信号接入开发板,程序会停在while(1)循环内
Susan Yang:
回复 user5960447:
MCLK = 4MHz去捕获80kHz是可行的但不容易实现。程序中4MHz / 80kHz = 50个CPU时钟来处理每个捕获,其中大约一半用于ISR开销。
另外
1__bic_SR_register_on_exit(LPM0_bits + GIE);
这将禁用main中的中断,在该除法运算运行时,会导致COV超限。请尝试:
__ bic_SR_register_on_exit(LPM0_bits);
2 建议在在ISR中执行(Redge2-Redge1)减法
3 请将Redge1,Redge2以及SMCLK_Count_Num声明为“ volatile”试试