нужна помощь по генератору сигналов AD9833 с микроконтроллером ATmega32-A

Я пытаюсь генерировать синусоиду, используя программируемый генератор сигналов AD9833 с микроконтроллером ATmega32-A (тактовая частота MCLK = 8 МГц). Я использую связь USART, поэтому, если я изменяю частоту в гипертерминале, частота сигнала должна измениться. Я написал для этого небольшой код, как показано ниже.

но из приведенного выше кода я генерирую синусоидальную волну, но если я хочу изменить частоту сигнала на 125 кГц, мне нужно ввести 499,9 кГц в гипертерминале. Если я введу 125 кГц, то он показывает 31,2 кГц. Я не знаю, почему он так генерируется и какую ошибку я сделал? а также он изменяет форму волны до частоты 500 кГц. Предположим, если я ввожу частоту формы волны около 1000 кГц, но частота сигнала не меняется, он показывает только 125 кГц.

наконец, я хочу генерировать форму волны с разной частотой. Если я изменяю частоту в гипертерминале или замазке, то любая частота, которую я ввожу, должна генерировать форму волны с этой частотой.

Это мой первый пост, так что если есть грамматические ошибки, прошу меня извинить.

Заранее спасибо.

     void unicom(void){

         switch(Command){


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

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

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

Привет еще раз,

На этот раз я пытаюсь запрограммировать AD9833 с микроконтроллером SM470R1B1M-HT через SPI. Я следую тому же принципу, что и «росс» ниже. Кажется, я не могу изменить частоту синусоиды. Ниже приведен код, который я пытаюсь использовать, я установил ту же конфигурацию с часами, что и раньше.

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. /a> AD9833


person verendra    schedule 25.09.2012    source источник


Ответы (2)


Когда вы преобразовываете частоту в два блока 14-битных чисел, которые нужны AD9833, вы выполняете операцию ИЛИ в D14 и D15 регистра частоты. Есть две проблемы.

Первая проблема заключается в том, что вы теряете 4 бита (2 бита времени) вашего значения freg.

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

Я думаю, это приведет вас туда, где вы хотите быть.

person Ross    schedule 25.09.2012
comment
Большое спасибо, теперь я понимаю, какую ошибку я сделал. это работает хорошо. - person verendra; 27.09.2012
comment
Извините, что спрашиваю еще раз. У меня есть небольшое сомнение. Я вызываю эту функцию в случае переключателя, поэтому она работает хорошо, но проблема заключается в основной функции. Я установил частоту на 125 кГц, когда от гипертерминала не было входных данных, но он показывает менее 50 кГц, в чем может быть проблема? Вы можете взглянуть на мой отредактированный код. - person verendra; 28.09.2012
comment
Я вижу изменения, но я не уверен, в чем проблема. Вы не забыли также настроить фазу в main()? Я бы проверил, есть ли другие регистры, которые вы забыли настроить... В противном случае я немного смущен функцией unicom(). В случае с WGF, почему вы всегда устанавливаете команду на 0? Это должно было быть только в том случае, если значение было меньше 500? - person Ross; 28.09.2012
comment
Большое спасибо за ответ. Я настроил фазу, но не разместил ее здесь. да, это значение, если меньше 500. - person verendra; 29.09.2012
comment
fByte1 = (fByte1 & 0x3F) | 0x40; //clears bits 15 and 14 - Байты имеют длину более 8 бит??!! fByte2 = (char)(freg>>14); //byte1 only has 6 bits - В комментарии указано 6 бит, но назначены все 8 бит!!?? - person sawdust; 01.10.2012
comment
@sawdust Даже фаза также не меняется, как и то, что я ввел. но вроде хорошо. потому что сдвиг влево с 8 битами и выполнение операции И с этим, но не работает. можете ли вы предложить мне. - person verendra; 02.10.2012
comment
@Ross Четная фаза также не меняется, как и то, что я ввел. но вроде хорошо. потому что сдвиг влево с 8 битами и выполнение операции И с этим, но не работает. Вы можете мне помочь. Я новичок в программировании микроконтроллеров. - person verendra; 02.10.2012
comment
@Ross Можете ли вы помочь мне с последним кодом, я следую вашей процедуре, но не смог добиться успеха. - person verendra; 03.07.2015

Фундаментальная проблема, которую я вижу в вашем коде, заключается в том, что он не многоуровневый. Вы пытаетесь выполнить слишком много манипуляций с данными в одной процедуре. Ваш код для чтения значений АЦП в другом посте многоуровневый, и это то, что вы должны делать для этого устройства.

Генератор сигналов AD9833 представляет собой 16-разрядное устройство. Его три типа регистров, которые вам нужно запрограммировать, все 16-битные. Только передача данных (с использованием SPI) составляет 8 бит. Таким образом, только фактические операторы вывода (с использованием 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()* выглядит сложным, но на самом деле он компилируется в очень простой машинный код.

Необходимы улучшения кода

  • Магические числа необходимо заменить на #defines.

  • Вместо перезаписи всего управляющего регистра необходимо поддерживать переменную состояния, чтобы при необходимости изменялись только управляющие биты. Затем аргумент fsel в SetWGPhase() можно исключить.

person sawdust    schedule 03.10.2012