0

プログラム可能な波形発生器 AD9833 と ATmega32-A マイクロ コントローラー (MCLK = 8MHz クロック周波数) を使用して正弦波を生成しようとしています。私は USART 通信を使用しているので、ハイパー ターミナルで周波数を変更すると、波形の周波数を変更する必要があります。以下に示すように、このための小さなコードを書きました。

しかし、上記のコードから正弦波を生成していますが、信号の周波数を 125KHz に変更したい場合は、ハイパーターミナルで 499.9KHz を入力する必要があります。125 KHz を入力すると、31.2KHz が表示されます。なぜそのように生成されているのか、どのような間違いを犯したのかわかりません。また、1000KHz 付近の波形の周波数を入力すると、周波数が 500KHz まで波形が変化しますが、信号の周波数に変化はなく、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; 
   }
 }

このコントローラーと AD9833 のプログラミングに使用していない SPI ガイドを添付します。SPI ガイド AD9833

4

2 に答える 2

2

周波数を AD9833 が必要とする 14 ビット数の 2 つのブロックに変換する場合、周波数レジスタの D14 と D15 で論理和をとっています。そこには2つの問題があります。

最初の問題は、freg 値の 4 ビット (一度に 2 ビット) を失っていることです。

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

2 つ目の問題は、ビット 15 と 14 を正確に 0x40 にする必要があることです。現在、データの OR を使用すると、周波数に基づいてデータが既に存在していた場合、結果は 0xC0 になる可能性があります。

マイナーな注意として、割り当てとして使用しているため、に割り当てるときにマスクを使用する理由はわかりませんfByte0-3

したがって、2 つの修正を組み合わせてマスクを単純化すると、次のようになります。

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

あなたのコードで私が目にする根本的な問題は、レイヤー化されていないことです。1 つのルーチンで大量のデータ操作を行おうとしています。別の投稿で ADC 値を読み取るためのコードは階層化されており、それがこのデバイスに対して行うべきことです。

AD9833 波形発生器は、基本的に 16 ビット デバイスです。プログラムする必要がある 3 種類のレジスタはすべて 16 ビットです。8ビットなのはデータ転送(SPIを使用)のみです。したがって、実際の出力ステートメント ( spi()を使用) のみがバイトを処理する必要があります (ADC 入力ルーチンが読み取ったバイトをすぐに short 整数に変換するように)。ジェネレータ用に計算された値は、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()* のソース コードは複雑に見えますが、実際には非常に単純なマシン コードにコンパイルされます。

コードの改善がまだ必要

  • マジック ナンバーは s に置き換える必要があります#define

  • 完全な制御レジスタを書き換える代わりに、必要に応じて制御ビットのみが変更されるように状態変数を維持する必要があります。次に、SetWGPhase()のfsel引数を削除できます。

于 2012-10-03T00:27:00.217 に答える