基于MSP430 Timer_B的D/A转换及C语言源程序
在这个例子中,一个正弦波用32个抽样值生成。正弦波的频率为200Hz,所以每秒要抽样200×32=6400次,也就是说=6.4KHz。每完成一次抽样要计数28,所以所需的时钟频率为。抽样值包含在程序开始的一个正弦表中,通过调用中断函数,在每个PWM周期结束时,将新的正弦波抽样值载入捕获/比较寄存器CCR1中。因此产生的PWM信号的脉冲宽度就决定了正弦波在每一个时刻的抽样值,将这个PWM信号经过低通滤波,即得所需的正弦波。
3.2 直流电平的产生
直流电平产生比较简单,因为它对应的PWM占空比是一定的。直流电平直接正比于PWM信号的占空比。要产生0.5VCC的直流电平,PWM的占空比显然是50%(考虑到损耗,实际应大一些)。只需要简单地将CCR2的值设置为128,并且无须变化就可以得到50%占空比的PWM信号。将得到的PWM信号通过RC网络进行低通滤波,即可得到0.5VCC的直流电平。
3.3 滤波器设计
图4 软件流程
对两路输出都采用了结构简单的RC滤波器,如图3所示。之所以采用这种结构,一是因为RC滤波器结构简单,二是为了实现低功耗,尽量避免采用有源器件。
用于交流信号的滤波器是一个双极点级联RC滤波器。如果滤波器阶数过高,可以采用提高的抽样频率的办法来降低滤波器阶数。滤波器的截至频率fc由下式来计算:
当R2 ? R1时滤波器的响应较好。但是如果截至频率很接近信号带宽边沿,将会导致相当大的衰减。因此为了减小滤波器的衰减,截至频率应该大于信号带宽边沿,但是要远小于PWM信号的频率。
用于产生直流电平的滤波器仅仅是用来储存电荷的,而不像交流信号滤波器那样用来滤波。因此采用了一个简单的单极RC滤波器。
4.程序流程
用MSP430F449的Timer_B的PWM来产生正弦波和直流电平的程序比较简单,流程如图4所示。MSP430F449自身有FLL,可用它来实现DCO的频率校准。但是DCO的频率只能锁定在ACLK的整数倍上,所以对于没有FLL的器件,或者所需频率不是ACLK整数倍的情况下,要用Timer_A或者其它的定时器进行DCO频率校准,这也就是所谓的"软锁频"。事实上实际的D/A转换常常是一些随时间变化的非周期信号。它们对时钟的精度要求不是很高,因此大多数情况下硬件FLL是可以胜任的。
5. 程序清单
MSP430的另外一个特点是用C语言编写程序简单,而且效率较高。本例就采用C语言编写了程序。清单如下:
#include 《msp430x44x.h》
#include 《math.h》
int SampleTimes=0;
//***定义正弦表,并用32个抽样值初始化正弦表,不要用"0"抽样***//
int SinTable[]={255,254,246,234,219,199,177,153,128,103,79,57,37,22,10,2,
1,2,10,22,37,57,79,103,128,153,177,199,219,234,246,255};
void main(void)
{
int i;
WDTCTL = WDTPW +WDTHOLD; // 禁止看门狗定时器
//***初始化端口***//
P2DIR |= 0x0C; // P2.2和P2.3为输出
P2SEL |= 0x0C; // P2.2和P2.3分别为TB1和TB2
//***设置系统时钟***//
FLL_CTL0 = XCAP18PF; // 设置XTAL1的负载电容
SCFQCTL = 50-1; // 1.6384MHz/32768Hz = 50,fDCO=MCLK=1.6384MHz
for (i = 50000; i; i--); // 晶振初始化延时
//***设置Timer_B***//
TBCTL = TBSSEL1 + TBCLR; // 选择SMCLK为时钟,定时器清除
TBCTL|=MC_1+CNTL_0+TBCLGRP_0; //选择up,16位模式
TBCCTL0=CCIE; //将CCR0设为比较模式,中断允许
TBCCR0=256-1; //PWM的周期为256,也就是DAC为8bit
TBCCTL1=OUTMOD_7+CLLD_1; //将CCRx设为比较模式,中断禁止
TBCCTL2=OUTMOD_7+CLLD_1; //选择输出模式7,当TBR计数到0时CCRx数据加载到TBCTLx
TBCCR1=SinTable[SampleTimes]; //将正弦表加载到CCR1
TBCCR2=128; //PWM的占空比为50%,产生0.5VCC的直流电平
_EINT(); //中断允许
for (;;)
{ _BIS_SR(LPM0_bits); //CUP进入低功耗模式
_NOP();
}
}
//调用中断函数
interrupt [TIMERB0_VECTOR] void Timer_B(void)
{
SampleTimes=(SampleTimes+1)%32;
TBCCR1=SinTable[SampleTimes]; //将新的抽样值装入CCR1
}
- 心电模拟波形发生系统的设计(06-15)
- AD转换模拟信号远程监控在实际中的应用(01-28)
- 基于FPGA核心的数字化仪模块设计(06-17)
- 可编程逻辑器件在高准确度A/D转换器中的应用(06-09)
- 一种基于CPLD的16位VFC式AD转换器设计(06-16)
- 一篇很好的AD转换设计中的基本问题整理(05-09)