写一个脉冲频率测量的程序
先确定测频的方法--脉冲填充法
被测信号 ____| |___________| |_____
填充的脉冲 ||||||||||||||||||
定时计数器 CCR(第1次) CCR(第2次)
2次捕获后的捕获寄存器的值相减就是填充的脉冲数
若SMCLK的频率为1MHZ则,输入脉冲周期就是【CCR(第2次)-CCR(第1次)】微秒
所以脉冲填充法不是真要向被测信号内填充脉冲,二是等效的脉冲填充。
这里没有考虑到定时器的溢出!所以理论上能够测得信号的周期为65535微秒。
需要考虑的初始化工作
1.设置BCS模块,确定系统时钟MCLK子系统时钟SMCLK
把MCLK设置为8MHZ,SMCLK设置为1MHZ。
2.捕获输入引脚的选择
选择IO引脚时应查阅器件的手册,能够快速的查阅PDF资料找到正确的答案是一个程序员的基本素质。
由于仿真时不能使用MSP430G2553器件,这给确定捕获输入引脚带来了一定的困难。可以在网上下一个MSP430F2132的资料。这次已把msp430f2132的资料附在压缩包内了,以后需要资料时应该学会自己去下载。
查阅资料后确定P1.3可以做CCI2A信号。
3.程序设计思路
根据测频的原理,需要2次捕获才能测量一次输入信号的频率。因此要定义2个变量保存2次捕获结果。变量是无符号的整数型变量(与捕获寄存器的字长匹配)。
输入信号与CPU的工作是异步的,所以设计程序的时候是不知道什么时候才有捕获输入。程序处理何时发生了捕获的方法有2种
一是查询的方法,定时器硬件在发生捕获事件后会置捕获中断表示CCIF为1,程序在主循环里不断的查询这个标志即可判断是否有捕获事件发生。
二是定时器中断法,当发生捕获事件时必产生定时器中断,在中断中读取捕获寄存器即可。
查询的方法不是好的程序设计方法,因为查询时要占用CPU,使得CPU不能再做其他任务。中断的方法对初学者有一定的困难。即中断程序如何与主程序通信(交换信息)。理解中断及设计中断服务程序要困难一些。程序给出中断的方法和查询的方法,供初学者比较。
定义2个变量
unsigned int capture1,capture2;
unsigned period;
第一次捕获的值放在capture1中,第2次捕获的值放在capture2中。两次捕获的值相减就是被测信号的周期。
开始一步一步的设计程序的源代码
一、系统时钟模块初始化
主时钟MCLK=8Mhz,子系统时钟SMCLK=1Mhz,使用DCO产生CPU的时钟。
时钟初始化程序
void BCSplus_init(void)
{
BCSCTL2 = SELM_0 + DIVM_0 + DIVS_3;//SELM_0选择DCO,DIVM_0,MCLK不分频,DIVS_3,SMCLK 8分频
if (CALBC1_8MHZ != 0xFF) {
DCOCTL = 0x00;
BCSCTL1 = CALBC1_8MHZ; /* 设置 DCO to 8MHz */
DCOCTL = CALDCO_8MHZ;
}
BCSCTL1 |= XT2OFF + DIVA_0; //关闭XT2,ACLK不分频
BCSCTL3 = XT2S_0 + LFXT1S_2 + XCAP_1;//XT2S_0:XT2 0.4~1Mhz,LFXT1S_2:VCLOCK做ACLK,XCAP_1:6pf电容
}
P1口的初始化程序
void gpio_init(void)
{
P1SEL |=BIT3;
P1SEL2 |=BIT3; //P1.3做CCI2A信号,定时器0的捕获输入
}
定时器的初始化程序
void timer0_init(void)
{
TA0CTL |=TASSEL_2+ID_0+MC_2;//选择SMCLK为定时器时钟,不分频,连续计数方式。
TA0CCR2 |=CM_1+CCIS_0+SCS+CAP+CCIE;//上升沿捕获,CCI2A做捕获输入,同步方式,捕获方式,允许捕获中断。
}
中断服务程序
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A1_ISR_HOOK(void)
{
if(TAIV==0x04)//发生的是CCR2捕获
{
capture1=TA0CCR2;//读TA0CCR2
if(capture1>capture2)//数据处理,如果capture1>capture2,则直接减
{
period=capture1-capture2;
}
else //否则
{
period=65536-(capture2-capture1);
}
capture2=capture1; //capture2做前一次的捕获值
}
}
仿真运行时发现LCD不能正常显示,经过单步调试,发现时当程序将P1.3作为捕获输入引脚时,P1.7也做了捕获引脚,P1.7是原LCD的数据线,这时,LCD不能正常工作,星期五的课上,,当将AD转换与PWM输出同时工作时,LCD也不能正常显示,原因也是一样的,这时proteus仿真软件的bug,所以只好把LCD驱动选择为P3out口。
程序需要进一步改进的地方
1.每次capture1-capture2比较麻烦,判断也比较啰嗦。定时器溢出时也不好判断和处理。
改进:在中断服务程序中读取捕获值后,立即让定时器清零,这样就不用做减法了。但是从中断响应开始到定时器清零有一段时间。这个时间可以用软件进行补偿。
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A1_ISR_HOOK(void)
{
if(TAIV==0x04)//发生的是CCR2捕获
{
period=TA0CCR2;//读TA0CCR2
TA0CTL |=TA0CLR;
if(TA0CCTL2&COV)
period +=65536;
}
}
2.提高测量精度
在proteus下进行单步调试,在定时器中断服务程序设置断点,进入中断时观察TAR的值,当程序对TA0清零后经历了几个定时计数周期,将这个周期加到period就能进行补偿。
提高内核的运行速度可以提高精度。