DDS AD9850 von 0 – 40 MHz mit ATtiny45          

von Gerd Sinning                      
Elektronik-Labor   Projekte   AVR 



Einen Sinusgenerator von 0-40 MHz kann man vielseitig einsetzen, um z.B. die Stereoanlage zu testen oder um einen VFO für ein Kurzwellenradio zu bauen. Dazu ist ein quarzstabiler DDS Sinusgenerator gut geeignet.

DDS Module mit dem AD9850 sind inzwischen z.B. auf ebay einfach zu erhalten, güstiger als der chip einzeln. Der AD9850 ist auf ein break-out board mit zwei Stiftleisten im 2,54 mm Raster aufgelötet, so daß man das gut in eigenen Schaltungen verwenden kann. Damit kann man nun einen Frequenzgenerator bis ca. 40 Mhz mit einer Auflösung von 0,03492 Hz bauen. Auf dem board ist ein 125 MHz Quarz und ein Tiefpassfilter für den Sinusausgang, gleichzeitig gibt es auch ein Rechtecksignal für digitale Schaltungen. Die Programmierung der Frequenz ist etweder parallel mit D0-D7 oder seriell, was hier verwendet wird. Das serielle Format ist W0 W1 W2 W3 W4 W5 ... W28 W29 W30 W31 0 0 0 0 0 0 0 0, die letzten 8 Nullen sind das command byte, darin sind 2 control bits (auf 0 lassen), ein powerdown bit (auch auf 0 lassen) und 5 phase bits, die bleiben hier auch mal auf Null. Die Frequenz hat 32 bits, W0 ist LSB und W31 ist MSB. W0 wird zuerst gesendet. Die Programmierung wird berechnet mit Freq_data = Frequenz * 4 294 967 296 / 125 000 000 und dann gesendet mit Shiftout Wdat , Wclk , Freq_data , 3 , 32 , 0 und dann noch das command byte mit Shiftout Wdat , Wclk , Dds_cmd , 3 , 8 , 0. Übernommen wird das durch das Latch Signal: Set Fqud, Waitus 10, Reset Fqud.

Kalibrieren kann man den DDS auch wenn man will und der Quarz nicht exakt auf 125 MHz schwingt. Dazu braucht man einen Kurzwellenempfänger, der auf 10 MHz die standard NIST radio station WWV, Time and Frequency Division, empfangen kann. Man stellt den DDS z.B. auf 1 MHz und die 10. Oberwelle erzeugt zusammen mit dem WWV Standardsignal eine Schwebungsfrequenz im Empfänger. Die soll möglichst niedrig sein, Null ist ideal. Dazu wird Const Clk_in = 125000000 solange verändert bis der DDS Generator kalibriert ist.

Das Ziel war es hier, eine möglichst kleine Einheit aufzubauen, weil schon viel auf dem Tisch steht, aber es soll auch gut zu bedienen sein. Also braucht man eine Zehnertastatur für die Frequenzeingabe und einige Funktionstasten. Die Tastatur passt nun nicht in so ein kleines Gehäuse, also wird sie nach aussen verlagert in eine RC5 Infrarot-Fernbedienung, die hat schon alles was man braucht, man muss nur noch eine finden.




Das DDS Modul, pins oben und unten, und das Schaltbild:

Vcc D0 D1 D2 D3 D4 D5 D6 D7 GND
Vcc CLK Latch DATA RST GND SQW SQW SinA SinB
Vcc is +5V @ 125MHz Clock
D0 - D7 = Parallel programming bits
GND = Ground
CLK = Serial programming clock
Latch = Serial programming latch (FQ_UD pin on 9850)
DATA = Serial programming DATA (internally tied to D7)
RST = Reset. Keep tied to GND
SQW = Square wave outputs (complementary) Duty cycle adjustable with blue pot.
SINA = Raw unfiltered AD9850 sine output
SINB = 70 MHz LPF filtered AD9850 output.

Ein Attiny45 reicht schon, um das Modul anzusteuern. Die Infrarotsignale von der Fernbedienung werden von einem IR TSOP an PB3 empfangen und im Programm dekodiert. Die Dekodierung im Programm muss man an die eigene Fernbedienung anpassen, dabei hilft 'Print #1 , " A:" ; Address ; " C:" ; Command ; " T:" ; Tog, mit den seriellen Daten an PB4, damit man am PC sieht, welcher Befehl auf welcher Taste liegt. Das muss man dann in Select Case Command entsprechend modifizieren. Die Verbindung zum DDS Modul braucht 3 Leitungen ' Portb.2 = WCLK ' Portb.1 = FQUD' und Portb.0 = DATA


Das Schaltbild, der IR Empfänger ist an PB3 und die serielle Schnittstelle (zum Test der Kommandos von der Fernbedienung) an PB4


So lässt sich das in ein kleines Gehäuse einbauen, der IR Empfänger wird unter ein Loch im Deckel geklebt. An der Buchse links oben ist das regelbare Sinussignal vom Verstärker mit den BF199, in der Mitte links das Rechtecksignal und unten SINA direkt, rechts oben ist die Buchse für RS232 und die externe Spannungsversorgung. Hier braucht man 5V und je nach Frequenz zwischen 70 und 120 mA, je höher die Frequenz desto mehr Strom. Der Verstärker liefert maximal 3,1 V pp oder 1 V RMS über den Frequenzbereich, der ist mit Const F_max = 40000000 auf 40 MHz begrenzt.

Das Basic-Programm wartet auf die Eingabe der Frequenz in Hz auf der Zehnertastatur der Fernbedienung und mit Case 38 (hier) wird die übernommen und programmiert. Es gibt auch eine Schrittweite für Frequenzänderungen: F_step = 1000 Hz ist default aber kann man ändern, mit Eingabe und Case 34 wird die Schrittweite übernommen. Die Tasten Case 32 und Case 33 erhöhen oder erniedrigen die Frequenz dann um die Schrittweite F_step. Wenn man die Taste gedrückt hält, dann wirkt das wie ein Scan. Ein einfacher Scan oder Sweep ist aber auch noch eingebaut. Taste Case 16 schaltet ihn ein und es gibt 100 Schritte (For I = 1 To 100) mit F_step, ausgehend von der bisherigen Frequenz, bei der höchsten Frequenz bleibt der DDS dann stehen, noch mal auf Scan drücken und er beginnt erneut bei der alten Frequenz und läuft hoch. Das geht recht schnell, mit 3,8 ms pro Schritt. Langsamer wird es, wenn man die serielle Ausgabe einschaltet, mit Case 15, dann braucht jeder Schritt 125 ms.

Insgesamt ist es recht bequem, den DDS Generator über eine Fernbedienung zu steuern. Wie am heimischen Fernseher nur ohne Bild.


References

datasheet ATtiny45, Atmel.com
http://www.pongrance.com/DDS-9850.html
http://www.kh-gps.de/dds.htm

Download: DDS45IR.zi

' AT45 controller for DDS AD9850 on china break-out board
'
' with RC5 remote control for DDS module frequency
' incl. frequency scan or sweep 100 steps up
'
' DDS on Portb 0 1 2
' Portb.2 = WCLK
' Portb.1 = FQUD
' Portb.0 = DATA
' Portb.4 = serial out
' Portb.3 = IR RC5 input
' GS 2015/2
'
'***************************************************************************
' This program is free software; you can redistribute it and/or
' modify it under the terms of the GNU General Public License.
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY;
'***************************************************************************
'
' ATtiny45 dip
' (PCINT5/RESET/ADC0/dW) PB5 VCC
' (PCINT3/XTAL1/CLKI/OC1B/ADC3) PB3 PB2 (SCK/USCK/SCL/ADC1/T0/INT0/PCINT2)
' (PCINT4/XTAL2/CLKO/OC1B/ADC2) PB4 PB1 (MISO/DO/AIN1/OC0B/OC1A/PCINT1)
' GND PB0 (MOSI/DI/SDA/AIN0/OC0A/OC1A/AREF/PCINT0)
'
';***************************************************************************
' PB0 output DATA
' PB1 output FQUD
' PB2 output WCLK
' PB4 output Com1
' PB3 input IR RC5
'***************************************************************************

$regfile = "attiny45.dat"
$crystal = 1000000
'$crystal = 8000000
$hwstack = 8
$swstack = 8
$framesize = 4


Wdat Alias Portb.0 'AD9850 Wdat output
Fqud Alias Portb.1 'AD9850 FQUD output
Wclk Alias Portb.2 'AD9850 SCLK output

Const Clk_in = 125000000
Const Multi = &H100000000
Const F_max = 40000000 ' 40 MHz

Dim Address As Byte , Command As Byte , Tog As Byte
Dim T0 As Byte , T1 As Byte , N As Byte , Dds_cmd As Byte
Dim Flagscan As Byte , Flagrs232 As Byte , I As Byte
Dim Instring As String * 12
Dim Freq_data As Long , Freq_in As Long
Dim F_in1 As Single , F_in2 As Single
Dim F_inold As Single , F_step As Single
Dim Freq_accu As Single

Portb = &B00001000
Ddrb = &B00010111

'CLKPR = &B10000000 'Clock Prescaler Change Enable
'CLKPR = &B00000000 'Clock Division Factor=0, 8 MHz

Config Rc5 = Pinb.3

Acsr.acd = 0 ' switch off analog comparator

Open "comb.4:9600,8,n,1,INVERTED" For Output As #1

Instring = "" 'blank
F_in1 = 100000 '100 KHz
F_in2 = 120000 '120 KHz
F_inold = 100000 '100 KHz
F_step = 1000
Freq_in = 100000
Flagscan = 0
Flagrs232 = 0

Dds_cmd = &B00000000

Gosub Init_dds
Waitms 100
Gosub Dds_output

Print #1 , "Wait for RC5"
Enable Interrupts

Do
Getrc5(address , Command)
If Address < 255 Then
'the toggle bit toggles on each new received command
'toggle bit is bit 7. Extended RC5 bit is in bit 6
Tog = Command And &B10000000
Command = Command And &B01111111 'clear the toggle bit

'Disable Interrupts
'Print #1 , " A:" ; Address ; " C:" ; Command ; " T:" ; Tog
'Enable Interrupts
T0 = Tog
If Command <= 9 And T0 <> T1 Then
N = Command + 48 'make ascii number
Instring = Instring + Chr(n)
T1 = T0 'store numbers
Else
T1 = T0
End If

Select Case Command
Case 38 : 'set F1
Freq_in = F_in1
Gosub Chkvalid
F_in1 = Freq_in
Case 30 : 'set F2
Freq_in = F_in2
Gosub Chkvalid
F_in2 = Freq_in
Case 34 :
Freq_in = F_step 'set F_step
Gosub Chkvalid
F_step = Freq_in
Case 16 :
Flagscan = 1 'start scan

Case 17 :
Flagscan = 0 'stop scan

Case 15 :
Flagrs232 = 1 'start RS232 output

Case 12 :
Flagrs232 = 0 'stop RS232

Case 32 : ' + Command
F_in1 = F_in1 + F_step
If F_in1 > F_max Then
F_in1 = F_max
End If
Gosub Chkvalid
Case 33 : ' - Command
F_in1 = F_in1 - F_step
If F_in1 < 0 Then
F_in1 = 0
End If
Gosub Chkvalid
End Select

Disable Interrupts
Enable Interrupts

End If 'If Address < 255

If Flagscan = 1 Then 'scan
F_inold = F_in1
For I = 1 To 100
F_in2 = I * F_step
F_in1 = F_inold + F_in2
Gosub Dds_output 'and send to DDS
Waitms 1
Next
Flagscan = 0
F_in1 = F_inold
Else 'no scan
If F_in1 <> F_inold Then 'only send changes
Gosub Dds_output 'and send to DDS
F_inold = F_in1
End If 'If F_in1 <> F_in1old
End If 'If Flagscan = 1


Loop

'***************************************************************************
' check length of string
'***************************************************************************
Chkvalid:

If Len(instring) >= 1 And Len(instring) <= 8 Then
Freq_in = Val(instring)
End If

Instring = "" '' '';
T1 = T0
Return

'***************************************************************************
' Init_dds
'***************************************************************************
Init_dds:

Reset Wdat 'DATA '
Reset Wclk 'WCLK
Waitus 10
Set Wclk 'WCLK
Waitus 10
Reset Wclk 'WCLK
Waitus 10
Set Fqud 'FQUD
Waitus 10
Reset Fqud 'FQUD
Waitus 10
Return

'***************************************************************************
' Dds_output
'***************************************************************************
Dds_output:

Disable Interrupts

Freq_accu = F_in1 * Multi 'calculate
Freq_accu = Freq_accu / Clk_in
Freq_data = Freq_accu

Shiftout Wdat , Wclk , Freq_data , 3 , 32 , 0 'DATA,WCLK
Shiftout Wdat , Wclk , Dds_cmd , 3 , 8 , 0 'DATA,WCLK
Waitus 10
Set Fqud 'FQUD
Waitus 10
Reset Fqud 'FQUD

If Flagrs232 = 1 Then 'debug print
Print #1 , " Cmd:" ; Command ; " In:" ; Instring
Print #1 , " F_in1:" ; F_in1 ; " F_in2:" ; F_in2 ; " F_st:" ; F_step
Print #1 , " F_old:" ; F_inold ; " F_in:" ; Freq_in
End If

Enable Interrupts
Return

End
                              


 Elektronik-Labor   Projekte   AVR