Проблема с DDS AD9850

Darth_Vader
Offline
Зарегистрирован: 12.10.2013

Добрый день!

Проблема с DDS на AD9850 (синяя плата HC-RS08, только что приехала с Китая).

Не могу добиться работы DDS. На выходе ZOUT1 (да и на других) ничего нет. Проверял включением осциллографа между ZOUT1 и GND.

Брак в плате, в руках или программе?

#include <LiquidCrystal.h> 

#define DDS_CLOCK 125000000
#define CLOCK 3  //pin connections for DDS
#define LOAD  2 
#define DATA  1
#define RESET 0

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void AD9850_init()
{
  digitalWrite(RESET, LOW);
  digitalWrite(CLOCK, LOW);
  digitalWrite(LOAD, LOW);
  digitalWrite(DATA, LOW);
}



void AD9850_reset()
{
  //reset sequence is:
  // CLOCK & LOAD = LOW
  //  Pulse RESET high for a few uS (use 5 uS here)
  //  Pulse CLOCK high for a few uS (use 5 uS here)
  //  Set DATA to ZERO and pulse LOAD for a few uS (use 5 uS here)
  
  // data sheet diagrams show only RESET and CLOCK being used to reset the device, but I see no output unless I also
  // toggle the LOAD line here.
  
  digitalWrite(CLOCK, LOW);
  digitalWrite(LOAD, LOW);
    
  digitalWrite(RESET, LOW);
  delay(5);
  digitalWrite(RESET, HIGH);  //pulse RESET
  delay(5);
  digitalWrite(RESET, LOW);
  delay(5);
     
  digitalWrite(CLOCK, LOW);
  delay(5);
  digitalWrite(CLOCK, HIGH);  //pulse CLOCK
  delay(5);
  digitalWrite(CLOCK, LOW);
  delay(5);
  digitalWrite(DATA, LOW);    //make sure DATA pin is LOW
     
  digitalWrite(LOAD, LOW);
  delay(5);
  digitalWrite(LOAD, HIGH);  //pulse LOAD
  delay(5);
  digitalWrite(LOAD, LOW);
  // Chip is RESET now
}

void SetFrequency(unsigned long frequency)
{
  unsigned long tuning_word = (frequency * 4294967296LL) / DDS_CLOCK;
  digitalWrite (LOAD, LOW); 

  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 8);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 16);
  shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 24);
  shiftOut(DATA, CLOCK, LSBFIRST, 0x0);
  
  digitalWrite (LOAD, HIGH); 
}


void setup()
{
  lcd.begin(16, 2);              // start the library
  lcd.setCursor(1,0);
  lcd.print("**DDS AD9850**");
}

void loop()
{
  AD9850_init;
  AD9850_reset;
  SetFrequency(1000);
  lcd.setCursor(0,1);
  lcd.print("Freq=1kHz");
  while(1);
}

 

Darth_Vader
Offline
Зарегистрирован: 12.10.2013
Поправил setup() и loop(), но ничего не изменилось
void setup()
{
  pinMode(RESET, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(CLOCK, OUTPUT);
  pinMode(LOAD, OUTPUT);
  lcd.begin(16, 2);              // start the library
  lcd.setCursor(1,0);
  lcd.print("**DDS AD9850**");
  AD9850_init;
  AD9850_reset;
}

void loop()
{
  delay(500);
  SetFrequency(10000);
  while(1);
}

 

 

Darth_Vader
Offline
Зарегистрирован: 12.10.2013

Разобрался. Тему можно закрыть.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

А поделиться информацией? Возможно кому то это тоже может помочь.

std
Offline
Зарегистрирован: 05.01.2012

kisoft +1, мне любопытно. Хочу на нём собрать гетеродинный приёмник для пассивного считавания EM4100 RFId меток.

Darth_Vader
Offline
Зарегистрирован: 12.10.2013

Ошибка в том, что я снимал сигнал с выхода QOUT1, а не ZOUT1

QOUT1 всегда 0, QOUT2 всегда 1. Потенциометр не крутил. По идее это выходы не для синуса, а для меандра.

У этой платы обнаружил особенность - чем выше частота (заметнее на частотах > 5Мгц), тем меньше амплитуда сигнала.

Причем, Vmax сигнала остаётся в районе 1В (1.04в, если быть точным), а Vmin с увеличением частоты тоже увеличивается.

Вечером накидаю график зависимости, может будет кому-то полезным.

 

Darth_Vader
Offline
Зарегистрирован: 12.10.2013

Записал видео, как меняется амплитуда сигнала в зависимости от генерируемой частоты.

На видео видна форма сигнала, максимальное и минимальное напряжение.

Диапазон частот - 20КГц÷20Мгц с шагом 20КГц

Трафик! 2 мин - 130 Мбайт.

https://dl.dropboxusercontent.com/u/72215607/VID_20131113_191651.3gp

#include <LiquidCrystal.h>

#include <EF_AD9850.h>

EF_AD9850 AD9850(3,2,0,1);

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

unsigned long freq = 10000, delta = 20000;

void setup() {
  AD9850.init();
  AD9850.reset();
  lcd.begin(16, 2);

}

void loop() {
  lcd.home();
  delay(10000);
  lcd.print("** DDS AD9850**");
  for(freq=delta; freq<=20000000; freq+=delta){
    AD9850.wr_serial(0,freq);
    lcd.setCursor(0,1);
    lcd.print("Freq=");
    lcd.print(freq);
    lcd.print("Hz   ");
    delay(100);
  }

}

 

Darth_Vader
Offline
Зарегистрирован: 12.10.2013

Кому будет интересно, составил график зависимости амплитуды от генерируемой частоты

http://s019.radikal.ru/i637/1311/bc/d4b0a5262872.png

iwe
Offline
Зарегистрирован: 22.10.2014

А можно фото проекта?

wowscheg
Offline
Зарегистрирован: 14.02.2012

Здравствуйте!

Делаю синтезатор на ардуино и платке с AD9850. Нашел код запустил работает, теперь мне нужно изменить код для введения одной функции. А именно, сейчас синтезатор выдает частоту от 1мгц до 30 мгц а нужно разбить на небольшие отрезки, переключаемые кнопкой, подключенной ну например к выводу A1

Например разбить на 9 кусочков

1. от 1мгц до 2мгц

2. от 2мгц до 3мгц

.....

9 от 9мгц до 10 мгц

И что бы диапазоны переключались цикличиски. Вот что имею. Помогите с кодом пожалуйста

/*
Main code by Richard Visokey AD7C - www.ad7c.com
Revision 2.0 - November 6th, 2013
*/
//Если необходима функция выбора шага энкодера на щелчек, Смотрим строки 57, 89 и 110
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
//Резерв для описания 
// Include the library code 
//Инициализация библиотек
#include <LiquidCrystal.h> //библиотека 1602
#include <rotary.h> //библиотека энкодера  
#include <EEPROM.h> //библиотека EEPROM

//Setup some items
//Настройка некоторых элементов
//Подключаем модуль синтезатора
#define W_CLK 10 // Pin 10 - connect to AD9850 module word load clock pin (CLK)
                 // Выыод 10 - подкоючаем к выводу W_CLK модуля синтезатора (таймер)
#define FQ_UD 11 // Pin 11 - connect to freq update pin (FQ)
                 // Выыод 11 - подкоючаем к выводу FQ_UD модуля синтезатора (обновление частоты)
#define DATA 12  // Pin 12 - connect to serial data load pin (DATA)
                 // Выыод 12 - подкоючаем к выводу DATA модуля синтезатора (загрузка данных)
#define RESET 13 // Pin 13 - connect to reset pin (RST)
                 // Выыод 13 - подкоючаем к выводу RESET модуля синтезатора (сброс)
                 
                 
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
Rotary r = Rotary(2,3); // sets the pins the rotary encoder uses. Must be interrupt pins.
                        //Подключаем энкодер к 2 и 3 ножкам
LiquidCrystal lcd(9, 8, 7, 6, 5, 4); // I used an odd pin combination because I need pin 2 and 3 for the interrupts.
                                     //Подключаем 1602 дисплей к соответствующим пинам, указываем номера портовв порядке RS, E, DB4, DB5, DB6, DB7
int_fast32_t rx=10000000; // Base (starting) frequency of VFO. This only loads once. To force load again see ForceFreq variable below.
                         //Запуск синтезатора с этой частоты, единожды, для дальнейшего обращения используем переменную ForceFreq ниже
int_fast32_t rx2=1; // variable to hold the updated frequency
                    // Переменная для хранения новой частоты
int_fast32_t increment = 100; // starting VFO update increment in HZ.
                               // Установка шага на один щелчек энкодера при запуске. 
int_fast32_t iffreq = 1000000; // Intermedite Frequency - Amount to subtract (-) from base frequency. ********************************************
                               // Здесь необходимо выставить частоту ПЧ в герцах
int buttonstate = 0;
int buttonstate2 = 0;
int GoIF = 1;
//String hertz = "100 Hz"; //Нужно для установки шага энкодера, при необходимости раскомментировать.
int hertzPosition = 5;
byte ones,tens,hundreds,thousands,tenthousands,hundredthousands,millions ; //Placeholders
                                                                           //Заполнители?
String freq; // string to hold the frequency
             //Строка для хранения частоты
int_fast32_t timepassed = millis(); // int to hold the arduino miilis since startup
                                    // Провести инициализацию ардуино в милисекундах после запуска
int memstatus = 1; // value to notify if memory is current or old. 0=old, 1=current.
                   // Смотрим, в памяти значение старое или новое. 0 - Старое 1 -Новое


int ForceFreq = 0; // Change this to 0 after you upload and run a working sketch to activate the EEPROM memory. YOU MUST PUT THIS BACK TO 0 AND UPLOAD THE SKETCH AGAIN AFTER STARTING FREQUENCY IS SET!
                   // Если установить 0 то при включении программа возьмет из памяти EEPROM последнее значение частоты, если 1 то стартует с частоты указанной 30 строке.
                   // Внимание, при первой прошивке и запуске значение в EEPROM нет, поэтому нужно выствить 1 прошить ардуино. Затем, если нужна память на последнюю частоту, выставить 0 в скетче и прошить ардуино снова.

void setup() {
pinMode(A5,INPUT); // Подключаем к кнопку которая при нажатии замыкает вывод А5 на общий провод 
digitalWrite(A5,HIGH); //Подтягиваем вывод A5 к плюсу питания
lcd.begin(16, 2); //Указываем сколько у нас символов и строк на дисплее.
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
pinMode(FQ_UD, OUTPUT); //Выставляем вывод как цифровой выход
pinMode(W_CLK, OUTPUT); //Выставляем вывод как цифровой выход
pinMode(DATA, OUTPUT);  //Выставляем вывод как цифровой выход
pinMode(RESET, OUTPUT); //Выставляем вывод как цифровой выход
pulseHigh(RESET);
pulseHigh(W_CLK);
pulseHigh(FQ_UD); // this pulse enables serial mode on the AD9850 - Datasheet page 12.
                  // Этот импульс необходим для последовательной шины, Datasheet страница 12.
lcd.setCursor(hertzPosition,1);
//lcd.print(hertz); //Начало настроек для выбора кнопки переключения шага энкодера----------------
//pinMode(A0,INPUT); // Connect to a button that goes to GND on push                             |
                   // Подключаем к кнопку которая при нажатии замыкает вывод А0 на общий провод  |
//digitalWrite(A0,HIGH); //Подтягиваем вывод A0 к плюсу питания                                  |
//-------------------Окончание настроек для выбора кнопки переключения шага энкодера-----------------
// Load the stored frequency
//Загружаем сохраненную частоту
if (ForceFreq == 0) {
freq = String(EEPROM.read(0))+String(EEPROM.read(1))+String(EEPROM.read(2))+String(EEPROM.read(3))+String(EEPROM.read(4))+String(EEPROM.read(5))+String(EEPROM.read(6));
rx = freq.toInt();
}
}


void loop() {
// Обновляем частоту на дисплее и частоту синтезатора если она (частота) изменилась
if (rx != rx2){
showFreq();
sendFrequency(rx);
rx2 = rx;
}
//---------------------------------------------Начало участка кода для управления шагом щелчка энкодером.

// Циклически меняем шаг перестройки при нажатии и удержании кнопки, при необходимости раскомментировать
//buttonstate = digitalRead(A0);
//if(buttonstate == LOW) {
//setincrement();
//};

//void setincrement(){ //Здесь закомментированы шаги переключения энкодера, необходимое раскомментировать
//if(increment == 10){increment = 50; hertz = "50 Hz"; hertzPosition=5;}
//else if (increment == 50){increment = 100; hertz = "100 Hz"; hertzPosition=4;}
//else if (increment == 100){increment = 500; hertz="500 Hz"; hertzPosition=4;}
//else if (increment == 500){increment = 1000; hertz="1 Khz"; hertzPosition=6;}
//else if (increment == 1000){increment = 2500; hertz="2.5 Khz"; hertzPosition=4;}
//else if (increment == 2500){increment = 5000; hertz="5 Khz"; hertzPosition=6;}
//else if (increment == 5000){increment = 10000; hertz="10 Khz"; hertzPosition=5;}
//else if (increment == 10000){increment = 100000; hertz="100 Khz"; hertzPosition=4;}
//else if (increment == 100000){increment = 1000000; hertz="1 Mhz"; hertzPosition=6;}
//else{increment = 10; hertz = "10 Hz"; hertzPosition=5;};
//lcd.setCursor(0,1);
//lcd.print(" ");
//lcd.setCursor(hertzPosition,1);
//lcd.print(hertz);
//delay(250); // С помощью этой задержки можно менять скорость изменения шага при нажатой кнопке
//};
//---------------------------------------------Окончание участка кода для управления шагом щелчка энкодером.



// Проверяем уровень на выводе А5, если низкий - включаем отступ на ПЧ
// на дисплее остается частота приема, синтезатор получает "Частота приема - Частота ПЧ"
// (тут напутано вроде или я глючу ? вроде как наоборот низкий уровень - нет вычета ПЧ)
buttonstate = digitalRead(A5);
if (buttonstate != buttonstate2){
if(buttonstate == LOW) {
lcd.setCursor(15,1);
lcd.print(".");
GoIF = 0;
buttonstate2 = buttonstate;
sendFrequency(rx);
}
else{
lcd.setCursor(15,1);
lcd.print(" ");
GoIF = 1;
buttonstate2 = buttonstate;
sendFrequency(rx);
};
};

// Записываем частоту в постоянную память если она не изменнялась поседние 2 секунды
if(memstatus == 0){
if(timepassed+2000 < millis()){
storeMEM();
}
}

}


// Процедура прерывания по событию изменение состояния энкодера
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result) {
if (result == DIR_CW){rx=rx+increment;}
else {rx=rx-increment;};
if (rx >=30000000){rx=rx2;}; // Верхний предел частоты
if (rx <=1000000){rx=rx2;}; // Нижний предел частоты
}
}

// вычисление частоты из даташита, стр. 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {
if (GoIF == 1){frequency=frequency-iffreq;}; // Если на выводе А5 низкий уровень - вычитаем ПЧ
int32_t freq = frequency * 4294967295/125000000; // Для тактовой 125 МГц на AD9850. Можно слегка поиграться значением для более точной настройки.
for (int b=0; b<4; b++, freq>>=8) {
tfr_byte(freq & 0xFF);
}
tfr_byte(0x000); // Завершающий байт последовательности, 0 для AD9850 (1 для AD9851 если не путаю)
pulseHigh(FQ_UD); // Готово! Дергаем ножкой мк
}

// Передача байта по биту за раз в режиме "сначала младший" (LSB) на AD9850 через последовательую шину (DATA)
void tfr_byte(byte data)
{
for (int i=0; i<8; i++, data>>=1) {
digitalWrite(DATA, data & 0x01);
pulseHigh(W_CLK); // после отправки каждого бита отправляем одиночный импульс высокого уровня на CLK
}
}

void showFreq(){ //Вывод частоты в верхнюю строку
millions = int(rx/1000000); //Показать колличество мегагерц на верхнюю строку
hundredthousands = ((rx/100000)%10);
tenthousands = ((rx/10000)%10);
thousands = ((rx/1000)%10);
hundreds = ((rx/100)%10);
tens = ((rx/10)%10);
ones = ((rx/1)%10);
lcd.setCursor(0,0);
lcd.print("  "); //Пустой символ перед частотой для выравнивания надписи в верхней строке
if (millions > 9){lcd.setCursor(1,0);}
else{lcd.setCursor(2,0);}
lcd.print(millions);
lcd.print(".");
lcd.print(hundredthousands);
lcd.print(tenthousands);
lcd.print(thousands);
lcd.print(".");
lcd.print(hundreds);
lcd.print(tens);
lcd.print(ones);
lcd.print(" Mhz "); //Вывод на дисплей Mhz после частоты в первой строке
timepassed = millis();
memstatus = 0; // Сигнализируем об изменении частоты и потенциальной необходимости ее записи в постоянную память
};

void storeMEM(){
//Записываем частоту в постоянную память (EEPROM) поразрядно (это коряво, но работает)
EEPROM.write(0,millions);
EEPROM.write(1,hundredthousands);
EEPROM.write(2,tenthousands);
EEPROM.write(3,thousands);
EEPROM.write(4,hundreds);
EEPROM.write(5,tens);
EEPROM.write(6,ones);
memstatus = 1; // Сигнализируем программе, что последние изменения частоты записаны в постоянную память (EEPROM)
};

 

Скай
Offline
Зарегистрирован: 05.02.2015

Кто-нибудь вообще в курсе, как правильно подключить и закодить зелёную плату с AD 9850?
Я гуглил, нашёл три скетча, ни один из них ни хрена не работает. 
Что надо: скетч, в котором задал частоту и осциллок, подключённый к выводу SinA показывает синусоиду указанной частоты. 

Помогите, пожалуйста, может, кто-то уже кодил сей генератор?

Mining
Offline
Зарегистрирован: 31.01.2016

Может кому пригодится.
DDS генератор синусоидальных и прямоугольных сигналов в диапазононе частот 0 - 40МГц на базе
Arduino Uno + AD9850 DDS

Для сборки надо:
Arduino Uno R3
шилд DFRobot LCD Keypad Shield
модуль HC-RS08 AD9850 DDS
8 проводов для соединения модулей

Сборка:
1.Подключаем к компьютеру плату Arduino Uno и загружаем в нее Sketch:

#include <LiquidCrystal.h> // Подключение библиотек
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Инициализация LCD с указанием пинов
float freq      = 10000; // Оглашение переменных -- Частота
float bigStep = 1000; // Шаг изменения частоты при нажатии вверх/вниз
float littleStep = 10; // Шаг изменения частоты при нажатии вправо/влево 
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0 // Создание директив для кнопок
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
#define W_CLK 15 // Пин A1 Arduino - подключен к CLK
#define FQ_UD 16 // Пин A2 Arduino - подключен к FQ (FU)
#define DATA 17  // Пин A3 Arduino - подключен к DATA
#define RESET 18 // Пин A4 Arduino - подключен к RST
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
//------------------------------------------------------ 
int read_LCD_buttons(){ // Функция считывания нажатия кнопок
 adc_key_in = analogRead(0);     
 if (adc_key_in > 1000) return btnNONE; 
 if (adc_key_in < 50)   return btnRIGHT;  
 if (adc_key_in < 150)  return btnUP; 
 if (adc_key_in < 315)  return btnDOWN; 
 if (adc_key_in < 600)  return btnLEFT; 
 if (adc_key_in < 850)  return btnSELECT;  
 return btnNONE;}
//-------------------------------------------------------
void tfr_byte(byte data){ // Функция побитной отправки байта
 for (int i=0; i<8; i++, data>>=1) { // данных в модуль генератора
  digitalWrite(DATA, data & 0x01);
  pulseHigh(W_CLK);}} // Подача импульса на CLK после каждого бита
//------------------------------------------------------- 
void sendFrequency(double frequency) { // Преобразование и отправка 
  int32_t freq = frequency * 4294967295/125000000;  // значения частоты
  for (int b=0; b<4; b++, freq>>=8) {tfr_byte(freq & 0xFF);}
  tfr_byte(0x000);   // Отправка завершательного контрольного байта
  pulseHigh(FQ_UD);}  // Обновление частоты генератора
//---------------------------------------------------- 
void setup()
{
 lcd.begin(16, 2); // Старт библиотеки. Указанием количества символов и строк
 pinMode(FQ_UD, OUTPUT);
 pinMode(W_CLK, OUTPUT);
 pinMode(DATA, OUTPUT);
 pinMode(RESET, OUTPUT);
 pulseHigh(RESET); // Отправка импульсов для запуска модуля генератора
 pulseHigh(W_CLK);
 pulseHigh(FQ_UD); 
}
//----------------------------------------------------  
void loop()
{
 lcd.setCursor(0,0); // Далее вывод текущего значения частоты
 lcd.print("Freq: ");
 lcd.setCursor(6,0);
 lcd.print("           ");  
 lcd.setCursor(6,0);
 if (freq<1000){lcd.print(freq); 
 lcd.print("Hz");}
 if ((freq>=1000)&&(freq<1000000)){lcd.print(freq / 1000); 
 lcd.print("kHz");}
 if ((freq>=1000000)&&(freq<50000000)){lcd.print(freq / 1000000);
 lcd.print("MHz");}
 lcd.setCursor(0,1);
 lcd.print("   Genie v1.0");  
 if (freq<100){bigStep = 10; // Определение шага грубой и точной
 littleStep = 1;} // настройки в зависимости от частоты
 if ((freq>=100)&&(freq<1000)){bigStep = 100;
 littleStep = 1;}
 if ((freq>=1000)&&(freq<10000)){bigStep = 1000;
 littleStep = 10;}
 if ((freq>=10000)&&(freq<100000)){bigStep = 10000;
 littleStep = 100;}
 if ((freq>=100000)&&(freq<1000000)){bigStep = 100000;
 littleStep = 1000;}
 if ((freq>=1000000)&&(freq<10000000)){bigStep = 1000000;
 littleStep = 10000;}
 if ((freq>=10000000)&&(freq<40000000)){bigStep = 10000000;
 littleStep = 100000;}
 lcd_key = read_LCD_buttons();  // Считывание клавиш
 switch (lcd_key) // Далее обработка нажатий клавиш          
 {
   case btnRIGHT:
     {freq += littleStep;
     break;}
   case btnLEFT:
     {freq -= littleStep;
     break;}
   case btnUP:
     {freq += bigStep;
     break;}
   case btnDOWN:
     {if (freq == bigStep){freq -= (bigStep/10);}  
     else {freq -= bigStep;}
     break;}
   case btnSELECT:
     {break;}
   case btnNONE:
     {break;}
 }
 if (freq<1) freq=1; // Ограничение значений частоты
 if (freq>40000000) freq=40000000;
 sendFrequency(freq);  // Вызов функции отправки частоты
 delay (200); // Пауза 200 мс
}

2.Получаем сообщение "Done uploading." = значит все сделано правильно и приступаем к соединению модулей.

На ножки Arduino Uno втыкаем в DFRobot LCD Keypad Shield.
Затем HC-RS08 AD9850 DDS подключить с помощью проводников по следующей схеме:
Выводы Arduino Uno соединяем с штырьками HC-RS08 AD9850 DDS
+5V → VCC
GND → GND
A1   → W_CLK
A2   → FU_UD
A3   → DATA
A4   → RESET

Выходной сигнал снимаем с pin модуля HC-RS08 AD9850 DDS:
QOUT1, QOUT2 =прямоугольный сигнал
ZOUT1 и ZOUT2 =синусоидальный

2. Подаем питание. Через несколько секунд появляется значение частоты по умолчанию- 10 кГц. Его можно изменить нажатиями кнопок вверх/вниз и вправо/влево.

Все пользуем.

ivenir
Offline
Зарегистрирован: 16.05.2016

Добрый вечер всем. Может кому пригодится. Частота задается через COM порт. 

float freq = 0;
long com=0;// Оглашение переменных -- Частота
#define W_CLK 15 // Пин A1 Arduino - подключен к CLK
#define FQ_UD 16 // Пин A2 Arduino - подключен к FQ (FU)
#define DATA 17  // Пин A3 Arduino - подключен к DATA
#define RESET 18 // Пин A4 Arduino - подключен к RST
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
//-------------------------------------------------------
void tfr_byte(byte data){ // Функция побитной отправки байта
 for (int i=0; i<8; i++, data>>=1) { // данных в модуль генератора
  digitalWrite(DATA, data & 0x01);
  pulseHigh(W_CLK);}} // Подача импульса на CLK после каждого бита
//------------------------------------------------------- 
void sendFrequency(double frequency) { // Преобразование и отправка 
  int32_t freq = frequency * 4294967295/125000000;  // значения частоты
  for (int b=0; b<4; b++, freq>>=8) {tfr_byte(freq & 0xFF);}
  tfr_byte(0x000);   // Отправка завершательного контрольного байта
  pulseHigh(FQ_UD);}  // Обновление частоты генератора
//---------------------------------------------------- 
void setup()
{
 Serial.begin(9600);
 pinMode(FQ_UD, OUTPUT);
 pinMode(W_CLK, OUTPUT);
 pinMode(DATA, OUTPUT);
 pinMode(RESET, OUTPUT);
}
//----------------------------------------------------  
void loop()
{
 if (Serial.available()>0) {  //если данные пришли
 com=Serial.parseInt();
  freq=com;
 if (freq<0) freq=0; // Ограничение значений частоты
 if (freq>40000000) freq=40000000;
 pulseHigh(RESET); // Отправка импульсов для запуска модуля генератора
 pulseHigh(W_CLK);
 pulseHigh(FQ_UD);
 sendFrequency(freq);   // Вызов функции отправки частоты
Serial.println(freq);
 }
}

 

anteynew
Offline
Зарегистрирован: 06.06.2016

Для получения квадратных импульсов с выводов QOUT1 и 2 плату нужно настроить !!! На плате есть переменный резистор R13 (большая синяя фигня на плате с пазами под крестовую отвертку). Подключаем плату к Ардуино, выставляем любую частоту, подключаем QOUT1 и GRN к осцилографу и крутим резистор до появления сигнала. Пришло из Китая 10 плат, ни одна не настоена ! С начала думал брак...

kostya261
Offline
Зарегистрирован: 12.05.2016

anteynew пишет:

Для получения квадратных импульсов с выводов QOUT1 и 2 плату нужно настроить !!! На плате есть переменный резистор R13 (большая синяя фигня на плате с пазами под крестовую отвертку). Подключаем плату к Ардуино, выставляем любую частоту, подключаем QOUT1 и GRN к осцилографу и крутим резистор до появления сигнала. Пришло из Китая 10 плат, ни одна не настоена ! С начала думал брак...

 

Фиг его знает, я его уже во все стороны как только не крутил... меандра так и не добился.

Синус нормальный.

777Andrej
Offline
Зарегистрирован: 09.04.2014

Может кто помочь ?
встроил в код генератора вольтметр. 
делаю измерения пока постоянного напряжения по входа А1 от 0-5в 
почему то показания вольтметра скачат, при том. если я выбираю диапазон от 0-100кгц они пляшут , если от 100кгц до 10мгц они стоят ровно.
такое ощущение что работу ацп кто то сбивает, и оно не успевает считать. 
как победить эту проблему не могу. 
 

#include <Rotary.h>


/*
Main code by Igor Krepsky - www.frompinskto.wordpress.com
based on fragments of code by Richard Visokey AD7C - www.ad7c.com
Rev. 2.2 - Spt., 2016  for AD9851 chip.
*/
// Подключение библиотек
#include <LiquidCrystal.h>
#include <rotary.h>


//Определения
#define W_CLK A2     // A2 - connect to AD9851 module word load clock pin (CLK)
#define FQ_UD A3     // A3 - connect to freq update pin (FQ)
#define DATA A4      // A4 - connect to serial data load pin (DATA)
#define RESET A5     // A5 - connect to reset pin (RST)
#define ENC_A 2      // Pin 2 - 1 канал валкодера 
#define ENC_B 3      // Pin 3 - 2 канал валкодера
#define ENC_KEY 4    // Pin 4 - кнопка валкодера
#define MODE_1 0     // Pin 0 - переключатель mode vfo
#define MODE_2 1     // Pin 1 - переключатель mode sweep
#define KEY_1 5      // Pin 5 - доп. кнопка
const int analogInPin = A1;  // Analog input pin 
     
float outputValue = A1;  

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

Rotary r = Rotary(2,3); // Устанавливает пины для каналов энкодера.  Должны поддерживать прерывания.

LiquidCrystal lcd(8, 9, 10, 11, 12, 13); // ПРИСВОЕНИЕ ДЛЯ LCD (RS_E_4_5_6_7)R/W=gnd

// Переменные
int_fast32_t rx=0000000;        // Стартовая частота VFO
int_fast32_t rif=0;             // Значение IF
int_fast32_t wif=450000;        // рабочее значение IF
int_fast32_t rx2=1;             // переменная для сохранения обновлённой частоты
int_fast32_t increment = 1;  // начальный VFO инкремент в HZ.
int_fast32_t delta=1000;        // Стартовая величина ширины качания sweep в Hz
int_fast32_t sstep=1;           // Стартовая величина шага качания sweep в Hz
int buttonstate = 0;            // Переменная для чтения состояния кнопки
String hertz = "1 Hz";
int  hertzPosition = 0;
byte ones,tens,hundreds,thousands,tenthousands,hundredthousands,millions ;  //Разряды для частоты
byte a_1, a_2;            // разряды для отображения IF
String freq;              // string для получения частоты
boolean mod_1;            // текущее значение переключателя mode vfo
boolean mod_1_old;        // сохранённое значение переключателя mode vfo
boolean mod_2;            // текущее значение переключателя mode sweep
boolean mod_2_old;        // сохранённое значение переключателя mode sweep

void setup() {
    // put your setup code here, to run once:
  pinMode(ENC_KEY,INPUT); // кнопка валкодера, 0 при нажатии
  digitalWrite(ENC_KEY,HIGH);
  lcd.begin(16, 2);
  pinMode(ENC_A, INPUT);
  pinMode(ENC_B, INPUT);
  pinMode(MODE_1, INPUT);
  pinMode(MODE_2, INPUT);
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();
  pinMode(FQ_UD, OUTPUT);
  pinMode(W_CLK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RESET, OUTPUT); 
  pulseHigh(RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);  // this pulse enables serial mode on the AD9851 - see datasheet
  lcd.setCursor(hertzPosition,1); 
  lcd.print(hertz);
}// END SETUP

void loop() {

 outputValue = float(analogRead(analogInPin)) / 204.6; //вольтметр
 lcd.setCursor(6, 1);
lcd.print(" Vout=          ");
lcd.setCursor(6, 1);
lcd.print(" Vout=");
int mv = outputValue * 1000;
if(mv<1000)
{
  lcd.print(mv);
}
else
{
  lcd.print(outputValue);
  lcd.print("  ");
}

  delay(100);

// ИЗМЕНЕНИЕ ИНКРЕМЕНТА (кнопка валкодера)
      buttonstate = digitalRead(ENC_KEY); // если нажатие кнопки валкодера - изменить инкремент
      if(buttonstate == LOW) {
      setincrement();        
      }
// ВОЗВРАТ ШАГА ИЗМЕНЕНИЯ ЧАСТОТЫ к 1КГЦ в РЕЖИМЕ ГЕНЕРАТОРА
      if ((mod_1 == 1)&&(mod_2 == 1)){
      buttonstate = digitalRead(KEY_1);
      if (buttonstate == LOW){increment = 1; hertz="1Hz"; hertzPosition=0;
      lcd.setCursor(hertzPosition,1);
      lcd.print("       ");
      lcd.setCursor(hertzPosition,1); 
      lcd.print(hertz);
      delay(250); // Adjust this delay to speed up/slow down the button menu scroll speed.  
      }
      }    
// ПЕРЕКЛЮЧАТЕЛЬ MODE
      mod_1 = digitalRead (MODE_1); // чтение значения переключателя mode vfo.
      mod_2 = digitalRead (MODE_2); // чтение значения переключателя mode sweep.
      
// ДЕЙСТВИЯ ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE 
      if ((mod_1 != mod_1_old)||(mod_2 != mod_2_old)){// если произошло переключение mode
      // и вывод на дисплей
      
      // 1.очистка
      
      lcd.setCursor(0,1);
      lcd.print("                ");
      
      // 2.вывод значения
      
      if ((mod_1 == 1)&&(mod_2 == 0)){// если режим генератора
        rif=0;
        lcd.setCursor(hertzPosition,1); 
        lcd.print(hertz);
      }
 
                                                                    
      if ((mod_1 == 0)&&(mod_2 == 1)){// если режим SWEEP
      rif=0;
      lcd.setCursor(hertzPosition,1); 
      lcd.print(hertz);
      if (delta < 10000){
      lcd.setCursor(5,1);  
      lcd.print("  SWP:");                       
      lcd.print(delta/1000);
      lcd.print("KHz ");
      }
      else if (delta >= 100000){
      lcd.setCursor(5,1);  
      lcd.print("SWP:");                       
      lcd.print(delta/1000);
      lcd.print("KHz ");
      }
      else
      {
      lcd.setCursor(5,1);  
      lcd.print(" SWP:");                       
      lcd.print(delta/1000);
      lcd.print("KHz ");
      } 
      } 
      
// ВЫВОД НА ДИСПЛЕЙ ЧАСТОТЫ И ПЕРЕДАЧА ЕЁ В DDS ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE      
      showFreq();
      sendFrequency(rx+rif);
      rx2 = rx;
      mod_1_old = mod_1;
      mod_2_old = mod_2;  
      } 
// ОКОНЧАНИЕ ДЕЙСТВИЯ ПОСЛЕ ПЕРЕКЛЮЧЕНИЯ MODE 
      
// ВЫЧИСЛЕНИЕ ЧАСТОТЫ ДЛЯ РЕЖИМА SWEEP
      if ((mod_1 == 0)&&(mod_2 == 1)){
      rif = rif + sstep;
      if (rif > delta) {rif = 0;}
      sendFrequency(rx+rif);// отправить частоту в синтезатор
      // переключение delta 
      buttonstate = digitalRead(KEY_1);
      if (buttonstate == LOW) {
      if (delta == 1000){delta = 5000;}
      else if (delta == 5000){delta = 10000; sstep = 2;}
      else if (delta == 10000){delta = 50000; sstep = 5;}
      else if (delta == 50000){delta = 100000; sstep = 10;}
      else {delta = 1000; sstep = 1;}
      if (delta < 10000){
      lcd.setCursor(5,1);  
      lcd.print("  SWP:");                       
      lcd.print(delta/1000);
      lcd.print("kHz ");
      }
      else if (delta == 100000){
      lcd.setCursor(5,1);  
      lcd.print("SWP:");                       
      lcd.print(delta/1000);
      lcd.print("kHz ");
      }
      else
      {
      lcd.setCursor(5,1);  
      lcd.print(" SWP:");                       
      lcd.print(delta/1000);
      lcd.print("kHz ");
      } 
     // delay(500);
      }  
      }
// ВЫЧИСЛЕНИЕ ЧАСТОТЫ ДЛЯ РЕЖИМА УЧЁТА ПРОМЕЖУТОЧНОЙ ЧАСТОТЫ
    if ((mod_1 == 1)&&(mod_2 == 0)){
      rif = wif;
      
     
      buttonstate = digitalRead(KEY_1);
      if (buttonstate == LOW);  // read the analog in value:

 
      }
    
// ВЫВОД НА ДИСПЛЕЙ ЧАСТОТЫ И ПЕРЕДАЧА ЕЁ В DDS В ОБЩЕМ СЛУЧАЕ 
          
        if (rx != rx2)
        {
        showFreq();// при изменении частоты вывести на дисплей
        sendFrequency(rx+rif);// отправить частоту в синтезатор
        rx2 = rx;
        }
            
}// END LOOP

// ПОДПРОГРАММЫ
// Обработка прерывания
ISR(PCINT2_vect) {
  
    // обработка энкодера
    unsigned char result = r.process();
    if (result) {    
    if (result == DIR_CW){rx=rx+increment;}
    else {rx=rx-increment;};       
    // конец обработки валкодера
    if ((rx+rif) >40000000){rx=(40000000-rif);}; // ВЕРХНИЙ VFO LIMIT
    if (rx <1){rx=0;}; // НИЖНИЙ VFO LIMIT
    }
    }

    
// расчёт частоты на основе докумментации на микросхему = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {  
  int32_t freq = frequency * 4294967296./125000997;  // note 180 MHz clock on 9851. если генератор на 125мгц, то вписать . тут же можно и подогнать частоту генератора
  for (int b=0; b<4; b++, freq>>=8) 
  {
   tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, LSB 1 to enable 6 x xtal multiplier on 9851 set to 0x000 for 9850
  pulseHigh(FQ_UD);  // Сделано!  Должен увидеть выход.
  }

// передаёт байт, по биту за раз, начиная с LSB  на 9851 через serial DATA line
void tfr_byte(byte data)
{
  for (int i=0; i<8; i++, data>>=1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //после передачи каждого бита, CLK is pulsed high
  }
}

void setincrement(){// установка значения инкремента частоты
  if(increment == 1){increment = 10; hertz = "10Hz"; hertzPosition=0;} 
  else if(increment == 10){increment = 100; hertz = "100Hz"; hertzPosition=0;}
  else if (increment == 100){increment = 1000; hertz="1Khz"; hertzPosition=0;}
  else if (increment == 1000){increment = 10000; hertz="10Khz"; hertzPosition=0;}
  else if (increment == 10000){increment = 100000; hertz="100Khz"; hertzPosition=0;}
  else if (increment == 100000){increment = 1000000; hertz="1Mhz"; hertzPosition=0;} 
  else if (increment == 1000000){increment = 10000000; hertz="10Mhz"; hertzPosition=0;} 
  else{increment = 1; hertz = "1Hz"; hertzPosition=0;};  
   lcd.setCursor(hertzPosition,1);
   lcd.print("       ");
   lcd.setCursor(hertzPosition,1); 
   lcd.print(hertz);
   delay(100); // Adjust this delay to speed up/slow down the button menu scroll speed.
};

void showFreq(){// вывод значения частоты на дисплей
    millions = int(rx/1000000);
    hundredthousands = ((rx/100000)%10);
    tenthousands = ((rx/10000)%10);
    thousands = ((rx/1000)%10);
    hundreds = ((rx/100)%10);
    tens = ((rx/10)%10);
    ones = ((rx/1)%10);
    lcd.setCursor(0,0);
    lcd.print("                ");
   if (millions > 9){lcd.setCursor(2,0);}
   else{lcd.setCursor(2,0);}
    lcd.print(millions);
    lcd.print(".");
    lcd.print(hundredthousands);
    lcd.print(tenthousands);
    lcd.print(thousands);
    lcd.print(".");
    lcd.print(hundreds);
    lcd.print(tens);
    lcd.print(ones);
    lcd.print(" Hz ");
      
};