0

我正在尝试使用带有 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; 
   }
 }

我附上了我为这个控制器和 AD9833 编程而休憩的 SPI 指南。SPI指南 AD9833

4

2 回答 2

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。现在,在数据中进行 OR'ing 时,如果根据您的频率已经存在数据,则结果可能为 0xC0。

作为一个小提示,我认为在分配 to 时没有理由使用掩码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

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

于 2012-09-25T22:31:48.370 回答
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;
}

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

仍然需要代码改进

  • 幻数需要替换为#defines。

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

于 2012-10-03T00:27:00.217 回答