【问题标题】:need help on AD9833 waveform generator with ATmega32-A micro controller需要关于带有 ATmega32-A 微控制器的 AD9833 波形发生器的帮助
【发布时间】:2012-09-25 21:10:11
【问题描述】:

我正在尝试使用带有 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 进行编程。我遵循与下面的“ross”解释的相同原则。 看来我无法改变正弦波频率。 下面是我正在尝试的代码,我设置了与以前相同的时钟配置。

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 guideAD9833

【问题讨论】:

    标签: c embedded spi texas-instruments


    【解决方案1】:

    当您将频率转换为 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。现在,在数据中使用 OR'ing,如果根据您的频率已经存在数据,结果可能是 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
    

    我认为这会让你到达你想去的地方。

    【讨论】:

    • 非常感谢,现在我明白我做错了什么了。它运作良好。
    • 抱歉再次询问。我有一点怀疑。我在开关盒中调用此函数,因此它运行良好,但问题出在主要功能中,当没有来自超终端的输入但显示低于 50KHz 时,我已将频率设置为 125kHz 可能是什么问题?你能看看我编辑的代码吗?
    • 我看到了编辑,但我不确定问题出在哪里。你还记得在 main() 中设置阶段吗?我会检查您是否忘记配置其他寄存器...否则,我对 unicom() 函数有点困惑。在 WGF 的情况下,为什么总是将命令设置为 0?只有当值小于 500 时才应该这样吗?
    • 非常感谢您的回复。我已经设置了阶段,但我没有在这里发布。是的,如果小于 500,这就是该值。
    • fByte1 = (fByte1 &amp; 0x3F) | 0x40; //clears bits 15 and 14 - 字节超过 8 位??!! fByte2 = (char)(freg&gt;&gt;14); //byte1 only has 6 bits - 评论说 6 位,但所有 8 位都已分配!!??
    【解决方案2】:

    我在您的代码中看到的根本问题是它没有分层。您正试图在一个例程中进行过多的数据操作。您在另一篇文章中读取 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;
    }
    

    此代码允许指定 FREQ0FREQ1 以及 PHASE0PHASE1 寄存器。 *WG_out()* 的源代码看起来很复杂,但实际上可以编译成非常简单的机器代码。

    仍需改进代码

    • 幻数需要替换为#defines。

    • 不需要重写整个控制寄存器,而是需要维护一个状态变量,以便根据需要只修改控制位。那么SetWGPhase()中的fsel参数就可以去掉了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 1970-01-01
      相关资源
      最近更新 更多