Elektronika schodzi pod strzechy, czyli coś, co w niezbyt odległych czasach było szczytem możliwości, dzisiaj zaczyna robić się dostępne dla każdego. Przykładem tego procesu może być układ AD9833 oferowany przez firmę Analog Devices. Wymieniony układ jest generatorem funkcyjnym (generującym sygnał sinusoidalny, trójkątny lub prostokątny) jako układ DDS. Określenie DDS (ang. Direct Digital Synthesis) oznacza bezpośrednią syntezę cyfrową – metodę generowania sygnałów o określonych kształtach bez udziału elementów analogowych w obwodach generatora. Układ jest w pełni sterowany cyfrowo z zewnątrz (przykładowo przez mikrokontroler).
AD9833 jest taktowany sygnałem cyfrowym o maksymalnej częstotliwości 25MHz. W oparciu o ten sygnał zegarowy wytwarzany jest wyjściowy przebieg o zadanym kształcie i zadanej częstotliwości. Stabilność generowanego przebiegu jest uzależniona od stabilności sygnału taktującego układem DDS. Przeciętna stabilność generatorów taktujących wynosi kilkadziesiąt pps, co w wielu amatorskich zastosowaniach jest w pełni wystarczająca.
Przykładowa aplikacja składa się z mikrokontrolera ATMEGA644, który jest użyty do sterowania generatorem (schemat jednostki centralnej pokazuje rysunek 1). Jest to standardowe środowisko obejmujące mikrokontroler oraz niezbędne do jego pracy elementy zewnętrzne jak obwód generatora sygnału taktującego (C102, C103, X101), obwód do generowania sygnału zerującego (D101, R101, P102, C101), przyłącza do zaprogramowania pamięci FLASH mikrokontrolera (P101).
Do mikrokontrolera przyłączony jest standardowy moduł LCD (schemat pokazuje rysunek 2) oraz sam generator DDS (schemat pokazuje rysunek 3).
Aplikacja generatora AD9833 oprócz kilku kondensatorów (C301, C302, C303) wymaga sygnału taktującego (jako sygnał MCLK dla układu U302). Jest on uzyskany ze standardowego generatora sygnału taktującego (U301). Na wyjściu tego generatora wytwarzany jest przebieg fali prostokątnej o częstotliwości 25 MHz. Częstotliwość tego sygnału jest maksymalną dopuszczalną częstotliwością dla układu DDS. Przy takim sygnale taktującym układem DDS możliwe jest generowanie na jego wyjściu sygnałów o częstotliwości od 0 do 12,5 MHZ. Jednak z uwagi na jakość produkowanego sygnału, rzeczywiste możliwości układu są ograniczone do praktycznie 1 MHz (przy większych częstotliwościach dają o sobie znać wyższe harmoniczne a przebieg sinusoidalny staje się zbyt schodkowy). Przy taktowaniu układu DDS sygnałem o częstotliwości 25 MHz możliwe jest uzyskanie rozdzielczości 0.1 Hz, czyli można wytworzyć przykładowo dowolny przebieg sinusoidalny w zakresie od 0 Hz do 1 MHz z dokładnością 0.1 Hz. Zmiana częstotliwości sygnału taktującego na 2.5 MHz pozwala uzyskać rozdzielczość 0.01 Hz. Oczywiście jest to okupione dziesięciokrotnym zmniejszeniem zakresu częstotliwości generowanego sygnału (od 0 Hz do 100 kHz) [w przykładach zastosowany jest generator taktujący o częstotliwości 2,5 MHz].
Do zaprogramowania układu AD9833 używany jest szeregowy interfejs synchroniczny, na który składa się sygnał zegarowy (SCLK), sygnał synchronizacji ramki przesyłanych do układu danych (FSYNC) oraz sygnał danych szeregowych (SDATA). Przebieg sygnałów sterujących pokazuje rysunek 4. Zapis kolejnych bitów danych do układu DDS następuje przy opadającym zboczu sygnału SCLK zaczynając od pozycji najbardziej znaczącej (za każdym razem zapisywanych jest 16 bitów sterujących).
Układ AD9833 ma dwa zestawy rejestrów do zapisu danych określających generowaną częstotliwość (FREQ0 oraz FREQ1) oraz dwa rejestry do zapisu danych określających fazę generowanego sygnału (PHASE0 oraz PHASE1). Znaczenie każdego zapisywanego do układu DDS słowa sterującego jest rozpoznawane po zawartości dwóch najbardziej znaczących bitów w następujący sposób:
Bit 15,Bit 14,Bit 13 - Znaczenie
0 0 x - Słowo sterujące.
0 1 x - Zapis danych określających generowaną częstotliwość do rejestru FREQ0
1 0 x - Zapis danych określających generowaną częstotliwość do rejestru FREQ1
1 1 0 - Zapis danych określających fazę generowanego sygnału do rejestru PHASE0
1 1 1 - Zapis danych określających fazę generowanego sygnału do rejestru PHASE1
Słowo sterujące ma następującą strukturę:
Bit - Nazwa - Znaczenie
Bit 13 - B28 - Aby załadować pełne słowo do jednego z rejestrów częstotliwości, wymagane są dwie operacje zapisu. B28 = 1 umożliwia pełne załadowanie całego słowa do rejestru częstotliwości w dwóch kolejnych zapisach. Pierwszy zapis zawiera 14 LSB słowa częstotliwości, a następny zapis zawiera 14 MSB. Pierwsze dwa bity każdego słowa 16-bitowego definiują rejestr częstotliwości, do którego słowo jest załadowane, a zatem powinny być takie same dla obu kolejnych zapisów. Gdy B28 = 0, 28-bitowy rejestr częstotliwości działa jak dwa rejestry 14-bitowe, jeden zawierający 14 MSB, a drugi zawierający 14 LSB. Oznacza to, że 14 MSB słowa częstotliwości może być zmieniane niezależnie od 14 LSB i vice versa. Aby zmienić 14 MSB lub 14 LSB, zostanie wysłany pojedynczy zapis do odpowiedniego adresu częstotliwości. Bit kontrolny D12 (HLB) informuje AD9833, czy bity mają być zmienione to 14 MSB lub 14 LSB.
Bit 12 - HLB - W przypadku gdy B28 = 0, 28-bitowy rejestr funkcjonalnie jak 14-bitowy, jeden zawierający 14 MSB, drugi zawierający 14 LSB. Bit kontrolny D12 (HLB) informuje AD9833, czy bity mogą być zmienione na 14 MSB lub 14 LSB.
Bit 11 - FSELECT - Bit FSELECT definiuje, czy układ DDS wykorzystuje rejestr FREQ0 lub rejestr FREQ1 do generowania sygnału wyjściowego.
Bit 10 - PSELECT - Bit PSELECT definiuje, czy układ DDS wykorzystuje rejestr PHASE0 lub PHASE1.
Bit 9 - Ten bit powinien być ustawiony na 0.
Bit 8 - RESET - Reset = 1 resetuje wewnętrzne rejestry do 0, co odpowiada wyjściu analogowemu średniej wielkości. Reset = 0 wyłącza reset.
Bit 7 - SLEEP1 - Gdy SLEEP1 = 1, wewnętrzny zegar MCLK jest wyłączony, a wyjście DAC pozostaje w wartości bieżącej.
Bit 6 - SLEEP12 - SLEEP12 = 1 wyłącza procesor DAC. SLEEP12 = 0 oznacza, że DAC jest aktywny.
Bit 5 - OPBITEN - Funkcja tego bitu, w połączeniu z D1 (MODE), polega na sterowaniu tym, co jest przesyłane na wyjściu VOUT. Gdy OPBITEN = 1, wyjście DAC nie jest już dostępne na wyjściu VOUT. Gdy OPBITEN = 0, DAC jest podłączony do VOUT. Bity trybu określają, czy jest dostępny sygnał sinusoidalny lub wyjściowy trójkątny.
Bit 4 - Ten bit powinien być ustawiony na 0.
Bit 3 - DIV2 - DIV2 jest używany w połączeniu z D5 (OPBITEN). Gdy DIV2 = 1, MSB danych DAC jest przekazywany bezpośrednio do wyjścia VOUT. Gdy DIV2 = 0, MSB / 2 danych DAC jest wyprowadzane na wyjściu VOUT.
Bit 2 - Ten bit powinien być ustawiony na 0.
Bit 1 - MODE - Ten bit jest używany w połączeniu z OPBITEN (D5). Funkcja tego bitu polega na sterowaniu tym, co jest przesyłane na wyjście VOUT, gdy wewnętrzny DAC jest podłączony do VOUT. Ten bit powinien być ustawiony na 0, jeśli bit kontrolny OPBITEN = 1. Gdy MODE = 1, ROM SIN jest pomijany, co skutkuje trójkątnym wyjściem z DAC. Gdy MODE = 0, ROM SIN jest używany do przekształcania informacji fazy w informacje o amplitudzie, co powoduje sinusoidalny sygnał na wyjściu.
Bit 0 - Ten bit powinien być ustawiony na 0.
Do określenia wymaganej częstotliwości wygenerowanego sygnału należy do układu DDS wpisać 28-bitową liczbę określającą ta częstotliwość. Te dane sterujące są podzielone na dwa zestawy 14-bitowe określające część bardziej znaczącą oraz mniej znaczącą. Dane te są wpisywane jako dwie operacje zapisu (w sytuacji zapisu obu części 14-bitowych [bit B28=1], w pierwszej kolejności część mniej znacząca oraz w drugiej kolejności część bardziej znacząca). Dane określające fazę generowanego sygnału są 12-bitowe, więc wpis do układu DDS jest realizowany jako pojedyncza operacja zapisu. Nastawy determinujące częstotliwość generowanego sygnału są obliczane w następujący sposób:
Gdzie:
fOUT – częstotliwość na wyjściu układu DDS,
fMCLK – częstotliwość sygnału taktującego
FREQREG – nastawa zapisana w rejestrze.
Łatwo zauważyć, że
gdzie:
Zakładając, że wymagana częstotliwość wyjściowa sygnału z rozdzielczością do 0.01 Hz jest określana jako liczba całkowita (wyrażana w setnych częściach Hz, czyli fOUT=1 oznacza 0.01Hz; fOUT=101 oznacza 1.01Hz), w przykładzie oprogramowania stała ta ma wartość:
Do prezentacji został napisany program (projekt w AVRSTUDIO)
Kod: Zaznacz cały
#ifndef _HardwModule_
#define _HardwModule_
#include <inttypes.h>
#define SquareWaveFormat 0 // generowana jest fala mprostokątna
#define SineWaveFormat 1 // generowana jest fala sin
#define TriangularWaveFormat 2 // generowana jest fala trójkątna
extern void StartDDSWaveGeneration ( uint8_t /* WaveFormat */ ,
uint32_t /* Frequency */ ) ;
extern void StopDDSWaveGeneration ( void ) ;
extern void InitDDSEnvir ( void ) ;
#endif
Kod: Zaznacz cały
#include "ddsmodule.h"
#include <avr/io.h>
#define nop() __asm__ __volatile__ ("nop")
#define DDSPort PORTC
#define DDSDirPort DDRC
#define SDATPin 3 // PC.3
#define SCLKPin 4 // PC.4
#define FSYNCPin 5 // PC.5
#define SetSDATLow DDSPort &= ~ ( 1 << SDATPin )
#define SetSDATHigh DDSPort |= ( 1 << SDATPin )
#define SetSCLKLow DDSPort &= ~ ( 1 << SCLKPin )
#define SetSCLKHigh DDSPort |= ( 1 << SCLKPin )
#define SetFSYNCLow DDSPort &= ~ ( 1 << FSYNCPin )
#define SetFSYNCHigh DDSPort |= ( 1 << FSYNCPin )
#define B28_BitPos 13
#define HLB_BitPos 12
#define FSELECT_BitPos 11
#define PSELECT_BitPos 10
#define Reset_BitPos 8
#define SLEEP1_BitPos 7
#define SLEEP12_BitPos 6
#define OPBITEN_BitPos 5
#define DIV2_BitPos 3
#define Mode_BitPos 1
#define FreqDataRegister 0x4000
#define PhaseDataRegister 0xC000
#define FreqPrescaler 1.073741824
static void SendDDSData ( uint16_t DDSData )
{
uint8_t Loop ;
/*-------------------------------------------------------------------------*/
SetSCLKHigh ;
nop ( ) ;
nop ( ) ;
nop ( ) ;
SetFSYNCLow ;
nop ( ) ;
nop ( ) ;
for ( Loop = 0 ; Loop < 16 ; Loop ++ )
{
if ( DDSData & 0x8000 )
{
SetSDATHigh ;
} /* if ... */
else
{
SetSDATLow ;
} /* if ... else */ ;
SetSCLKLow ;
nop ( ) ;
nop ( ) ;
nop ( ) ;
SetSCLKHigh ;
DDSData = DDSData << 1 ;
} /* for */ ;
SetFSYNCHigh ;
nop ( ) ;
nop ( ) ;
nop ( ) ;
SetSCLKLow ;
} /* SendDDSData */
static void SetControlRegister ( uint8_t B28 ,
uint8_t HLB ,
uint8_t FSELECT ,
uint8_t PSELECT ,
uint8_t Reset ,
uint8_t SLEEP1 ,
uint8_t SLEEP12 ,
uint8_t OPBITEN ,
uint8_t DIV2 ,
uint8_t Mode )
{
uint16_t ControlData ;
/*-------------------------------------------------------------------------*/
ControlData = 0 ;
if ( B28 )
ControlData |= ( 1 << B28_BitPos ) ;
if ( HLB )
ControlData |= ( 1 << HLB_BitPos ) ;
if ( FSELECT )
ControlData |= ( 1 << FSELECT_BitPos ) ;
if ( PSELECT )
ControlData |= ( 1 << PSELECT_BitPos ) ;
if ( Reset )
ControlData |= ( 1 << Reset_BitPos ) ;
if ( SLEEP1 )
ControlData |= ( 1 << SLEEP1_BitPos ) ;
if ( SLEEP12 )
ControlData |= ( 1 << SLEEP12_BitPos ) ;
if ( OPBITEN )
ControlData |= ( 1 << OPBITEN_BitPos ) ;
if ( DIV2 )
ControlData |= ( 1 << DIV2_BitPos ) ;
if ( Mode )
ControlData |= ( 1 << Mode_BitPos ) ;
SendDDSData ( ControlData ) ;
} /* SetControlRegister */
void StartDDSWaveGeneration ( uint8_t WaveFormat ,
uint32_t Frequency )
{
float FrequencyDataFloat ;
uint32_t FrequencyData ;
uint16_t ControlData ;
/*-------------------------------------------------------------------------*/
FrequencyDataFloat = ( float ) Frequency * FreqPrescaler ;
FrequencyData = ( uint32_t ) FrequencyDataFloat ;
SetControlRegister ( 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ) ;
ControlData = FreqDataRegister | ( ( ( uint16_t ) FrequencyData ) & 0x3FFF ) ;
SendDDSData ( ControlData ) ;
ControlData = FreqDataRegister | ( ( ( uint16_t ) ( FrequencyData >> 14 ) ) & 0x3FFF ) ;
SendDDSData ( ControlData ) ;
ControlData = PhaseDataRegister ;
SendDDSData ( ControlData ) ;
switch ( WaveFormat )
{
case SquareWaveFormat :
SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 ) ;
break ;
case SineWaveFormat :
SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
break ;
case TriangularWaveFormat :
SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) ;
break ;
default :
SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
} /* case */ ;
} /* StartDDSWaveGeneration */
void StopDDSWaveGeneration ( void )
{
/*-------------------------------------------------------------------------*/
SetControlRegister ( 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ) ;
} /* StopDDSWaveGeneration */
void InitDDSEnvir ( void )
{
/*-------------------------------------------------------------------------*/
DDSDirPort |= ( 1 << SDATPin ) | ( 1 << SCLKPin ) | ( 1 << FSYNCPin ) ;
SetSDATHigh ;
SetSCLKLow ;
SetFSYNCHigh ;
SetControlRegister ( 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ) ;
} /* InitDDSEnvir */
Kod: Zaznacz cały
/*
Taktowanie procesora : 20MHx
Taktowanie układu DDS: 2.5 MHz (rozdzielczosc 0.01Hz)
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "ddsmodule.h"
#include "lcdmodule.h"
#define SysTimeReq 6
#define TRUE 1
#define FALSE 0
static volatile uint8_t SysTimerTick ;
static volatile uint16_t Timer0IRQCounter ;
static uint8_t HelloText [ ] PROGMEM = "DDS generator" ;
SIGNAL ( TIMER0_OVF_vect )
{
/*-------------------------------------------------------------------------*/
Timer0IRQCounter ++ ;
if ( Timer0IRQCounter >= SysTimeReq )
{
SysTimerTick = TRUE ;
Timer0IRQCounter = 0 ;
} /* if */ ;
} /* TIMER0_OVF_vect */
static void HardwareInit ( void )
{
/*-------------------------------------------------------------------------*/
TIMSK0 = ( 1 << TOIE0 ) ;
TCCR0A = 0 ;
TCCR0B = ( 1 << CS00 ) | ( 1 << CS01 ) ;
} /* HardwareInit */
static void EnvirInit ( void )
{
/*-------------------------------------------------------------------------*/
InitDDSEnvir ( ) ;
InitLCDEnvir ( ) ;
} /* EnvirInit */
static void SoftwareInit ( void )
{
/*-------------------------------------------------------------------------*/
Timer0IRQCounter = 0 ;
SysTimerTick = FALSE ;
} /* SoftwareInit */
static void LongDelay ( void )
{
uint16_t LoopCounter ;
/*-------------------------------------------------------------------------*/
LoopCounter = 0 ;
SysTimerTick = FALSE ;
for ( ; ; )
{
if ( SysTimerTick )
{
SysTimerTick = FALSE ;
LoopCounter ++ ;
if ( LoopCounter > 5000 )
{
break ;
} /* if */ ;
} /* if */ ;
} /* for */ ;
} /* LongDelay */
int main ( void )
{
/*-------------------------------------------------------------------------*/
SoftwareInit ( ) ;
HardwareInit ( ) ;
EnvirInit ( ) ;
sei ( ) ;
StopDDSWaveGeneration ( ) ;
LongDelay ( ) ;
InitialiseLCD ( ) ;
ClrScrLCD ( ) ;
WriteTextLCDFlash ( HelloText ) ;
for ( ; ; )
{
StopDDSWaveGeneration ( ) ;
StartDDSWaveGeneration ( SquareWaveFormat , ( uint32_t ) 100000 ) ;
LongDelay ( ) ;
StopDDSWaveGeneration ( ) ;
StartDDSWaveGeneration ( SineWaveFormat , ( uint32_t ) 100000 ) ;
LongDelay ( ) ;
StopDDSWaveGeneration ( ) ;
StartDDSWaveGeneration ( TriangularWaveFormat , ( uint32_t ) 100000 ) ;
LongDelay ( ) ;
} /* for */ ;
return ( 0 ) ;
} /* main */
Po zaprogramowaniu mikrokontrolera układ DDS generował: