Синтез прямой частоты DDS AD9850 0-40Mhz запуск отладочной платы (HC+SR08) + программа PIC, dsPIC,AVR, STM8, STM32.
Эту отладочную платку можно купить на Ebay.com или Aliaxpress.com. Предлагаю рассмотреть схему подключения и программу. Рассмотреть работу в последовательном и параллельном интерфейсе.
Фото 1. DDS AD9850 0-40Mhz
Привожу схему которую принципе легко найти в интернете, теперь обратим внимание на основные моменты!
Рис 1. Схема платы DDS AD9850
Для параллельного интерфейса нужно использовать линии данных D0 - D7, линии синхронизации W_CLK и обновление памяти FQ_UD. Для задания частоты нужно передать 5 раз по 8 бит через последовательный интерфейс D0 - D7, заканчивается все импульсом на ножку FQ_UD для того, что бы новые данные обновились во внутренней памяти AD9850 и после этого на выходе DDS (PIN 20 и PIN 21) вступит в силу новая частота. Основное преимущество параллельного интерфейса быстрая работа, недостаток большое кол-во ножек управления.
Частота задается по формуле Freq = Frequency * (4294967296/XTAL_MHZ)
Где,
-Freq - это то значение которое нужно загрузить в DDS AD9850 в биты Freq-b0 ... Freq-b0
-Frequency - нужная нам частота в Гц.
-XTAL_MHZ это частота генератора, обычно 125 Mhz (нужно в формулу подставлять 125000000 Гц)
Рис. 2. Диаграмма для параллельного интерфейса AD9850
Для последовательно интерфейса нужно использовать линии данных D7 , линии синхронизации W_CLK и обновление памяти FQ_UD. Если управление DDS AD9850 будет через последовательный порт (SPI) ОБЯЗАТЕЛЬНО НУЖНО ВЫХОДЫ D0 и D1 соединить с VCC(+питание), D2 нужно подключить на землю (-питание). Все начинается с инициализации нужно передать команду b00000011 и подать короткий импульс на FQ_UD. Для задания частоты нужно передать последовательно 40 бит (W0 ... W31), биты W32 и W33 всегда 0, бит W34 в моем случае также 0, Биты W35...W39 для изменения фазы сигнала в моем случает также раны 00000, заканчивается все импульсом на ножке FQ_UD для того, что бы новые данные вступит в силу, новая частота появиться на выходе DDS (PIN 20 и PIN 21).
Фото 2. Подключение платы DDS AD9850 - для последовательного интерфейса
Рис. 3. Диаграмма для последовательного интерфейса AD9850
Пример кода для dsPIC33FJ64GP706, код легко адаптировать под другие микроконтроллеры PIC, dsPIC,AVR, STM8, STM32.
Файл MAIN
#include <xc.h>
#include "CCSPIC_AD9850.h"
#define FCY 40000000UL // определение тактовой частоты для макросов __delay_ms() и __delay_us()
#include <libpic30.h>
_FGS(GWRP_OFF & GCP_OFF);
_FOSCSEL(FNOSC_PRIPLL);
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_XT);
_FWDT(FWDTEN_OFF);
int main(void)
{
/* Configure Oscillator to operate the device at 80MHz dsPIC33FJ64GP706
* Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
* Fosc= 8MHz*40/(2*2)=80Mhz for 8MHz input clock */
PLLFBD=38; // M = PLLDIV + 2, умножить на 40, это биты CLKDIV
CLKDIVbits.PLLPOST=0; // N1=2 Деление входной чаты на 2, (если 1 то на 4)
CLKDIVbits.PLLPRE=0; // N2=2 Деление входной чаты на 2
OSCTUN=0;
__builtin_write_OSCCONH(0x03); /* Initiate Clock Switch to Primary Oscillator with PLL (NOSC=0b011)*/
__builtin_write_OSCCONL(0x01);
while (OSCCONbits.COSC != 0b011); /* Wait for Clock switch to occur */
while(!OSCCONbits.LOCK);
AD9850_Init();
AD9850_Reset();
AD9850_Osc(233000, 0);
while(1)
{
//AD9850_Osc(1234, 0); // Тут меняем частоту в Гц
}
}
Файл *.c
#include <xc.h>
#include "CCSPIC_AD9850.h"
#define FCY 40000000UL // определение тактовой частоты для макросов __delay_ms() и __delay_us()
#include <libpic30.h>
void AD9850_Init(void)
{
/*** Устновкой цифровых и аналоговых выходов */
AD1PCFGL = 0x7FFF; // все выводы цифровые - аналоговый ВНИМАНИЕ ИЗМЕНИ AN15!!
AD1PCFGH = 0xFFFE; // все выводы цифровые, кроме RC1/AN16
AD2PCFGL = 0xFFFF; // все выводы цифровые
CONTROL_DIR &= ~(W_CLK|FQ_UD|DATA|RESET); // настроить на выход
CONTROL_PORT &= ~(W_CLK|FQ_UD|DATA|RESET); // сбросить
}
void AD9850_Reset(void)
{
CONTROL_PORT &= ~DATA; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
CONTROL_PORT |= DATA; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT &= ~DATA; // Ноль
__delay_us(1);
AD9850_Osc(0,0);
}
/* Sets the DDS sine and square oscillator to the detailed "frequency" and "phase" variables.
* "frequency" will be turned into a 32 bit word, so the frequency resolution of 0.0291 Hz
* with a 125 MHz reference clock. "phase" will be a 5 bit word instead so the resolution is
* 11.5 degrees, or pi/32 radians.
*/
void AD9850_Osc(double frequency, double phase){
static int i; // Для циклов
static unsigned long y; // Буфер для передачи
static unsigned long z;
//y = (int)(frequency * FREQ_FACTOR/XTAL_MHZ); // поменял
y = frequency * (FREQ_FACTOR/XTAL_MHZ); // поменял
while(phase>360) phase-=360;
z =(int)phase/11.5; // поменял
//Frequency 32-bit word
for (i=31;i>=0;i--)
{
PORTBbits.RB2 = ((y >> (31-i)) & 0x01); // DATA
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
}
//control bit #1, control bit #2 and Power off, all to low
CONTROL_PORT &= ~DATA; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
//phase 5-bit word
for (i=4;i>=0;i--)
{
PORTBbits.RB2 = ((z >> (4-i)) & 0x01); // DATA
__delay_us(1);
CONTROL_PORT |= W_CLK; // Установить
__delay_us(1);
CONTROL_PORT &= ~W_CLK; // Ноль
__delay_us(1);
}
CONTROL_PORT |= FQ_UD; // Установить
__delay_us(1);
CONTROL_PORT &= ~FQ_UD; // Ноль
__delay_us(1);
}
Файл *.h
#ifndef CCSPIC_AD9850_H
#define CCSPIC_AD9850_H
//Interchangeable pins
#define CONTROL_PORT PORTB
#define CONTROL_DIR TRISB
#define W_CLK (1 << 0) // RB0
#define FQ_UD (1 << 1) // RB1
#define DATA (1 << 2) // RB2
#define RESET (1 << 3) // RB3
//Frequency of your crystal oscillator (CLKIN input pin 9 in datasheet), measured in MHz
// This reference frequency must be higher than 1MHz.
#define XTAL_MHZ 125.00
//Relationship value between actual frequency and 32-bit word sent in the serial streaming
#define FREQ_FACTOR 4294.967295
//function prototypes
void AD9850_Init(void);
void AD9850_Reset(void);
void AD9850_Osc(double frequency, double phase);
void AD9850_Sweep_Up(double minFreq, double maxFreq, double inc, int cyclesPerDelay);
void AD9850_Sweep_Down(double minFreq, double maxFreq, double inc, int cyclesPerDelay);
void AD9850_Sweep_Loop(double minFreq, double maxFreq, double inc, int cyclesPerDelay);
void AD9850_PowerDown(void);
#endif