1回答

1收藏

MSP430G2231 正弦波发生器(网友作品)

其他 其他 5087 人阅读 | 1 人回复 | 2012-08-23


由于使用到的DA芯片使用的是spi接口的通信,所以着重研究了一下SPI模块。G2系列的串行通信模块即可以配置成SPI的主或从方式,又可以配置成IIC模式,不需要使用软件模拟时序,大大方便了开发。
SPI通信,SPI通信属于同步通信。即发送者和接受者使用同一个时钟,在相同时钟的驱动下工作,与常见的串口通信有所区别。考虑到DA的时序,时钟的频率需要在1Mhz一下,DA在下降沿采集数据,数据线空闲时置低。由于MSP430只需要发送数据,可不需要输入的数据线。
顺着左下角的紫色箭头浏览SPI的时钟线。首先是选择SPI的时钟源。USISELx 寄存器用于选择SPI时钟的来源。可以选择辅助时钟、系统子时钟、定时器模块产生的时钟等。USIDIVx用于选择时钟分频的系数,用于获得需要的时钟频率。USIMST寄存器用于选择430单片机作为SPI的主设备或者从设备。在此设计中430 用作主设备,向外提供时钟。时钟一路向右,为从设备提供时钟,;另一路向左为430的SPI模块提供时钟。寄存器USICKPH 和USICKPL用于选择时钟的相位和决定在上升沿或者下降沿采样。
USISR寄存器由两个8bit寄存器组成,用于存放SPI的收发数据。USICNTx 模块是计数模块,控制要发送的数据的位数。当USISWRST置位的时候,可以时能数据模块和计数模块,spi通信就开始工作了。


   配合DA分析一下SPI寄存器模块的设计。下面是TLV5620的时序图。



每一次模式转换需要11位数据。其中A1,A0 用于选择使用哪个通道。一共有4路DA通道,由于仅用到A通道,前两位为00。



RNG位用于选择倍数,这里最大输出选择的参考电压的一倍,此位设置为0即可。D7,D6,D5,D4,D3,D2,D1,D0为8位数据用于控制输出电压,先发送最高有效位。数据线上一次传送11位数据,因此计数器中存入11,USI16B置高后,数据存储单元最多可以存放16位数据。USILSB用于选择先发送最高有效位。 LOAD这个线需要在11个时钟过后发送一个低脉冲,通知DA更新DA输出。至此,一帧数据完成发送。



橘黄色的线指示中断信号,USICNTx中的数在每一个时钟沿后减一,减到0后触发中断。中断信号送到分频器模块,停止寄存器的输出。当需要再次发送数据的时候,向USICNTx写入传送位数,即可清除中断信号。


程序的流程大体是 1)配置好SPI模块的各个寄存器的数据,使得其能够工作在需要的模式。 2)使能计数器和移位器模块,使得SPI开始工作 3)进入低功耗的模式 4)传送完成后引发中断 5)先装载传送数据,再存入发送数据个数启动下一次的数据传送



作为信号源加入一级跟随器,使得DA的输出具有驱动能力,同时避免负载对输出端口的影响。跟随级后面添加有源或无源的巴特沃斯滤波器,滤除信号以外频率的信号。作为一个练手的东西,就不做了。输出数据可以用matlab生成。





-------------------------------------------------------------    实物图片           -------------------------------------------------------------









该图为使用面包板搭建的电路,可以方便的验证电路。





该图为信号源输出的正弦波




输出波形的FFT变换,可以看到有两个峰值-------------直流成分和正弦波成分。



---------------------------------------------------程序部分-----------------------------------------------------------------------------------

#include<msp430g2231.h>
           #include"source.h"
          #define DAC_UPDATE BIT4
unsigned char i=0;
void update_spi(unsigned char i);
#define debug
#ifdef  debug
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;                     //关闭看门狗
BCSCTL1 = CALBC1_1MHZ;                        // Set range
DCOCTL = CALDCO_1MHZ;                         // Set DCO step + modulation */
P1DIR |= DAC_UPDATE;                          //设置成为输出
P1OUT |= DAC_UPDATE;                          //输出高电平
P1REN |= DAC_UPDATE;                          // 输出口上拉电阻
USICKCTL =USISSEL_2;                          // 16 SMCLK   选择时钟源为SMLK
USICKCTL &=   ~USICKPL;
USICTL0  &=   ~USILSB;                         //清零从高位开始发送
//BCSCTL3 |= LFXT1S_2;                        // ACLK = VLO
USICTL1 &=~(USII2C+USICKPH);                  //关闭I2C模式,下降沿发送数据
USICNT  |= USI16B;                            //允许使用高八位
USICTL1 |= USIIE;                             // Counter interrupt, flag remains set
USICTL0 |= USIPE5 + USIPE6 + USIMST + USIOE;  // USIPE6 SDO打开,输出    USIPE7 SDI打开,输入    USIPE8 SCLK 时钟输出   设置为主模式
USICTL0 &= ~USISWRST;                         // USI released for operation
  _BIS_SR(LPM0_bits + GIE);                   // Enter LPM0 w/ interrupt

while(1)
{
}
}
#pragma vector=USI_VECTOR
__interrupt void universal_serial_interface(void)
{
//USICNT |=USIIFGCC;
  //P1OUT ^= 0x01;                        // Toggle P1.0 using exclusive-OR
  P1DIR |=0x10;//DAC_UPDATE;                    //设置成为输出
  P1OUT   &= ~DAC_UPDATE;
  if(i>=199)i=0;
  else i++;
  update_spi(i);
  //USISRH  =  0x07;
  //USISRL  =  0x54;

  //P1OUT =  0x10;                         // P1.4 set, else reset
  //P1REN |= 0x10;                         // P1.4 pullup
}
void update_spi(unsigned char i)
{
  
   USISRH  =  digital_signal >>3;
   USISRL   = (digital_signal & 0x07)<<5;
   P1OUT   |= DAC_UPDATE;
   USICNT  |= 0x0B;                         // re-load counter
}
#endif
#ifndef  debug
void main()
{
WDTCTL = WDTPW + WDTHOLD;                     //关闭看门狗
P1DIR |=0x10;//DAC_UPDATE;                    //设置成为输出
P1OUT |=0x10;//DAC_UPDATE;                    //输出高电平
while(1);
}
#endif


分享到:
回复

使用道具 举报

回答|共 1 个

倒序浏览

沙发

fengye5340-272571

发表于 2012-8-29 19:21:58 | 只看该作者

好资料,顶一下!
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条