需要帮助AD9833波形发生器与ATmega32-A微控制器

时间:2012-09-25 21:10:11

标签: c embedded spi texas-instruments

我正在尝试使用带有ATmega32-A微控制器的可编程波形发生器AD9833生成正弦波(MCLK = 8MHz时钟频率)。我正在使用USART通信,所以如果我改变超级终端的频率,那么波形频率必须改变。 我为此编写了一些小代码,如下所示。

但是从上面的代码我生成正弦波,但如果我想将信号频率改为125KHz,那么我必须在超高频输入499.9KHz。如果输入125KHz则显示31.2KHz。我不知道为什么会产生这样的错误,我做了什么错误?并且它正在改变波形,直到500KHz频率假设我输入大约1000KHz的波形频率但信号频率没有变化它只显示125KHz。

最后我想生成不同频率的波形。如果我在超级终端或腻子处改变频率,那么我输入的频率必须生成具有该频率的波形。

这是我的第一篇文章,如果有任何语法错误,那么请原谅。

提前致谢。

     void unicom(void){

         switch(Command){


                case(WGF):
            if(Param < 500)
                SetWGFreq(Param);   
                Command = 0;
            break; 

               case....
               case....
               default:
             }

  void main(void){
  SetWGFreq(125);
  -----------
   --------
   }

再一次,

这次我尝试通过SPI用SM470R1B1M-HT微控制器编程AD9833。我正在遵循下面“罗斯”所解释的相同原则。 看来我无法改变正弦波频率。 下面是我正在尝试的代码,我使用时钟设置相同的配置。

void SetupSPI(void);
unsigned char spi(unsigned char data);
void SetWGFreq(unsigned int);
void setFrequencyA(unsigned long fdata);
void WG_CS_Status(int status);

int main(void)
{
GCR &= ~ZPLL_MULT4; 
GCR &= ~ZPLL_CLK_DIV_PRE1; 
GCR &= ~ZPLL_CLK_DIV_PRE2;
GCR &= ~ZPLL_CLK_DIV_PRE3;   

PCR = CLKDIV_1;                         // ICLK = SYSCLK 
PCR |= PENABLE;                         // Enable peripherals

GIODIRA |= X7;

CLKCNTL |= CLKDIR | CLKSR_ICLK;

SetupSPI();

for(;;)
{
  //SetWGFreq(25);
  setFrequencyA(1045200);
}                             // Wait in endless loop
}

void SetupSPI(void)
{
int data = 0;

 SPI2CTRL1 = CHARLEN_8 + PRESCALE_4;                // 8 bits per xfer
 SPI2CTRL2 |= CLKMOD + MASTER + POLARITY;             // We are the master
 SPI2PC6 |= SOMI_FUN | SIMO_FUN | CLK_FUN;
 // SPI2PC6 |=   0x0E;
 // enable
 SPI2CTRL2 |= SPIEN;

 data = SPI2BUF;
}

unsigned char spi(unsigned char data)
 {
    SPI2DAT1 = data;             
    while(!(SPI2CTRL3 & 0x01)){}        // Wait for RxFlag to get set    
    return (SPI2BUF & 0x000000FF);      // Read SPIBUF 
 } 

void setFrequencyA(unsigned long fdata)
 {
 WG_CS_Status(0);
 while(GIODOUTA&X7);   // Delay
 spi(0x20);      // Initiate loading of frequence register 0 by 28 bits.
 spi(0x00);
 spi(( 0x40 | (0x3F & (fdata >> 8))));   // load bit 8-13 + 0x40.
 spi(fdata);                             // load bit 0-7
 spi(( 0x40 | (0x3F & (fdata >> 22))));  // load bit 22-27 + 0x40.
 spi(fdata >> 14);                       // load bit 14-21
 spi(0);   // dummy write
 WG_CS_Status(1);
}
void WG_CS_Status(int status)
 {    
 if(status == 0)
  {
     // Make Chip Select low
     GIODOUTA &= ~X7;
  }
 else
  {
     // Make Chip select high
     GIODOUTA |= X7; 
   }
 }

我正在为此控制器附加SPI指南,而不是AD9833编程。SPI guide AD9833

2 个答案:

答案 0 :(得分:2)

当您将频率转换为AD9833需要的两个14位数字块时,您在频率寄存器的D14和D15中进行“或”操作。那里有两个问题。

第一个问题是你的freg值丢失了4位(2位)。

76543210 76543210 76543210 76543210
LL000000 00000000 LL000000 00000000 //The L's are lost because they're overwritten by the addressing.

第二个问题是你需要第15位和第14位正好是0x40。现在,如果根据您的频率数据已经存在,那么在数据中进行“或”运算可能会得到0xC0。

作为次要注释,我认为在分配给fByte0-3时没有理由使用蒙版,因为您正在使用作为作业。

因此,结合两个修正并简化蒙版可以得到:

fByte0 = (char)freg;
fByte1 = (char)(freg>>8);
fByte1 = (fByte1 & 0x3F) | 0x40; //clears bits 15 and 14, then sets for FREQ0
fByte2 = (char)(freg>>14);  //byte1 only has 6 bits, so move over by 8+6
fByte3 = (char)(freg>>22);  //byte1 only has 6 bits, so move over by 8+8+6
fByte3 = (fByte3 & 0x3F) | 0x40; //clears bits 15 and 14, then sets for FREQ0

我认为这会让你到达目的地。

答案 1 :(得分:0)

我在您的代码中看到的基本问题是它不是分层。您试图在一个例程中进行过多的数据操作。您在另一篇文章中读取ADC值的代码是分层的,这就是您应该为此设备做的事情。

AD9833波形发生器基本上是一个16位器件。它需要编程的三种类型的寄存器都是16位。它只是8位的数据传输(使用SPI)。因此,只有实际的输出语句(使用 spi())需要处理字节(就像您的ADC输入例程立即将读取的字节转换为短整数一样)。为发生器计算的值应为16位值。然后,您应该能够看到代码如何在生成器的数据表中实现数据要求。

void WG_out(unsigned short rval)
{
    /* assume little-endian CPU but AD9833 wants high byte first */
    spi(*((unsigned char *)&rval + 1));
    spi(*(unsigned char *)&rval);
}

void SetWGFreq(int fsel, unsigned int freq)
{
    unsigned short freg_addr;
    unsigned short freq_reghi;
    unsigned short freq_reglo;
    unsigned short cntl_reg;

    SPCR = 0x5A;         /* set SPI to mode 2 and Fosc/64 */
    WG_CS = 0;

    freg_addr = (fsel > 0) ? 0x8000 : 0x4000;
    /* split the f value into two 14-bit values */
    freq *= 33554.432;   /* number based on a MCLK of 8 MHz */
    freq_reghi = freg_addr | ((freq >> 14) & 0x00003fff);
    freq_reglo = freg_addr | (freq & 0x00003fff);

    cntl_reg = (1 << 13) | (fsel > 0) ? (1 << 11) : 0;
    while (WG_CS_PIN)   /* wait for chip select to go low */
        /* DELAY */ ;   
    WG_out(cntl_reg);   /* set B28 in Control */
    WG_out(freq_reglo); /* 14 LSB goes first */
    WG_out(freq_reghi); /* 14 MSB goes next */
    WG_CS = 1;
}

void SetWGPhase(int fsel, int psel, unsigned int phase)
{
    unsigned short cntl_reg;
    unsigned short phase_reg;

    SPCR = 0x5A;
    WG_CS = 0;
    cntl_reg = (1 << 13) | (fsel > 0) ? (1 << 11) : 0 | (psel > 0) ? (1 << 10) : 0;
    phase *= 1303;      /* 4096 / 2pi radians */ 
    phase_reg = 0xc000 | (psel > 0) ? (1 << 13) : 0 | (phase & 0x0fff);
    while (WG_CS_PIN)   /* wait for chip select to go low */
        /* DELAY */ ;   
    WG_out(cntl_reg);   /* set B28 in Control */
    WG_out(phase_reg);
    WG_CS = 1;
}

此代码允许指定 FREQ0 FREQ1 以及 PHASE0 PHASE1 寄存器。 * WG_out()*的源代码看起来很复杂,但它实际上编译为非常简单的机器代码。

仍然需要代码改进

  • 幻数需要替换为#define s。

  • 不需要重写完整的控制寄存器,而是需要维护状态变量,以便只根据需要修改控制位。然后可以消除 SetWGPhase()中的 fsel 参数。