AD9833 Frequenzgenerator mit dem Arduino programmiert und vermessen

Ich habe einen AD9833 Frequenzgenerator mit dem Arduino programmiert. Er kann Frequenzen von 0 bis zu 12,5MHz und die Kurvenformen Sinus, Dreieck und Rechteck ausgeben.

Hier das AD9833 Datenblatt und für die praktische Anwendung die Application Note AN-1070 von Analog Devices.

Er wurde mit dem Arduino Uno programmiert.
Die Anschlüsse sind:
Uno – AD9833
5V  > VCC
GND > GND
D6 > FNC
D7 > DAT
D8 > CLK

Und hier das Arduino Programm:

//AD9833 Frequenzgenerator 0-12.5 MHz Auflösung 1 Hz
//
// Sinus und Dreieck:
// Frequenz 0 - 12.499.999 Hz (Ri ca. 700 Ohm)
// Amplitude ca. 0,6 VSS hochohmig und ca. 0,042 VSS an 50 Ohm
// Ab ca. 1 MHz nimmt die Amplitude ab.
//
// Rechteck:
// Frequenz 0-6.245.000 Hz (Ri ca. 500 Ohm)
// Amplitude ca. 5 VSS hochohmig und ca. 0,45 VSS an 50 Ohm 
// Die Amplitude ist konstant bis hoch zu 6,2 MHz
//
// Matthias Busse 12.4.2018 Version 1.0

#include "Wire.h"

int FSYNC = 6;
int SDATA = 7;
int SCLK = 8;
unsigned long freq;     
byte wave=1;

void setup() {
  pinMode(FSYNC, OUTPUT);
  pinMode(SDATA, OUTPUT);
  pinMode(SCLK, OUTPUT);
  digitalWrite(FSYNC, HIGH);
  digitalWrite(SDATA, LOW);
  digitalWrite(SCLK, HIGH);
  Wire.begin();
  Serial.begin(38400);
  UpdateRegister(0x2100);  // Nach Application Note AN-1070 von Analog Devices
  UpdateRegister(0x50C7);
  UpdateRegister(0x4000);
  UpdateRegister(0xC000);
  UpdateRegister(0x2000);
  freq=1000;
  wave=1;
  UpdateFreq(freq, 0x2000); // Sinus 1000 Hz
}

void loop() {
int ser, len;
char buf[10];

  if (Serial.available() > 0) {
    ser = Serial.read();
    if(ser == 'h') {
      Serial.println("AD9822 Software Version 1.0");
      Serial.println("Help:");
      Serial.println(" s: Sinus     + Frequency 0...12499000 Hz (12.5MHz) Examples: s1000 | s 12345678");
      Serial.println(" t: Triangle  + Frequency 0...12499000 Hz (12.5MHz) Examples: d2000 | d 12400000");
      Serial.println(" r: Rectangle + Frequency 0... 6244000 Hz (6.24MHz) Examples: r3000 | r 123456");
      Serial.println(" g: get frequency");
      Serial.println(" f: get waveform");
      Serial.println(" d: device class");
      Serial.println(" w: who");
      Serial.println(" v: version");
      Serial.println(" 1: min. frequency");
      Serial.println(" 2: max. frequency");
      Serial.println(" 3: frequency step");
    }
    if(ser == 'd') Serial.println("Sythesizer"); // device ?
    if(ser == 'w') Serial.println("AD9833");     // who ?
    if(ser == 'v') Serial.println("1.0");        // version ?
    if(ser == '1') Serial.println("0");          // 0 Hz fmin
    if(ser == '2') Serial.println("12499999");   // 12.5 MHz fmax
    if(ser == '3') Serial.println("1");          // 1 Hz Frequenzschritte
    if(ser == 'f') {                             // Wellenform
      if(wave==1) Serial.println("Sinus");
      if(wave==2) Serial.println("Dreieck");
      if(wave==3) Serial.println("Rechteck");
    }
    if(ser == 'g') Serial.println(freq);         // Frequenz in Hz  
    if(ser == 's') {                             // Sinus ausgeben: s100 | s 10000000
      Serial.setTimeout(15);
      len = Serial.readBytes(buf,12);
      if((len>2) && (len<11)) {                  // s und was dahinter ?
        freq = atof (buf);
        if((freq >= 0.0) && (freq < 12500000.0)) {
          UpdateFreq(freq, 0x2000);           // Sinus
          wave=1;
        }
      }
    }  // Sinus
    if(ser == 't') {                          // Dreieck ausgeben: d100 | d 10000000
      Serial.setTimeout(15);
      len = Serial.readBytes(buf,12);
      if((len>2) && (len<11)) {               // d und was dahinter ?
        freq = atof (buf);
        if((freq >= 0.0) && (freq <= 12500000.0)) {
          UpdateFreq(freq, 0x2002);           // Dreieck
          wave=2;
        }
      }
    } // Dreieck
    if(ser == 'r') {                          // Rechteck ausgeben: r100 | r 10000000
      Serial.setTimeout(15);
      len = Serial.readBytes(buf,12);
      if((len>2) && (len<11)) {               // r und was dahinter ?
        freq = atof (buf);
        if((freq >= 0.0) && (freq <= 6244500.0)) {
          wave=3;
          UpdateFreq(freq, 0x2020);           // Rechteck
        }
      }
    }
  }
}

void UpdateFreq(long freq, int form){
// Die Frequenz Register schreiben.
long FreqReg;
unsigned int MSB, LSB;
   
  FreqReg = (freq * pow(2, 28)) / 25000000; // 25MHz Quarz
  if (form == 0x2020) FreqReg = FreqReg << 1;  // Rechteck 1/2 Frequenz
  MSB = (int)((FreqReg & 0xFFFC000) >> 14);
  LSB = (int)(FreqReg & 0x3FFF);
  LSB |= 0x4000;
  MSB |= 0x4000;
  UpdateRegister(0x2100); // Control Register, Reset Bit DB8 gesetzt
  UpdateRegister(LSB);    // Frequency Register 0 LSB
  UpdateRegister(MSB);    // Frequency Register 0 MSB
  UpdateRegister(0xC000); // Phase Register
  UpdateRegister(form);   // Exit Reset : Wellenform nach dem Reset
}

void UpdateRegister(unsigned int data){
// Ein DDS Register schreiben
unsigned int pointer = 0x8000;

  digitalWrite(FSYNC, LOW);
  for (int i=0; i<16; i++){
    if ((data & pointer) > 0) { 
      digitalWrite(SDATA, HIGH); 
    }
    else { 
      digitalWrite(SDATA, LOW); 
    }
    digitalWrite(SCLK, LOW);
    digitalWrite(SCLK, HIGH);
    pointer = pointer >> 1 ;
  }
  digitalWrite(FSYNC, HIGH);
}

Der Frequenzgenerator lässt sich nun direkt aus einem Terminal Programm am PC über die USB Schnittstelle ansteuern. Die möglichen Funktionen werden mit dem h Kommando ausgegeben. Das sieht dann so aus im Arduino Terminal Programm mit 38400 Baud.

Dadurch lässt sich die Wellenform und Frequenz leicht einstellen und es können die aktuellen Einstellungen abgefragt werden.

Die Rechteck Wellenform kann nur bis ca. 6,24 MHz ausgegeben werden und die Amplitude ist über den gesamten Bereich ziemlich konstant bei 5Vss (Volt Spitze Spitze). Werden Frequenzen über 6,2 MHz übergeben, dann sinkt die Frequenz wieder. Das wurde mit einem Frequenzzähler überprüft. Deshalb ist die Rechteckfrequenz im Programm dort begrenzt.

Die Ausgangsspannung ist beim Sinus und Dreieck ca. 0,6Vss bis 1MHz und bricht dann bei höheren Frequenzen deutlich zusammen. Hier die Messungen dazu und das Diagramm. Einmal hochohmig gemessen und einmal an 50 Ohm gemessen mit dem Oszilloskop.

Die Sinuswelle wird über 3 MHz mit hochohmiger Belastung sehr unsauber und es sind viele Störungen drauf.
Die Dreieckwelle wird hochohmig über 1-2 MHz zu einer Sinus Welle und auch ab 3MHz sehr unsauber.
Nur die Rechteckwelle ist bis 6,24 MHz relativ sauber, wenn auch die Flankensteilheit hier gerade an ihre Grenzen stößt.

Als Zusammenfassung kann man sagen dass dieser Wellenformen Generator gut bis zu ca. 1 MHz einsetzbar ist. Ein hochohmiger Verstärker sollte nachgeschaltet werden.
Bei direktem Anschluß an 50 Ohm bricht sie Ausgangsspannung ordentlich zusammen, was natürlich nicht verwunderlich ist, da der Ausgangswiderstand des A9833 bei ca. 500-700 Ohm liegt. Die Frequenzen werden sehr gut eingehalten, da er Quarzgesteuert ist.

Verwendet wurden:
AD9833 Platine
Arduino Uno
Arduino Software 1.8.0
Frequenzzähler AE20401
Oszilloskop Tektronix 2465A

von Matthias Busse

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site uses Akismet to reduce spam. Learn how your comment data is processed.