DDS генератор на Arduino + AD9850

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Народ, кто нибудь придавал мучению китайский модуль с AD9850 управляя ардуиной?

Возможно ли получить минимальный шаг перестройки 0.0291 Hz, как заявлено даташите: "The AD9850’s innovative high speed DDS core provides a 32-bit frequency tuning word, which results in an output tuning resolution of 0.0291 Hz for a 125 MHz reference cloc input." ?

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

Эксперементируй -вот sketch

/*
Main code by Richard Visokey AD7C - www.ad7c.com
Revision 2.0 - November 6th, 2013
*/

//  --  Modified 05.11.2015 --

// Include the library code
#include <LiquidCrystal.h>
#include <Rotary.h>
#include <EEPROM.h>

// Установка DDS AD9850
#define W_CLK 8   // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 9   // Pin 9 - connect to freq update pin (FQ)
#define DATA 10   // Pin 10 - connect to serial data load pin (DATA)
#define RESET 11  // Pin 11 - connect to reset pin (RST) 
#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.

// Установка дисплея
LiquidCrystal lcd(12, 13, 7, 6, 5, 4); // I used an odd pin combination because I need pin 2 and 3 for the interrupts.

// Рабочие переменные
int_fast32_t rx=10000000; // Starting frequency of VFO
int_fast32_t rx_round=0; 
int_fast32_t rx2=1; // variable to hold the updated frequency
int_fast32_t increment = 100000; // starting VFO update increment in KHz.
int buttonstate = 0;
int press_counter = 1;
String hertz = "               ";
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.

int border1 = 300;
int border2 = 75;
int border3 = 25;

int ForceFreq = 0;  // "1" - Задать начальную частоту 10000 кГц, "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!

boolean inc_flag = false;  // Сброс флага определения вращения энкодера 

// Переменные для идентификации вращения энкодера
unsigned long time_old = 0;
unsigned long time_new = 0;
unsigned long delta_time = 0;
unsigned long abs_delta_time = 0;

void setup() {
  pinMode(A0,INPUT); // Connect to a button that goes to GND on push
  digitalWrite(A0,HIGH);
  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.
  
// --------  Start screen    --------
  lcd.clear();
  lcd.setCursor(0,0);   
  lcd.print("DDS Autostep 7.8");  
  lcd.setCursor(0,1);     
  lcd.print("Signal Generator");   
  delay(700);
  lcd.setCursor(0,1);     
  lcd.print("50KHz .... 45MHz");   
  delay(700);  
// Бегущая строка - экран приветствия
  for (int positionCounter = 0; positionCounter < 16; positionCounter++) { lcd.scrollDisplayLeft(); delay(20);  }
//  for (int positionCounter = 0; positionCounter < 32; positionCounter++) { lcd.scrollDisplayRight(); delay(20); }  
//  Очистим экран после приветствия
lcd.clear(); 
  
// Загружаем из EEPROM сохраненную там частоту  
  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();  
  }

// Задаем начальный режим
  hertz = "  100KHz"; 
//  lcd.setCursor(0,1); lcd.print(press_counter); 
  lcd.setCursor(3,1); lcd.print("Step:");
  lcd.setCursor(8,1); lcd.print(hertz);
  
// Запоминаем опорное время
  time_old=millis();  
  abs_delta_time = 1000; // Фиксируем шаг 100Гц
  
}  // Конец инициализации void setup()


// ************  Главный цикл **********

void loop() {

// Обработка режима авт. изменения инкремента
  if (press_counter == 5)
    {      
          if (abs_delta_time > border1)
            { increment = 100; abs_delta_time = 1000; lcd.setCursor(0,1); lcd.print("   ");}
            
          if ((abs_delta_time <= border1)&&(abs_delta_time > border2))
            { increment = 1000; abs_delta_time = (border1 + border2)/2; lcd.setCursor(0,1); lcd.print(">  ");}            

          if ((abs_delta_time <= border2)&&(abs_delta_time > border3))
            { increment = 10000; abs_delta_time = (border2 + border3)/2; lcd.setCursor(0,1); lcd.print(">> ");}            
            
           if (abs_delta_time <= border3)
            { increment = 250000; abs_delta_time = 20; lcd.setCursor(0,1); lcd.print(">>>");}      
    }  
 
// Если частота изменилась в последнем цикле, то  
  if (rx != rx2)
    {    
      showFreq();           // Показать ее и
      sendFrequency(rx);    // Установить ее
      rx2 = rx;
    }
      
// Пишем частоту в EEPROM, если не записана, и прошли 1,5 секунды со времени последнего изменения частоты.
    if(memstatus == 0)
      {   
        if(millis() >= timepassed+1500)  { storeMEM(); abs_delta_time = 1000;}        
      }   

// Не нажата ли головка энкодера?      
  buttonstate = digitalRead(A0);  
  if(buttonstate == LOW)  // Если нажата
    {
      // Организуем счетчик нажатий кнопки
      press_counter = press_counter+1;
      if (press_counter >= 7){press_counter = 0;}
//      lcd.setCursor(0,1); 
//      lcd.print(press_counter); 
      // Назначаем действия по каждому состоянию счетчика нажатий
      lcd.setCursor(3,1); lcd.print("Step:");
      switch (press_counter) {
      case 0:
//      {increment = 100;  hertz = "    Auto"; lcd.setCursor(8,1); lcd.print(hertz); }
        {increment = 1000000; hertz="   1 MHz"; lcd.setCursor(8,1); lcd.print(hertz); }
        break;   
      case 1:
        {increment = 100000; hertz=" 100 KHz"; lcd.setCursor(8,1); lcd.print(hertz); }
        break;
      case 2:
        {increment = 50000; hertz="  50 KHz"; lcd.setCursor(8,1); lcd.print(hertz); }
        break;        
      case 3:
        {increment = 5000; hertz="   5 KHz"; lcd.setCursor(8,1); lcd.print(hertz); }
        break;
      case 4:
        {increment = 1000; hertz="   1 KHz"; lcd.setCursor(8,1); lcd.print(hertz); }
        break;
      case 5:
        {increment = 100;  hertz = " 100  Hz"; lcd.setCursor(8,1); lcd.print(hertz); }
        break;
      case 6:
        {increment = 100;  hertz = "    Auto"; lcd.setCursor(8,1); lcd.print(hertz); }
        break;
         
      default: 
//      {increment = 100;  hertz = "    Auto"; lcd.setCursor(8,1); lcd.print(hertz); }
        {increment = 1000000; hertz="    1 MHz"; lcd.setCursor(8,1); lcd.print(hertz); }
  }

// Пауза при циклической обработке кнопки энкодера.
      delay(200);
      lcd.setCursor(0,1); lcd.print("> ");
      delay(200); 
      lcd.setCursor(0,1); lcd.print("  ");
    };

}  // Закончили главный цикл
// ************  Конец цикла **********

// Ловушка прерывания при вращении энкодера
ISR(PCINT2_vect) {
  unsigned char result = r.process();
  
  if (result) // Если начали вращать энкодер
    {  
      // Определяем скорость вращения
        
          time_new=millis(); // Запоминаем время импульса
          delta_time=(time_new - time_old); // Вычисляем интервал времени между импульсами
          abs_delta_time=abs(delta_time);   // Абс. величина интервала
          time_old=time_new;  // Перезапоминаем опорное время

// В зависимости от направления вращения "+" или "-" инкремент 
    if (result == DIR_CW) { rx=rx+increment; }
    else                  { rx=rx-increment; }; 
    if (rx >45000000){rx=rx2;}; // Ограничение макс. частоты
    if (rx <50000){rx=rx2;};   // Ограничение мин. частоты
  } // Конец обработки вращения энкодера
}  //  Конец ловушки прерывания


// Расчет частоты для DDS
// Frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {  
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850.  You can make 'slight' tuning variations here by adjusting the clock frequency.
  for (int b=0; b<4; b++, freq>>=8) { tfr_byte(freq & 0xFF); }
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
  pulseHigh(FQ_UD);  // Done!  Should see output
}    // Конец расчета частоты

// Передача частоты в DDS
// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
  for (int i=0; i<8; i++, data>>=1) 
    {
      digitalWrite(DATA, data & 0x01);
      pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
    }
}   // Конец передачи частоты в DDS


// Индикация частоты
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 ");
    timepassed = millis();
    memstatus = 0; // Trigger memory write
};

// Запись частоты в EEPROM
void storeMEM(){
  //Write each frequency section to a EPROM slot.  Yes, it's cheating but it works!
   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;  // Let program know memory has been written
};

 

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Спасибо! Но что то в скетче не могу найти где установить минимальный шаг перестройки. Хочу увидеть заявленный 0.0291 Hz ))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Ivan_Kornege, нигде. Там много всего нужно поменять что б ввести частоты с  запятой.

 

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

dimax пишет:

Ivan_Kornege, нигде. Там много всего нужно поменять что б ввести частоты с  запятой.

Тодым слёзно молим о помощи как ГУРУ в всоздании генераторов на ардуине ☝☺

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Ivan_Kornege, совершенно не интересно честно говоря, я и в своём генераторе не стал делать шаг меньше герца за отсутствием смысла. Да и модуля такого нет..

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

dimax пишет:

Ivan_Kornege, совершенно не интересно честно говоря, я и в своём генераторе не стал делать шаг меньше герца за отсутствием смысла. Да и модуля такого нет..

Ну, а как же спортивный интерес )). Надо же потестить железяку увидеть заявленные 0.0291 Hz  . 

Ну, и при исследовании различного рода катушек индуктивности генератор с такой точностью очень даже нужен. Многие человеки за такой генератор скажут ОГРОМНОЕ СПАСИБО! Уговорил? Работаем в ЧЕТЫРЕ руки? ))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Ivan_Kornege, откуда ж у меня спортивному интересу взяться, ежели нет этого модуля? Присылай модуль в дар  - напишу :)

MagicianT
Offline
Зарегистрирован: 03.10.2015

Тут пример самый простой, что можно найти, я с него начинал 

http://blog.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html

там видно что при передаче частоты в функцию

 

void sendFrequency(double frequency) {
int32_t freq = frequency * 4294967295 / 125000000; // note 125 MHz clock on 9850
она домножается на 4294967295 / 125000000 = 34.35973836
34.35973836^-1 = 0.02910383
 
Нет проблем передавайте при вызове float и всё должно сработать
Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

dimax пишет:

Ivan_Kornege, откуда ж у меня спортивному интересу взяться, ежели нет этого модуля? Присылай модуль в дар  - напишу :)

Замётано! Для хорошего человека не жалко.

В скетч добавишь шаг пеерстройки 0.0291 Hz, который Mining здесь подогнал #1

?

Свою старую как то не фонтан тебе слать я еЁ трохи покоцал пояльником. Бульба вырастет к сентяброю -продам и прямиком от китайца отправлю новенькую AD9850.

И у тебя время будет для творческого разбега )). К зиме бум с табой такие красавцы с DDS ))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Ivan_Kornege, не вопрос - сделаю.  Но в принципе до сентября ты и сам бы успел научиться :-)

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

dimax пишет:

Ivan_Kornege, не вопрос - сделаю.  Но в принципе до сентября ты и сам бы успел научиться :-)

А бульбу тогда кто будет растить :'-)

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

dimax, скважность прямоугольника на блоке HC-SR08 регулируется подстроечником (номинал10к) за счёт смещения напряжения на входе компоратора (нога VINN). Можно ли выкинуть подстроечник и приклячить 10-битный ЦАП TLC5615CD и сделать управление с ардуины?

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

MagicianT пишет:

Тут пример самый простой, что можно найти, я с него начинал 

http://blog.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html

там видно что при передаче частоты в функцию

 

void sendFrequency(double frequency) {
int32_t freq = frequency * 4294967295 / 125000000; // note 125 MHz clock on 9850
она домножается на 4294967295 / 125000000 = 34.35973836
34.35973836^-1 = 0.02910383
 
Нет проблем передавайте при вызове float и всё должно сработать

не не сработало. не компилируется

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Ivan_Kornege, можно конечно, там же просто смещение задаётся. Но может фаза сигнала задрожать, если выход цап шумный окажется.

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

MagicianT пишет:

Тут пример самый простой, что можно найти, я с него начинал 

http://blog.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html

там видно что при передаче частоты в функцию

 

void sendFrequency(double frequency) {
int32_t freq = frequency * 4294967295 / 125000000; // note 125 MHz clock on 9850
она домножается на 4294967295 / 125000000 = 34.35973836
34.35973836^-1 = 0.02910383
 
Нет проблем передавайте при вызове float и всё должно сработать

Что Вы имеет ввиду "передавайте при вызове float"? А можно это выразить ввиде кода.

MagicianT
Offline
Зарегистрирован: 03.10.2015

Ещё пример:

/* 
 * A simple single freq AD9850 Arduino test script
 * Original AD9851 DDS sketch by Andrew Smallbone at www.rocketnumbernine.com
 * Modified for testing the inexpensive AD9850 ebay DDS modules
 * Pictures and pinouts at nr8o.dhlpilotcentral.com
 * 9850 datasheet at http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf
 * Use freely
 */
 
 #define W_CLK 8       // Pin 8 - connect to AD9850 module word load clock pin (CLK)
 #define FQ_UD 9       // Pin 9 - connect to freq update pin (FQ)
 #define DATA 10       // Pin 10 - connect to serial data load pin (DATA)
 #define RESET 11      // Pin 11 - connect to reset pin (RST).
 
 #define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
 
 // transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
  for (int i=0; i<8; i++, data>>=1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }
}

 // frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850
  for (int b=0; b<4; b++, freq>>=8) {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
  pulseHigh(FQ_UD);  // Done!  Should see output
}

void setup() {
 // configure arduino data pins for output
  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 - Datasheet page 12 figure 10
}

void loop() {
//  sendFrequency(10.e6);  // freq
//  while(1);
  int sensor = analogRead(5);
  
 sendFrequency(sensor * 1e2);
  delay(100);
}

Ставим крутилку на аналог А5 и меняем частоту. 1е2 задаёт масштаб. Так вот, из-за того что аналог порт возвращает интежер значение, получить желаемый шаг по частоте не представляется возможным. Даже если масштаб (х 1е2) убрать, всё равно 1 Гц, а не 0.029Гц как хотелось. Вообще проблема , если она есть, из разряда правильного шкалирования данных. 

Функция void sendFrequency(double frequency) жуёт даблы, но на ардуино, насколько мне известно, нет разницы между флотами и даблами, поетому я и сказал "передавайте флоты".

Пардон за шрифт, форум не имеет опции "изменить размер" и после копи-пасте куска с декларацией функции всё пошло, как говорят, фак ап

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Неожиданно... китаец вдруг прислал в подарок шилд, для ардуины UNO, с кнопками и дисплеем1602. И вот я слепил UNO с шилдом и приклячил AD9850

вот чеё вышло

Ну и скетч накидал как смог ))

/* Генератор синусоидальных и прямоугольных сигналов в диапазононе частот от 1Гц до 40МГц. 
Управляется генератор с помощью четырех кнопок - две (вверх/вниз) 
для грубой настройки, и две (влево/вправо) - для точной. 
Шаг настройки изменяется в зависимости от текущей частоты.
Комплектация для сборки мезонином:
   - Arduino Uno R3
   - Шилд DFRobot LCD Keypad Shield (на борту кнопки и диспей 1602)
   - Модуль генератора сигналов AD9850 DDS
   - 8 проводников для соединения модулей
   - USB кабель

Инструкция по сборке:
1) Скачайте и установите Arduino ID. Компилируется в 1.6.8 -провернеро 13-09-2016г.).
2)Подключите к компьтеру плату Arduino Uno и загрузите в нее скетч.
3)После загрузки приступать к следующему этапу -соединению модулей. 
Keypad Shield нужно просто воткнуть поверх Arduino Uno, 
а модуль генератора подключить с помощью проводников по схеме:
Выводы Arduino  Выводы модуля генератора AD9850
+5V              VCC
GND              GND
A1               W_CLK
A2               FU_UD
A3               DATA
A4               RESET

4) После сборки еще раз проверяем правильность подключения, если все правильно -можно 
подавать питание.
5) Через несколько секунд появится значение частоты по умолчанию - 1000000.00 Hz (1.00MHz), которое можно изменить 
нажатиями кнопок вверх/вниз и вправо/влево. 

Выходной сигнал снимается с контактов (контактных штырьков) модуля генератора QOUT1, QOUT2(прямоугольный), ZOUT1 и ZOUT2 (синусоидальный) 

*/
#include <LiquidCrystal.h> // Подключение библиотеки дисплея LCD1602
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // Инициализация LCD1602 с указанием пинов. Устанавливаем номера пинов к которым подключен дисплей
float freq      = 1000000; // Оглашение переменных -- Частота по умолчани при первом запуске 1,00МГц . Можно поставить свою с которой будет стартовать.
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(float 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); // Старт библиотеки дисплея. Устанавливаем количество символов в строке (16) и количство строк (2)
 pinMode(FQ_UD, OUTPUT); //Пин AD9580
 pinMode(W_CLK, OUTPUT); //Пин AD9580
 pinMode(DATA, OUTPUT); //Пин AD9580
 pinMode(RESET, OUTPUT); //Пин AD9580
 pulseHigh(RESET); // Отправка импульсов для запуска модуля генератора AD9580
 pulseHigh(W_CLK);
 pulseHigh(FQ_UD); 
}
//----------------------------------------------------  
void loop()
{
 lcd.setCursor(0,0); //Устанавливаем курсор на первую строчку , где задаем 0- слева отступаем ноль символов считая с левой стророны и 0-первая строка где выводится этот текст "Fr" - freq (частота)
 lcd.print("Fr: "); //выводится этот текст "Fr:" в первой строке
 lcd.setCursor(4,0); //Устанавливаем курсор на первую строчку , задаем 4- с лева отступаем четыре символа считая с левой стророны и 0- первая строка
 lcd.print("           ");  // выводится значение частоты генератора
 lcd.setCursor(4,0); // Устанавливаем курсор на первую строчку , задаем 4- с лева отступаем четыре символа считая с левой стророны и 0- первая строка
 if (freq<1000){lcd.print(freq); // Выводится обозначение частоты "Hz" есесли частота меньше 1000Hz
 lcd.print("Hz");}
 if ((freq>=1000)&&(freq<1000000)){lcd.print(freq / 1000); // Выводится обозначение частоты "kHz" есесли частота больше 1000 и меньше 1000000 Hz
 lcd.print("kHz");}

 //Дробим МегаГерцовый диапозон. Мне надо шагать не более чем 1Гц от 1000000 Гц (1МГц)до 1999999 Гц (1,999999МГц)----------------------
 if ((freq>=1000000)&&(freq<2000000)){lcd.print(freq); //выводит на дисплей частоту от 1000000 Гц (1МГц)до 1999999 Гц (1,999999МГц)
 lcd.print("Hz");} // выводит на дисплей обозначение частоты в Hz
 //------------------------------------------------------------------------------------------------------------------------------------------
 if ((freq>=2000000)&&(freq<50000000)){lcd.print(freq / 1000000);
 lcd.print("MHz");}
 lcd.setCursor(0,1); // //Устанавливаем курсор на вторую строчку , где задаем 0- слева отступаем ноль символов считая с левой стророны и 1 -вторая строка.
 lcd.print(" Arduino+AD9850"); // Текст второй (нижней) строки. Пробелами от ковычек до символов делаем отступ от левого края.

 // Управление генератором AD9850------------------------------------------------------------------------------------------------------------ 
 if (freq<100){bigStep = 10; // Определение шага грубой-bigStep 10Hz
 littleStep = 1;} //Определение шага точной-littleStep 1Hz
 
 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;}
 //в диаппозоне от 1МГц до 2МГц мне надо шагать помельче. В данном случае шаг 1Гц кнопками лево/право.
  if ((freq>=1000000)&&(freq<2000000)){bigStep = 100000; // если частота больше или равна 1,00МГц и меньше 2,00МГц большой шаг 100КГц кнопи ввер/вниз
  littleStep = 1;} // мелкий шаг 1 это 1Гц кнопки в лево/вправо Если заменить на littleStep = 10;} шагать будет 10Гц Если littleStep = 100;} шагает 100Гц  и т.д.

 if ((freq>=2000000)&&(freq<10000000)){bigStep = 1000000; // если частота больше или равна 2,00МГц и меньше 10,00МГц
  littleStep = 10000;} // мелкий шаг  10000 это 10кГц
 
 if ((freq>=10000000)&&(freq<40000000)){bigStep = 10000000; // если частота больше или равна 10,00МГц
 littleStep = 100000;} // мелкий шаг 100000 это 100кГц
 ------------------------------------------------------------------------------------------------------------------------------------------
 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; //я установил максимум 40МГц
 sendFrequency(freq);  // Вызов функции отправки частоты
 delay (200); // Пауза 200 мс
}
AVGN
Offline
Зарегистрирован: 10.10.2016

Поделюсь и я.

Генератор частоты на Arduino (Atmega328, 16MHz) + AD9850 с выводом информации на дисплей Nokia 5110
2-а диаппазона:
1-й 1,0 Hz - 1000,0 kHz
2-й 1000,0 - 40000,0 kHz

Шаг регулировки частоты:
0 = 1,0000 kHz
1 = 0,1000 kHz
2 = 0,0100 kHz
3 = 0,0010 kHz
4 = 0,0001 kHz

Для управления частотой генератора используется энкодер типа Rotary Encoder KY-040

Что куда подключать - комментарии в скетче. Схема пока в голове надо начертить.

/*
Генератор частоты на Arduino (Atmega328, 16MHz) + AD9850 с выводом информации на дисплей Nokia 5110
2-а диаппазона:
1-й 1,0 Hz - 1000,0 kHz
2-й 1000,0 - 40000,0 kHz 

Шаг регулировки частоты:
0 = 1,0000 kHz
1 = 0,1000 kHz
2 = 0,0100 kHz
3 = 0,0010 kHz
4 = 0,0001 kHz

Для управления частотой генератора используется энкодер типа Rotary Encoder KY-040 с подтягтвающими резисторами 10 кОм установленными на плате энкодера.
Паралельно вывходам энкодера,для устранения дребезга, на ножки котроллера 2,12,3 установить неполярные конденсаторы 10пФ.  
Вывод информации на ЖК дисплей Nokia 5110
За основу взят скетч Автор seawar http://cxem.net/cb/1-110.php
Скетч для ардуино на мк atmega328 (UNO,Nano, MiniPro 16MHz) переаботан для генартора, скомпилирован Arduino 1.6.8, протестирован на Arduino nano (Atmega328, 16MHz). 
AVG 08-10-2016
*/


// подключаем для Nokia 5110 библиотеку LCD5110_SSVS качаем отсюда https://github.com/ssvs111/ARDUINO-LCD-NOKIA5110-SSVS-RUS , содержит русский шрифт,  инструкция для библиотеки на русском.
#include <LCD5110_SSVS.h>        // Бибилиотека для подключения Nokia 5110 по ЧЕТЫРЕМ контактам к котроллеру. пример: 0→CLK,1→DIN,14→DC,5→RST, остальные GND→минус(общий провод), LIGHT→подсветка(можно не подлючать если не нужна),VCC→ +3,3V, CE→ минус(общий провод) 
extern uint8_t SmallFont[];      // Размер шрифта из библиотеки, объявить массив шрифта в качестве внешнего или включить его в свой скетч
extern uint8_t MediumNumbers[];  // Размер шрифта из библиотеки, объявить массив шрифта в качестве внешнего или включить его в свой скетч
extern uint8_t RusFont[];        // Подключаем русский шрифт //размер шрифта из библиотеки, объявить массив шрифта в качестве внешнего или включить его в свой скетч
LCD5110 lcd(4, 5, 6, 7);         // Объявляем контакты на Ардуино для подключения Nokia 5110 4→CLK,5→DIN,6→DC,7→RST
//lcd.setContrast(60);           // Контрастность в % дисплея Nokia 5110. Если закомментировать, то по умолчанию будет 70%


#define pin_A 2    // Контакт 2 для подключения энкодера - поворот энкодера
#define pin_B 12   // Контакт 12 для подключения энкодера - направление вращения энкодера
#define pin_sw 3   // Контакт 3 для подключения кнопки энкодера

#define RESET 8    // Контакт 8  - вход сброса модуля AD9850 (RST)
#define FQ_UD 9    // Контакт 9  - вход обновления частоты модуля AD9850 (FQ)
#define W_CLK 10   // Контакт 10 - стробирующий вход модуля AD9850 (CLK)
#define DATA 11    // Контакт 11 - вход последовательных данных модуля AD9850 (D7)

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

#define band_select 13     // Контакт 13 - подключаем кнопку переключателя диапазонов, второй контакт кнопки на общий провод.
#define bands_number 2     // Количество диапазонов 2 .

const float band[bands_number*2] = 
{
                                    0.001, 1000.0,     // Частота диапазона №2 переключается с диапазона №1 когда кнопка нажата - подаем землю "-" на 13 контакт (светодиод на ардуине потухнет).
                                    1000.0, 40000.0  // Частота диапазона №1 от 1000.0 до 40000.0 кГц запускается при включении ардуино.
};
byte current_band;         // номер текущего диапазона
//double Frequency;        // частота генератора , закомментировал что то не нравятся мне даблы
float Frequency;           // частота генератора , что то не нравятся мне даблы поэтому float
float change_step = 1.0;   // устанавливаем шаг изменения частоты генератора - 1.0 кГц
byte tuning_flag = 0;
volatile byte flag_interrupt_turn = 0;
volatile byte flag_interrupt_button = 0;
 
void setup()
{  
  pinMode(pin_A, INPUT);             // для чтения с выхода А энкодера
  //digitalWrite(pin_A, HIGH);       // включаем подтягивающий резистор, если его нет на энкодере
  pinMode(pin_B, INPUT);             // для чтения с выхода В энкодера
  //digitalWrite(pin_B, HIGH);       // включаем подтягивающий резистор, если его нет на энкодере
  pinMode(pin_sw, INPUT);            // для чтения с кнопки энкодера
  //digitalWrite(pin_sw, HIGH);      // включаем подтягивающий резистор, если его нет на кнопке SW энкодера
  pinMode(FQ_UD, OUTPUT);            // для выдачи на модуль AD9850
  pinMode(W_CLK, OUTPUT);            // для выдачи на модуль AD9850
  pinMode(DATA, OUTPUT);             // для выдачи на модуль AD9850
  pinMode(RESET, OUTPUT);            // для выдачи на модуль AD9850
  pinMode(band_select, INPUT);       // для чтения с переключателя диапазонов
  digitalWrite(band_select, HIGH);   // включаем подтягивающий резистор для кнопки переключения диапазонов
  pulseHigh(RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);                  // разрешение последовательного режима AD9850

// *************************************************************************************************************** 
//Делаем заставку и выводим на Nokia 5110 при старте. Экран с разрешением 84х48 пикселей мы можем выводить шрифт SmallFont до 6 строк по 14 символов. высота стандартного шрифта 8 точек, поэтому строки должны идти с интервалами через 8: 0,8,16,24,32,40
  lcd.InitLCD();  // инициализация дисплея Nokia 5110
  lcd.clrScr();   // очищаем весь дисплей Nokia 5110
  
//Вывод первой строчки, высота стандартного шрифта 8 точек, поэтому строки текста должны идти с интервалами через 8 точек: 0 -1я строка, 8 -2-я строка, 16 -3я строка, 24 -4я строка, 32 -5я строка, 40 -6я строка
//  lcd.setFont(SmallFont);             //устанавливам шрифт мелкий
   lcd.setFont(RusFont);                //устанавливам русский шрифт RusFont
    lcd.print("UTYTHFNJH", CENTER, 0);  // слово "ГЕНЕРАТОР" печатаем англиским шрифтом клавиатуру на EN. Выводим в первой строке дисплея по центу.

//Вывод второй строчки
  lcd.setFont(SmallFont);                  //устанавливам шрифт мелкий
    lcd.print("Arduino 328", CENTER, 8);   //выводим в 8-й строке дисплея по центу.
  
//Вывод третьей строчки
    lcd.print("+", CENTER, 16);   //выводим в 16-й строке дисплея по центу. Если пишем LEFT -слева
 
//Вывод четвертой строчки
    lcd.print("AD9850", CENTER, 24);   //выводим в 24-й строке дисплея по центу.

//Вывод пятой строчки
  lcd.setFont(RusFont); //устанавливам русский шрифт RusFont
    lcd.print("1Uw - 1000 rUw",CENTER, 32);  //выводим 1Гц-1000кГц в 32-й строке дисплея по центру
  
//Вывод шестой строчки
     lcd.print("VUw", 66, 40);  //выводим МГц в 40-й строке дисплея начиная с 58-й точки дисплея . Отступил 58 точек -эксперементально определил. ширина символа 6точек*9символа =54
     lcd.setFont(SmallFont);
     lcd.print("1,0 - 2,0", 0, 40);  //выводим в 40-й строке дисплея начиная с 3-го символа. ширина символа 6точек*2символа =12  
    
   delay(3000);                  // 3000 миллисекунд показываем текст указанный выше при старте.
// Закончили вывод заставки при старте Ардуино.
// *************************************************************************************************
  
  current_band = digitalRead(band_select);
  Frequency = band[current_band*2];          // Задаем частоту диапазона N1 при первом включении Ардуино. было: Frequency = band[current_band*2] + (band[current_band*2+1]-band[current_band*2])/2;// середина текущего диапазона
  sendFrequency(Frequency*1000);             // Начальная установка частоты AD9850 в Гц
  lcd_print_frequency();                     // Инициализация lcd_print_frequency .
  attachInterrupt(0, enc_turn, FALLING);     // Выход А энкодера подключен к пин 2 (int 0). Ожидаем срез импульса
  attachInterrupt(1, enc_button, FALLING);   // Выход кнопки энкодера подключен к пин 3 (int 1). Ожидаем срез импульса
} 
 
void loop()
{
 if(flag_interrupt_turn)
   check_flag_turn();
 if(flag_interrupt_button)
   check_flag_button();
 if (current_band != digitalRead(band_select))   // Если переключился диапазон
   {
    delay(3);
    current_band = digitalRead(band_select);
    Frequency = band[current_band*2];   // устанавливаем начальную частоту текущего диапазона. можно поставить середину если записать так: Frequency = band[current_band*2] + (band[current_band*2+1]-band[current_band*2])/2;// середина текущего диапазона
    sendFrequency(Frequency*1000);      // установка частоты AD9850 в Гц
    lcd_print_frequency();              // выводим частоту на дисплей
   }
}

void enc_turn()     // обработчик прерываний от вращения энкодера
{
  noInterrupts();   // запрет прерываний во избежание дребезга
  flag_interrupt_turn = 1;
  return;
}

void enc_button()   // обработчик прерываний от кнопки энкодера
{
  noInterrupts();   // запрет прерываний во избежание дребезга
  flag_interrupt_button = 1;
  return;
}

void check_flag_turn()       // проверка флага вращения энкодера
{
    delay(2);                // задержка перед обработкой прерывания для избежания дребезга
    if(digitalRead(pin_A))   // если выход А высокий, значит прерывание ложное
      {
        flag_interrupt_turn = 0;
        interrupts();  // разрешение прерываний
        return;
      }
    current_band = digitalRead(band_select);  // считываем текущий диапазон 
    if(digitalRead(pin_B))
      {
        // выход В в сост. 1, значит, вращение по часовой стрелке, увеличиваем не более чем до верхней границы диапазона
        if(Frequency + change_step <= band[current_band*2+1]) Frequency += change_step;
          else Frequency = band[current_band*2+1] ;              
      }   
    else 
      {
         // выход В в 0 сост., значит, вращение против часовой стрелки ,уменьшаем, но не ниже нижней границы диапазона
         if(Frequency - change_step >= band[current_band*2]) Frequency -= change_step; 
           else Frequency = band[current_band*2] ;               
      }
    sendFrequency(Frequency*1000);   // Установка новой частоты AD9850
    lcd_print_frequency();
    flag_interrupt_turn = 0;
    interrupts();    // разрешение прерываний
    return;
}

void check_flag_button()      // проверка флага кнопки энкодера
{
    delay(2);                 // задержка перед обработкой прерывания для избежания дребезга
    if(digitalRead(pin_sw))   // если выход кнопки высокий, значит прерывание ложное
      {
        flag_interrupt_button = 0;
        interrupts();   // разрешение прерываний
        return;
      }
      
// **** переключение диапазонов точной настройки кнопкой энкодера.   
    if (++tuning_flag > 4)
      tuning_flag = 0;
    switch(tuning_flag)
    {
      case 0:                   // Режим 0
        change_step = 1.0;      // Шаг настройки 1,0кГц
        break;  
      case 1:                   // Режим 1
        change_step = 0.1;      // Шаг настройки 100,0Гц
        break;
      case 2:                   // Режим 2
        change_step = 0.01;     // Шаг настройки 10,0Гц
        break;  
      case 3:                   // Режим 3
        change_step = 0.001;    // Шаг настройки 1,0Гц
        break;
      case 4:                   // Режим 4
        change_step = 0.0001;   // Шаг настройки 0,1Гц
        break;    
    } 
    

 // ***** Выводим информацию показания точной настройки на дисплей Nokia 5110. Экран с разрешением 84х48 пикселей мы можем выводить шрифтом SmallFont Размер символов:  6x8 точек, до 6 строк по 14 символов
    //lcd.clrScr(); //очищаем дисплей Nokia 5110
    //или
    //clrRow(8, [start], [40]) //очистка выбранной строки номер row, от позиции start до end;
    
//Вывод во втророй строчке, первая занята под вывод частоты генератора. Высота стандартного шрифта 8 точек, поэтому строки должны идти с интервалами через 8: 0,8,16,32,40
  lcd.setFont(RusFont);         // Применить русский шрифт RusFont для нижеследующей информации.
    lcd.print("Ifu",LEFT,8 );   // Выводим слово "Шаг" в 8-й строке дисплея начиная с лева
    lcd.print("rUw", RIGHT, 8); // Обозначение индикации режима точной настройки в кГц выводим в 8-й строке дисплея равнение с права.
  lcd.setFont(SmallFont);       // Применить шрифт  -млкий.
    lcd.printNumF( ((float)change_step),4 ,18, 8);   //индикация режима точной настройки выводим 4-е знака после запятой в 8-й строке дисплея начиная с 4-го символа. ширина символа 6точек*3символа =18
    
//Вывод третьей строчки
    lcd.printNumI(tuning_flag, LEFT, 16); // Индикация режима номер шага от 0 до 4 точной настройки выводим в 16-й строке дисплея начиная слева
    lcd.print("*************", 6, 16);    // Украшательства

// Украшательства, заполняем пустые строчки Nokia 5110    
//Вывод четвёртой строчки
  lcd.setFont(RusFont); //устанавливам русский шрифт RusFont
    lcd.print("UTYTHFNJH", CENTER, 24 ); // слово "ГЕНЕРАТОР" печатаем переключив клавиатуру на EN. Выводим в 24 строке дисплея по центу.
     
//Вывод пятой строчки  
    lcd.print("1Uw - 1000 rUw",CENTER, 32);  //выводим диапазон 1Гц-1000кГц в 32-й строке дисплея по центру
  
//Вывод шестой строчки
    lcd.print("VUw", 66, 40);        // Выводим МГц в 40-й строке дисплея начиная с 10-го . ширина символа 6точек*9символа =54 точно получилось 58 точек
    lcd.setFont(SmallFont);          // Применить шрифт  -млкий.
    lcd.print("1,0 - 2,00", 0, 40);  // Выводим в 40-й строке дисплея начиная с 3-го символа. ширина символа 6точек*2символа =12 
// закончили украшательства
    
    flag_interrupt_button = 0;
    interrupts(); // Разрешение прерываний
    return;
}

// *******************************************************
void lcd_print_frequency()   // Вывод частоты генератора на Nokia 5110
{
  
lcd.clrScr();   // Очищаем экран Nokia 5110;
//lcd.clrRow(row, [start], [end]);   // Очистка выбранной строки номер row, от позиции start до end;

//Вывод в первой строчке Nokia 5110, Высота стандартного шрифта 8 точек, поэтому строки должны идти с интервалами через 8: 0,8,16,32,40
  lcd.setFont(SmallFont);                   // Применить шрифт, ширина символа 6точек, для вывода на Nokia 5110 нижеледующей информации. 
     lcd.printNumF(Frequency,4 ,LEFT, 0);   // Частота сигнала 4-е знака после запятой выводим в первой строке начиная слева. //printNumF(num, dec, x, y, [divider], [length], [filler]); //вывести число с плавающей запятой; dec – число знаков после запятой; divider – знак десятичного разделителя, по умолчанию точка ".";
  lcd.setFont(RusFont);                     // Применить русский шрифт RusFont для нижеследующей информации.
     lcd.print("rUw", RIGHT, 0);            // Индикация измерения частоты в кГц выводим в 1-й строке дисплея равнение справа.

// подключаем вывод точной настройки и номера режима точной настройки на Nokia 5110
//Вывод во втророй строчке, первая занята под вывод частоты генератора. Высота стандартного шрифта 8 точек, поэтому строки должны идти с интервалами через 8: 0,8,16,32,40
    lcd.print("Ifu",LEFT,8 );                        // Выводим слово Шаг в 8-й строке дисплея начиная с лева
    lcd.print("rUw", RIGHT, 8);                      // Обозначение индикации режима точной настройки в кГц выводим в 8-й строке дисплея равнение с права.
  lcd.setFont(SmallFont);                            // Выставляем шрифт  -млкий.
    lcd.printNumF( ((float)change_step),4 ,18, 8);   // Индикация режима точной настройки 4-е знака после запятой выводим в 8-й строке дисплея начиная с 18-го символа. ширина символа 6точек*3символа =18 

//Вывод третьей строчки
    lcd.printNumI(tuning_flag, LEFT, 16);            // Индикация номера от 0 до 4 точной настройки выводим в 16-й строке дисплея начиная слева
    lcd.print("*************", 6, 16);               // Украшательства

// Украшательства
//Вывод четвёртой строчки
  lcd.setFont(RusFont);                              // Устанавливам русский шрифт RusFont
    lcd.print("UTYTHFNJH", CENTER, 24 );             // Слово "ГЕНЕРАТОР" печатаем переключив клавиатуру на EN. Выводим в 24 строке дисплея по центу.
     
//Вывод пятой строчки
    lcd.print("1Uw - 1000 rUw",CENTER, 32);          // Выводим 1Гц-1000 кГц в 32-й строке дисплея по центру
  
//Вывод шестой строчки
     lcd.print("VUw", 66, 40);                       // Выводим МГц в 40-й строке дисплея начиная с 60-й точки/ подобрал визуально . ширина символа 6точек*9символа =54
     lcd.setFont(SmallFont);
     lcd.print("1,0 - 2,00", 0, 40);                 // Выводим в 40-й строке дисплея начиная с 12-го символа. ширина символа 6точек*2символа =12 

// Закончили украшательства

}

// **************************AD9850*****************************************************
void tfr_byte(byte data)// последовательная передача байта в модуль AD9850 на вход DATA
{
  for (int i=0; i<8; i++, data>>=1)
  {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //строб каждого бита
  }
}
 
void sendFrequency(float frequency)// расчет и передача управляющего 32 битного числа "frequency tuning word"
                                    //для задания частоты: frequency = <sys clock> * <frequency tuning word>/2^32
{
  //unsigned long freq = frequency * 4294967295/125000000;  // расчет числа. частота домножается на 4294967295 / 125000000 = 34.35973836 и 34.35973836^-1 = 0.02910383 или 1/34.35973836 = 0.02910383
  int32_t freq = frequency * 0.99999890 * 4294967295/125000000;  // мой модуль AD9850 расчет числа, поправка для конкретного экземпляра платы
  //unsigned long freq = frequency * 1.00000965 * 4294967295/125000000;  // расчет числа, 1.00000965 - поправка для конкретного экземпляра платы

 //int32_t freq = frequency * 4294967296/180000000; // Для тактовой 180 МГц на AD9851. Можно слегка поиграться значением для более точной настройки.
  
  for (int b=0; b<4; b++, freq>>=8)                                 
   {
    tfr_byte(freq & 0xFF);   //передача числа в AD9850
   }
  tfr_byte(0x000);           // завершающий байт, все 0 для AD9850
  // tfr_byte(0x001);        // Завершающий байт последовательности, 1 для AD9851
  pulseHigh(FQ_UD);          // строб новой частоты
}

.

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

AVGN, здорово! Работает!

MagicianT
Offline
Зарегистрирован: 03.10.2015

Не обманывайте пользователя, шаг не может быть меньше 0.029, обсуждалось выше

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

AVGN супер работа, весь скетч в комментариях (отдельное СПАСИБО!) да еще и русифицировал!

MagicianT, ты про что? в мануале речь идет про шаг 0.0291 Hz, а скетч AVGN  минимальный шаг 0,1Hz. Дедушка MINING подтвердил, а он как СОВЕТСКИЙ ☭ РАДИОЛЮБИТЕЛЬ И ИНЖЕНЕР ошибок не допускает☝

MagicianT
Offline
Зарегистрирован: 03.10.2015

Я про фото в посте 19, там шаг 0.0001.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

MagicianT, аффтар не парился, и всё выводит в килогерцах :)))

MagicianT
Offline
Зарегистрирован: 03.10.2015

Оппс, я и не заметил. Юзер интерфейс надо доработать, а то понапишут кГц, ГГц, а ты сиди и нули подсчитывай. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Ivan_Kornege пишет:

AVGN супер работа, весь скетч в комментариях (отдельное СПАСИБО!) да еще и русифицировал!

MagicianT, ты про что? в мануале речь идет про шаг 0.0291 Hz, а скетч AVGN  минимальный шаг 0,1Hz. Дедушка MINING подтвердил, а он как СОВЕТСКИЙ ☭ РАДИОЛЮБИТЕЛЬ И ИНЖЕНЕР ошибок не допускает☝

 

Да, откомпилировалось слёту в версии 1.6.5, библиотеку доставлял стандартными средствами, заимствовал по ссылке в скетче )))

Только сегодня приехал сей девайс, вечером буду пытать, посмотрим что на С1-65 покажет на 40 мегагерцах

УПС один девайс битый, жрёт 330ма, греется, на выходе по нулям
Кстати, в фунции ввода частоты разве не надо умножать прямо на коэффициент???
 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em, коротышей нет? Когда ко мне приехала платка ad9851 и я её взял в руки -то был в шоке, такое ощущение, что кто-то на ней учился паять, про смыв флюса уже не говорю.. это само собой. Купил -промой:)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em, коротышей нет? Когда ко мне приехала платка ad9851 и я её взял в руки -то был в шоке, такое ощущение, что кто-то на ней учился паять, про смыв флюса уже не говорю.. это само собой. Купил -промой:)

Глаза уже не те, сам чип припаян качественно, а вот всё остальное паяли в сарае, сомнение именно в том, что чип сильно разогревается, как бы не просадили статикой при пайке

Второй раз нахожу столь непонятное соединение выводов модуля, вопрос - с какой целью это сделано?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em, в даташите было какое-то упоминание на сей счёт, лень смотреть. Но вроде суть в том, что для последовательного доступа нужно какие-то лапки подтянуть к питанию. Здесь видимо их просто повесили на +5, а лишние входы на землю.

AVGN
Offline
Зарегистрирован: 10.10.2016

Версия с библиотекой AD9850SPI.h

Нажимая кнопку экодера переключаем шаг перестройки AD9850^
1,0 МГц
100,0 КГц
10,0 КГц
1,0 КГц
100,0 Гц
10,0 Гц
1,0 Гц
0,1 Гц

AD9850

/*
  Компилируется в IDE 1.8.1.
В железе проект проверн 01-04-2017.
НЕ ШУТКА )))
Генератор сигналов на AD9850
0 Гц - 9,99МГц
Блок управления AD9850 с бибилотекой AD9850SPI.h (AD9850SPI-master) 
Библиотека отсюда https://github.com/F4GOJ/AD9850SPI 
Чертил как мог AVGN

Подключение блока 
HC-SR08 AD9850
*********************
Выводы блока AD9850:
D0 и D1 подать +5V 
D2 и Reset замкнуть на GND
*********************************
Arduino nano -> AD9850
D13      ->        W_CLK 
15        ->        FQ_UD //A1 Arduino
D11      ->        DATA    
16        ->        RESET //A2 Arduino

Энкодер KY-040
Импульсов на щелчок ставим 4
Подключается к пинам поддерживающие прерывания:
UNO - Pin 2,3
Переключение шага частоты кнопкой энкодера. Подключается к А0 Ардуино.
На А7 подключаем светодиод для индикации нажатия кнопки энкодера.
Нажимая кнопку экодера переключаем шаг перестройки AD9850^
1,0 МГц
100,0 КГц
10,0 КГц
1,0 КГц
100,0 Гц
10,0 Гц
1,0 Гц
0,1 Гц
 */

#include <LCD5110_Graph.h>

#include <TimerOne.h>

#include <SPI.h>

#include <AD9850SPI.h>

int Pulses;
int Data=0;
volatile byte New=0;
volatile int EncData=0; 
volatile byte EncState=0;
float ZQ_Freq;
float freq;
byte phase;
float trimFreq;
bool EN;
String Text1;
int Str1;
String Text2;
int Str2;
String Text3;
int Str3;
String Text4;
int Str4;
String Text5;
int Str5;
String Text6;
int Str6;
LCD5110 myGLCD( 4 , 5 , 6 , 8 , 7 );
extern uint8_t SmallFont[];
float _gtv1 = 1000000; //Устанавлиаем частоту при включении Ардуино
byte _gtv3 = 0; //Фаза AD9850
bool _gtv2; //Энкодер крутится Вправо
bool _gtv4; //Энкодер крутится Влево
bool _gtv6; //Сброс переключателя выборв шаг частоты
int _gtv7; //Сигнал для переключателя  -выбор шаг частоты
float _gtv8; //Шаг частоты
String _gtv9 = " ГЕНЕРАТОР"; //Выводим на 5110 в первой строке по центру ГЕНЕРАТОР
String _gtv10 = " Arduino 328"; //Выводим на вторую строку 5110  "Arduino 328"
String _gtv11 = "AD9850"; //Выводим  на 5110 в четвертой строке  AD9850 
String _gtv12 = "+"; //Выводим на 5110 в третьей строке +
String _gtv13 = "0Гц - 1000 кГц"; //Выводим на 5110 в пятой строке 1Гц-1000кГц
String _gtv14 = "1,0 - 9,99 МГц"; //Выводим на 5110 в шестой строке 1,0 - 9,99 МГц
bool _gtv15 = 0; //Включаем заставку
String _gtv16;
String _gtv17;
String _gtv18;
String _gtv19;
String _gtv20;
String _gtv21;
int _gtv22;
int _gtv23;
int _gtv24;
int _gtv25;
int _gtv26;
int _gtv27;
bool _gtv28;
bool _gtv29;
bool _gtv31;
bool _gtv32;
float _gtv33 = 9999999; //Ограничиваем вырхний предел частоты 9,99 МГц
String _gtv34;
bool _gtv35;
bool _gtv36;
bool _trgrt2 = 0;
bool _trgrt2I = 0;
int _swi18;
String _swi19;
bool _bounseInputA0S = 0;
bool _bounseInputA0O = 0;
unsigned long _bounseInputA0P = 0UL;
bool _tim1I = 0;
bool _tim1O = 0;
unsigned long _tim1P = 0UL;
bool _trgrt3 = 0;
bool _trgrt3I = 0;
String _GSFS10 = "0";
String _GSFS1 = "0";
bool _count2I = 0;
int _count2P = 0;
String _GSFS2 = "0";
bool _swi3;
bool _swi4;
String _GSFS3 = "0";
String _swi9;
String _swi10;
String _GSFS4 = "0";
bool _trgrt1 = 0;
bool _trgrt1I = 0;
bool _swi12;
String _GSFS5 = "0";
String _GSFS6 = "0";
float _mux2;
int _swi1;
String _GSFS7 = "0";
String _GSFS8 = "0";
int _swi2;
int _swi5;
bool _swi20;
String _swi11;
String _swi6;
String _swi13;
String _swi16;
float _swi15;
float _swi17;
String _swi7;
String _swi14;
String _swi8;
void setup()
{
pinMode(14, INPUT);
digitalWrite(14, HIGH);
pinMode(21, OUTPUT);

_bounseInputA0O =  digitalRead(14);
Timer1.initialize(1000);         // инициализировать timer1
Timer1.attachInterrupt(EncoderScan);





//W_CLK - D13, FQ_UD - 15,  DATA - 11, RESET - 16
 DDS.begin(13, 15, 16);
  myGLCD.InitLCD( 60 );
  myGLCD.setFont(SmallFont);
}
void loop()
{
bool  _bounceInputTmpA0 =  (digitalRead (14));

if (_bounseInputA0S) 
    {
     if (millis() >= (_bounseInputA0P + 40)) 
         {_bounseInputA0O= _bounceInputTmpA0; _bounseInputA0S=0;}
     }
else
    {
     if (_bounceInputTmpA0 != _bounseInputA0O )
         {_bounseInputA0S=1; _bounseInputA0P = millis();} 
      } 




//Плата:1
//Наименование:Направление вращения энкодера
noInterrupts();
Data+= EncData ;
EncData=0;
interrupts();
if ((Data >=4)||(Data<=-4) ){
 	Pulses = Data / 4 ;
	Data = 0;
}
else {Pulses=0;}

_gtv2 = (Pulses) > (0L);
_gtv4 = (Pulses) < (0L);

//Плата:2
//Наименование:Выбор шага
if (_bounseInputA0O) { if (_trgrt3I) { _trgrt3 = 0;} else {_trgrt3 = 1; _trgrt3I = 1;} } else {_trgrt3 = 0; _trgrt3I = 0;}; 
 
if (_trgrt3) 
   { 
   if (! _count2I)  
      {
       _count2P = _count2P+1;
       _count2I = 1;
      }
   }
else
   {
   _count2I=0;
   }
if (( (_trgrt2) || (_gtv6) )) _count2P = 0;
if (1) { if (_trgrt2I) { _trgrt2 = 0;} else {_trgrt2 = 1; _trgrt2I = 1;} } else {_trgrt2 = 0; _trgrt2I = 0;}; 
 _gtv7 = _count2P;
_gtv6 =  _count2P  >=  (8);

//Плата:3
//Наименование:Частота
if((_gtv7) == 0) {_mux2 = 1000000.00;}
if((_gtv7) == 1) {_mux2 = 100000.00;}
if((_gtv7) == 2) {_mux2 = 10000.00;}
if((_gtv7) == 3) {_mux2 = 1000.00;}
if((_gtv7) == 4) {_mux2 = 100.00;}
if((_gtv7) == 5) {_mux2 = 10.00;}
if((_gtv7) == 6) {_mux2 = 1.00;}
if((_gtv7) == 7) {_mux2 = 0.1;}
if((_gtv7) == 8) {_mux2 = 0.00;}
if (_gtv2) {
_gtv1 = (_gtv1)+(_gtv8);
}
if (_gtv4) {
_gtv1 = (_gtv1)-(_gtv8);
}
_gtv8 = _mux2;

//Плата:4
//Наименование:Частота всегда больше или равна нулю и не более 9,99 МГц
if ((_gtv1) < (0.00)) {
_gtv1 = 0.00;
}
if ((_gtv1) > (_gtv33)) {
_gtv1 = _gtv33;
}

//Плата:5
//Наименование:Управление генератором
ZQ_Freq = 125000000.00;
freq = _gtv1;
phase = _gtv3;
DDS.calibrate( trimFreq =  ZQ_Freq ); // ZQ_Freq подстройка частоты кварца
DDS.setfreq(freq, phase);

//Плата:6
//Наименование:Заставка
//Комментарии:Включаем заставку на 5 секунд
if (1)
{ if (_tim1I) { if (_isTimer(_tim1P, 5000)) {_tim1O = 1;}} else {_tim1I =1; _tim1P = millis();}} else {_tim1O = 0; _tim1I = 0;}
_gtv15 = _tim1O;

//Плата:7
//Наименование:Дисплей. Старт, настройки входов/выходов.
if (1) { if (_trgrt1I) { _trgrt1 = 0;} else {_trgrt1 = 1; _trgrt1I = 1;} } else {_trgrt1 = 0; _trgrt1I = 0;}; 
 EN = ( (_trgrt1) || (_bounseInputA0O) || (_gtv4) || (_gtv2) );
Text1 = _gtv16;
Str1 = _gtv22;
Text2 = _gtv17;
Str2 = _gtv23;
Text3 = _gtv18;
Str3 = _gtv24;
Text4 = _gtv19;
Str4 = _gtv25;
Text5 = _gtv20;
Str5 = _gtv26;
Text6 = _gtv21;
Str6 = _gtv27;
if (EN==1)
{
    myGLCD.clrScr();
    myGLCD.print ( utf8rus (Text1), Str1, 0);   // Выводим в первой строке дисплея. По центу если 0 заменить на CENTER.
    myGLCD.print ( utf8rus (Text2), Str2, 8);   //Выводим в 8-й строке дисплея. По центу если 0 заменить на CENTER.
    myGLCD.print ( utf8rus (Text3), Str3, 16);   //Выводим в 16-й строке дисплея. По центу если 0 заменить на CENTER.
    myGLCD.print ( utf8rus (Text4), Str4, 24);
    myGLCD.print ( utf8rus (Text5), Str5, 32);
    myGLCD.print ( utf8rus (Text6), Str6, 40);
    myGLCD.update ();
    }
else 
{
myGLCD.clrScr();
}

//Плата:8
//Наименование:Расставляем точки запятые для вывода на LCD
if(_gtv31)
{_swi14=((_GSFS3) + (String(".")) + (_GSFS4) + (String(" КГц")));}
else
{_swi14=((_GSFS10) + (String(".")) + (_GSFS1) + (String(".")) + (_GSFS2) + (String("МГц")));}
if(_gtv35)
{_swi6=((_GSFS5) + (String(".")) + (_GSFS6) + (String(" КГц")));}
else
{_swi6=_swi14;}
if(_gtv36)
{_swi13=((_GSFS7) + (String(".")) + (_GSFS8) + (String(" КГц")));}
else
{_swi13=_swi6;}
if(_gtv32)
{_swi19=((( _floatToStringWitRaz(_gtv1,1))) + (String(" Гц")));}
else
{_swi19=_swi13;}
_GSFS10 = (( _floatToStringWitRaz(_gtv1,1))).substring(0, 1);
_GSFS1 = (( _floatToStringWitRaz(_gtv1,1))).substring(1, 4);
_GSFS2 = (( _floatToStringWitRaz(_gtv1,1))).substring(4);
_GSFS3 = (( _floatToStringWitRaz(_gtv1,1))).substring(0, 3);
_GSFS4 = (( _floatToStringWitRaz(_gtv1,1))).substring(3);
_GSFS5 = (( _floatToStringWitRaz(_gtv1,1))).substring(0, 2);
_GSFS6 = (( _floatToStringWitRaz(_gtv1,1))).substring(2);
_GSFS7 = (( _floatToStringWitRaz(_gtv1,1))).substring(0, 1);
_GSFS8 = (( _floatToStringWitRaz(_gtv1,1))).substring(1);
_gtv34 = _swi19;

//Плата:9
//Наименование:Дисплей. Схема формирования сигналов для вывода на дисплей
//Комментарии:Заставка, дизайн, вывод информации генератора
if(_gtv28)
{_swi15=(_gtv8)/(1000L);}
else
{_swi15=(_gtv8)/(1000000L);}
if(_gtv29)
{_swi17=_gtv8;}
else
{_swi17=_swi15;}
if(_gtv15)
{_swi11=_gtv34;}
else
{_swi11=_gtv9;}
if(_gtv15)
{_swi1=0;}
else
{_swi1=9998;}
if(_gtv28)
{_swi7=String(" КГц");}
else
{_swi7=String(" МГц");}
if(_gtv29)
{_swi8=String(" Гц");}
else
{_swi8=_swi7;}
if(_gtv15)
{_swi9=((String("Шаг ")) + (( _floatToStringWitRaz(_swi17,1))) + (_swi8));}
else
{_swi9=_gtv10;}
if(_gtv15)
{_swi2=0;}
else
{_swi2=9998;}
if(_gtv15)
{_swi10=String("****FLProg****");}
else
{_swi10=_gtv12;}
if(_gtv15)
{_swi5=0;}
else
{_swi5=9998;}
if(_gtv15)
{_swi16=_gtv9;}
else
{_swi16=_gtv11;}
if(_gtv15)
{_swi18=9;}
else
{_swi18=9998;}
_gtv16 = _swi11;
_gtv22 = _swi1;
_gtv17 = _swi9;
_gtv23 = _swi2;
_gtv18 = _swi10;
_gtv24 = _swi5;
_gtv19 = _swi16;
_gtv25 = _swi18;
_gtv20 = _gtv13;
_gtv26 = 0;
_gtv21 = _gtv14;
_gtv27 = 0;

//Плата:10
//Наименование:Коммутатор. Какой сигнал ЧАСТОТЫ выводить на дисплей 
if(( ((_gtv1) < (100000.00)) || ((_gtv1) < (10000.00)) || ((_gtv1) < (1000.00)) ))
{_swi12=0;}
else
{_swi12=(_gtv1) < (1000000.00);}
if(( ((_gtv1) < (10000.00)) || ((_gtv1) < (1000.00)) ))
{_swi3=0;}
else
{_swi3=(_gtv1) < (100000.00);}
if((_gtv1) < (1000.00))
{_swi4=0;}
else
{_swi4=(_gtv1) < (10000.00);}
_gtv31 = _swi12;
_gtv35 = _swi3;
_gtv36 = _swi4;
_gtv32 = (_gtv1) < (1000.00);

//Плата:11
//Наименование:Коммутатор. Какой сигнал ШАГА ЧАСТОТЫ выводить на дисплей 
if((_gtv8) < (1000.00))
{_swi20=0;}
else
{_swi20=(_gtv8) < (1000000.00);}
_gtv28 = _swi20;
_gtv29 = (_gtv8) < (1000.00);

//Плата:12
//Наименование:Индикацияя
//Комментарии:Мигает светодиод
digitalWrite(21, !(_bounseInputA0O));




}
String  _floatToStringWitRaz(float value, int raz)
{
 
  return String(value,raz);
}
bool _isTimer(unsigned long startTime, unsigned long period )
  {
  unsigned long currentTime;
currentTime = millis();
if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));}
  }
void EncoderScan()
{
bitWrite(New, 0,digitalRead( 2) );
bitWrite(New, 1, digitalRead( 3 ) );
switch(EncState)
	{
	case 2:
		{
		if(New == 3) EncData++;
		if(New == 0) EncData--; 
		break;
		}
 
	case 0:
		{
		if(New == 2) EncData++;
		if(New == 1) EncData--; 
		break;
		}
	case 1:
		{
		if(New == 0) EncData++;
		if(New == 3) EncData--; 
		break;
		}
	case 3:
		{
		if(New == 1) EncData++;
		if(New == 2) EncData--; 
		break;
		}
	}
 
EncState = New;		
}
String utf8rus(String source)
{
int i,k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };

  k = source.length(); i = 0;

  while (i < k) {
    n = source[i]; i++;

    if (n >= 0xC0) {
      switch (n) {
        case 0xD0: {
          n = source[i]; i++;
          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x30;
          break;
        }
        case 0xD1: {
          n = source[i]; i++;
          if (n == 0x91) { n = 0xB8; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x70;
          break;
        }
      }
    }
    m[0] = n; target = target + String(m);
  }
return target;
}

 

AVGN
Offline
Зарегистрирован: 10.10.2016

ua6em пишет:

Второй раз нахожу столь непонятное соединение выводов модуля, вопрос - с какой целью это сделано?

Так в даташите на AD9850 прописано.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

подключал так - скетч работает - ноги d0-d7 в воздухе - что я неправильно делаю

#define W_CLK 8       // Pin 8 - connect to AD9850 module word load clock pin (CLK)
 #define FQ_UD 9       // Pin 9 - connect to freq update pin (FQ)
 #define DATA 10       // Pin 10 - connect to serial data load pin (DATA)
 #define RESET 11      // Pin 11 - connect to reset pin (RST).

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em, так в модуле все нужные лапы уже подтянуты, так что всё ок.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax - понятно! Глядя на схему не увидел, что это есть!
Еще бы понять, что такое может коротить, что ток жрёт и греется?

Синус конечно шикарный, по картинке на осциллографе КНИ лучше 1%, визуально просто идеальный на 300 Килогерцах, никто не мерял? Мне сейчас нечем

простой тестовый скетч

/* 
 * A simple single freq AD9850 Arduino test script
 * Original AD9851 DDS sketch by Andrew Smallbone at www.rocketnumbernine.com
 * Modified for testing the inexpensive AD9850 ebay DDS modules
 * Pictures and pinouts at nr8o.dhlpilotcentral.com
 * 9850 datasheet at <a data-cke-saved-href="<a data-cke-saved-href="http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf" href="http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf" rel="nofollow">http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf</a>" href="<a data-cke-saved-href="http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf" href="http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf" rel="nofollow">http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf</a>" rel="nofollow"><a data-cke-saved-href="http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf" href="http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf" rel="nofollow">http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf</a></a>
 * Use freely
 * 
 * Взято отсюда, модифицировано - 
 * <a data-cke-saved-href="<a data-cke-saved-href="https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html" href="https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html" rel="nofollow">https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html</a>" href="<a data-cke-saved-href="https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html" href="https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html" rel="nofollow">https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html</a>" rel="nofollow"><a data-cke-saved-href="https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html" href="https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html" rel="nofollow">https://www.riyas.org/2014/02/quickly-test-ad9850-ebay-module-with-arduino-and-software-defined-radio.html</a></a>
 */
 
long fr_1 =200000;     // Устанавливаемая частота

#define W_CLK 10       // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 9        // Pin 9 - connect to freq update pin (FQ)
#define DATA 11        // Pin 10 - connect to serial data load pin (DATA)
#define RESET 8        // Pin 11 - connect to reset pin (RST).
 
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
 
 // transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
  for (int i=0; i<8; i++, data>>=1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }
}

 // frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850
  for (int b=0; b<4; b++, freq>>=8) {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
  pulseHigh(FQ_UD);  // Done!  Should see output
}

void setup() {
 // configure arduino data pins for output
  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 - Datasheet page 12 figure 10
}

void loop() {
  fr_1=200000;
  for (int i=1; i<150; i++)
  {
  //sendFrequency(10.e6);
  fr_1=fr_1+1000;
  sendFrequency(fr_1);
  delay (10);
  }
 // sendFrequency(10.01e6);  // freq
 // sendFrequency(300000);
 delay(1000);
}

 

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em,  внимательно осмотреть, проверить на ляпы под лупой. Всяко бывает, мож там чип задом наперёд припаян..

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em,  внимательно осмотреть, проверить на ляпы под лупой. Всяко бывает, мож там чип задом наперёд припаян..

Дима, ты прав, чип на 180 перевернули, вот это уроды, ну бабки вернут 100%, отфотографирую и на спор поставлю

Morroc
Offline
Зарегистрирован: 24.10.2016

Поделитесь хоть зачем шаг меньше 1 Гц. Там от температуры они десятками гуяют, да и на слух вроде не слышно.

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Morroc пишет:

Поделитесь хоть зачем шаг меньше 1 Гц. Там от температуры они десятками гуяют, да и на слух вроде не слышно.

А зачем производитель сделал шаг перестройки 0.0291 Hz не интересно? Десятками гуляют, когда кварц используешь из поднебесной. Впаяй от приличного производителя и поймёшь разницу.

Хотя забей. Если у тебя уши вместо осциллографа, то тебе это нафиг не надо ))))))

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

ua6em пишет:

dimax пишет:

ua6em,  внимательно осмотреть, проверить на ляпы под лупой. Всяко бывает, мож там чип задом наперёд припаян..

Дима, ты прав, чип на 180 перевернули, вот это уроды, ну бабки вернут 100%, отфотографирую и на спор поставлю

Перепаять и будет пахать. Я сам перепутал. Неправильно воткнул модуль в самапальную панель. Думал пипец. Выдернул ...подул на микруху... вставил как надо ... пашет. Но у китайца можно отжать лавэ за халтуру. Что б впредь неповадно было.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Сомневаюсь! Ток был приличный, подбило стабилизатор на UNO на 3.3 вольта, от него запитывалось
Я же его в прибор ставить буду, там пионерия не нужна

Сегодня посмотрю моим цифровым HANTEK 6022BE сигнал с AD9850, пришёл сегодня оный, первое впечатление весьма и весьма хреновое, конечно осциллограф со стоимостью за мильён наверное прекрасен, а это всё игрушки.
Два канала, но параметры развёртки для обоих одни, видимо коммутатор используется. Это конечно не DSO но
Пока не смог включить открытый вход, может и нет такого режима (((
Жду вечера, что цифирь покажет )))
 

 

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

ua6em пишет:

Сомневаюсь! Ток был приличный, подбило стабилизатор на UNO на 3.3 вольта, от него запитывалось
Я же его в прибор ставить буду, там пионерия не нужна

Сегодня посмотрю моим цифровым HANTEK 6022BE сигнал с AD9850, пришёл сегодня оный, первое впечатление весьма и весьма хреновое, конечно осциллограф со стоимостью за мильён наверное прекрасен, а это всё игрушки.
Два канала, но параметры развёртки для обоих одни, видимо коммутатор используется. Это конечно не DSO но
Пока не смог включить открытый вход, может и нет такого режима (((
Жду вечера, что цифирь покажет )))

это просто микруха на ардуине улетела. Они там слабенькте разве что дисплейчик типа 5110 питать. Я КРЕНку на5 вольт с радиатором использую и при моем косяке от 5 вольт AD9850 не вылетел. Раскалился чип прилично пальцы жег. От 3,3 вольт вообще ничего не будет.

Я брал у китайца хантек DSO 5202P за 12т.р хороший прибор. Но сейчас народ пишет у нас в гандурасе таможня лютуе и обдирает радиолюбителей как липку мля...

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em, снял с ad9851 осцилограммы  40 и 70 MHz  своим осциллом сравните потом :) Кликабельно.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

dimax пишет:

ua6em, снял с ad9851 осцилограммы  40 и 70 MHz  своим осциллом сравните потом :) Кликабельно.

 

Хорошо! На аналоговом синусоида идеальная, неожиданно так, у меня он до 20 мегагерц, на 20 и сниму картинку

300 Кгц )))
Назвать прибором это чудо язык не поворачивается, максимум осциллографический пробник
Оно даже уровень сигнала правильно померять не может (((

Откалибровал, измерил амплитуду, врёт на 0,37 вольта )))

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Morroc пишет:

Поделитесь хоть зачем шаг меньше 1 Гц. Там от температуры они десятками гуяют, да и на слух вроде не слышно.

Не гуляют, сейчас ставят термостабилизированные кварцевые генераторы. Можно часы тактировать - до того точно.

Morroc
Offline
Зарегистрирован: 24.10.2016

В районе или лучше 1 ppm ? Ой не верю, что на тех модулях такие, разве что где то взять или купить и поставить.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Morroc, примерно 2ppm Но что ставят фактически тут конечно "по системе фортуна" :-)

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

ua6em пишет:

Назвать прибором это чудо язык не поворачивается, максимум осциллографический пробник
Оно даже уровень сигнала правильно померять не может (((

Конечно за эти деньги ничего нормального не купить, но можно было их отложить в кубышечку, и поднакопить на человеческий осцилл. Тем более у вас  аналоговый ведь есть, так что потерперть ещё можно.  А так фактически выброшенные деньги получилось.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

вы советские цифровые 80-х годов не видели вот то была жесть )))

аналоговый взял на время на работе до того как взял осцил заказал - горело

ну посмотреть сигнал можно

Ardudue
Offline
Зарегистрирован: 31.08.2016

dimax, Вы случайно не разбирались с функцией сдвига фазы в AD9851?

Можно ли управлять сдвигом фазы с помощью Arduino?

Пытаюсь сделать FM модуляцию на базе AD9851 под управлением Arduino .

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Ardudue, изучал, но практически не использовал, для чего? Приёмники не проверить, у них частоты не те, да и купить фм-трансмиттер за 100руб если что не проблема.  А фазу двигать не трудно, для этого желательно подключить модуль в паралельном режиме,  и после установки частоты отсылать только изменённый первый байт данных, в котором 5  старших бит отвечают за фазу.

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Ardudue пишет:

dimax, Вы случайно не разбирались с функцией сдвига фазы в AD9851?

Можно ли управлять сдвигом фазы с помощью Arduino?

Пытаюсь сделать FM модуляцию на базе AD9851 под управлением Arduino .

Посмотрите здесь

Что получилось у автора https://youtu.be/FJdQhJg-_6k

Пытался разобраться с проектом, но не доковырял

//More info http://zissisprojects.wordpress.com/arduino-sdr-ad9850
// https://zissisprojects.wordpress.com/2014/02/10/all-digital-fm-modulation-w-arduino-ad9850 

#include <SPI.h>
uint32_t frequency = 694000;                  //The desired frequency must be divided by 50 ex. 34,7MHz/50 = 694000
uint32_t tword = frequency * 3436 / 100;      //tuning word calculation
byte W[5] = {0,0,0,0,0};
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);  //these are the prescalers for the ADC sampling rate.
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_16 = (1 << ADPS2);
int mic = 512;

void setup()
          {
            
            DDRB = B01100000;                          //portb has outputs, PB5(may be used for reset) PB6(FU_UD pin)
            PORTB = 0x00;
           // Serial.begin(115200);                    // everything can be controlled by serial comm
             pinMode (A0,INPUT);                       // here comes the audio frequency in
            SPI.setDataMode(SPI_MODE0);                // mode 0 seems to be the right one //Функция устанавливает режим работы шины SPI, задавая уровень сигнала синхронизации и фазу синхронизации. http://arduino.ru/Reference/Library/SPI/setDataMode
            SPI.setClockDivider(SPI_CLOCK_DIV2);       // this is pretty fast //Устанавливает делитель частоты синхронизации SPI к частоте контроллера. http://arduino.ru/Reference/Library/SPI/setClockDivider
            SPI.setBitOrder(LSBFIRST);                 // AD9850 wants LSB first // SPI.setBitOrder(LSBFIRST); -Функция устанавливает порядок вывода даннах в/из шины SPI,  может быть LSBFIRST (наименьший разряд(бит) первый) или MSBFIRST (старший разряд первый). Вывод будет MSBFIRST с первого (левого) бита http://arduino.ru/Reference/ShiftOut
                                                       // http://arduino.ru/Reference/Library/SPI/setBitOrder
            SPI.begin();                               
                                                       // set up the ADC
            ADCSRA &= ~PS_128;                         // remove bits set by Arduino library
            ADCSRA |= PS_32;                           // setting the sampling rate at 16MHz/32 this makes the analogRead() complete in around 40μs
            
          }

void loop()
  {    mic = analogRead(A0);                           //reading the AF signal
       frequency = 694000 + 3*mic-1536;                //this is the Frequency Modulation. Desired frequency is divided by 50 and then around 75khz deviation is calculated depending on the input amplitude
       tword = frequency * 1718;                       //calculating the tuning word for AD9850
              W[0] = (byte) tword;
              W[1] = (byte) (tword >> 8);
              W[2] = (byte) (tword >> 16);             //converting it to bytes
              W[3] = (byte) (tword >> 24);
              W[4] = 0; //phase zero
                                                       //start sending with spi interface
                 PORTB = B01000000;
                 PORTB = 0x00;                         //pulse FU_UD
                for (int j = 0; j<5;j++)
           {
             SPI.transfer(W[j]);                       //send the word
           }
                 PORTB = B01000000;
                 PORTB = 0x00;                         //pulse FU_UD
          
  }