Синтезатор Si5351

ic746
Offline
Зарегистрирован: 04.12.2016

Приветствую всех!

Решил тут синтезатор частоты собрать и заплутал в 3 соснах.

http://www.ur5yfv.com.ua/2018/08/21/%D0%B8%D0%B7-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8F-%D0%BD%D0%B0-si5351a-%D1%81%D0%B8%D0%BD%D1%82%D0%B5%D0%B7%D0%B0%D1%82%D0%BE%D1%80-%D0%B3%D0%B5%D0%BD%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80-%D0%BF-2/

Код:

/*
Вся эта программа изначально написана NT7S и SQ9NJE.
Оригинальный код, немного подправленный мною, под мои нужды.
Ознакомится с оригиналом можно здесь
http://nt7s.com/
http://sq9nje.pl/
http://ak2b.blogspot.com/
*/

#include <Rotary.h>
#include <si5351.h>
#include <Wire.h>
#include <LiquidCrystal.h>

  #define F_MIN        1000000L               // Нижний предел частоты
  #define F_MAX        30000000L              // Верхний предел частоты
  #define OLED_RESET 4
  #define ENCODER_A    3                      // Encoder pin A
  #define ENCODER_B    2                      // Encoder pin B
  #define ENCODER_BTN  11  
  #define LCD_RS    5
  #define LCD_E           6
  #define LCD_D4    7
  #define LCD_D5    8
  #define LCD_D6    9
  #define LCD_D7    10

// переменные нужные для кнопок PRE/ATT
 int regim=1; // для кнопки
 int flag=0;  // для кнопки
  
  LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);       // LCD - pin assignement in 
  Si5351 si5351;
  Rotary r = Rotary(ENCODER_A, ENCODER_B);

// Для кварцевых резонаторов со значением 8867 МГц.  
volatile uint32_t LSB = 886300000ULL; //частота ОГ(гетеродина) для "нижней" боковой. Настр. на ниж. скат КФ.
volatile uint32_t USB = 886700000ULL; //частота ОГ(гетеродина) для "верхней" боковой. Настр. на вверхн. скат КФ.
volatile uint32_t bfo = 886700000ULL; //стартовать с "верхней" ...
//Эти USB/LSB частоты добавляется или вычитается из частоты VFO в "void loop()"
//В этом примере если начальная частота будет 14.20000 плюс 9.001500 то на выходе clk0 = 23.2015Mhz
volatile uint32_t vfo = 710000000ULL / SI5351_FREQ_MULT; //стартовая частота при запуске синтезатора.
volatile uint32_t radix = 100000;  // Шаг перестройки по умолчанию при старте = 100 кГц
boolean changed_f = 0;
String tbfo = "";


//------------------ Установка дополнительных функций здесь  ---------------------------
//Удалить коммент (//) для применения нужного варианта. Задействовать только одно.
#define IF_Offset // Показание на ЖКИ плюс(минус) на значение ПЧ
//#define Direct_conversion // чатота на выходе как на ЖКИ. Прямой выход. Генератор.
//#define FreqX4  // частота на выходе, умноженная на четыре ...
//#define FreqX2  // частота на выходе, умноженная на два ...
//---------------------------------------------------------------------------------------

/**************************************/
/* Interrupt service routine for      */
/* encoder frequency change           */
/**************************************/
ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result == DIR_CW)
    set_frequency(1);
  else if (result == DIR_CCW)
    set_frequency(-1);
}

/**************************************/
/* Change the frequency               */
/* dir = 1    Increment               */
/* dir = -1   Decrement               */
/**************************************/
void set_frequency(short dir)
{
  if (dir == 1)
   vfo += radix;
  if (dir == -1)
    vfo -= radix;

      if(vfo > F_MAX)
       vfo = F_MAX;
       if(vfo < F_MIN)
        vfo = F_MIN;

  changed_f = 1;
}

/**************************************/
/* Read the button with debouncing    */
/**************************************/
boolean get_button()
{
  if (!digitalRead(ENCODER_BTN))
  {
    delay(20);
    if (!digitalRead(ENCODER_BTN))
    {
      while (!digitalRead(ENCODER_BTN));
      return 1;
    }
  }
  return 0;
}

/**************************************/
/* Displays the frequency             */
/**************************************/
void display_frequency()
{
  uint16_t f, g;

  lcd.setCursor(3, 0);
  f = vfo / 1000000; 	//variable is now vfo instead of 'frequency'
  if (f < 10)
    lcd.print(' ');
  lcd.print(f);
  lcd.print('.');
  f = (vfo % 1000000) / 1000;
  if (f < 100)
    lcd.print('0');
  if (f < 10)
    lcd.print('0');
  lcd.print(f);
  lcd.print('.');
  f = vfo % 1000;
  if (f < 100)
    lcd.print('0');
  if (f < 10)
    lcd.print('0');
  lcd.print(f);
  lcd.print("Hz ");
  lcd.setCursor(0, 1);
  lcd.print(tbfo);
  //Serial.println(vfo + bfo);
  //Serial.println(tbfo);
}

/**************************************/
/* Отображаем шаг изменения частоты */
/**************************************/
void display_radix()
{
  lcd.setCursor(9, 1);
  switch (radix)
  {
    case 1:
      lcd.print("    1");
      break;
    case 10:
      lcd.print("   10");
      break;
    case 100:
      lcd.print("  100");
      break;
    case 1000:
      lcd.print("   1k");
      break;
    case 10000:
      lcd.print("  10k");
      break;
    case 100000:
      //lcd.setCursor(10, 1);
      lcd.print(" 100k");
      break;
      case 1000000:
      //lcd.setCursor(9, 1);
      lcd.print("   1MHz"); //1MHz increments
      break;
  }
  lcd.print("Hz");
}

void setup()
{


 // начальное сообщение
 //   lcd.print("SINTIZER Si5351"); // текст на экране - "  HELLO !!! "
 //   delay(3000); // Время на прочтение начального сообщения 3 сек
      
  Serial.begin(19200);
  lcd.begin(16, 2);          // Initialize and clear the LCD
  lcd.clear();
  Wire.begin();

  si5351.set_correction(80235000); //**mine. There is a calibration sketch in File/Examples/si5351Arduino
  //where you can determine the correction by using the serial monitor.
  //ввести калибровочное знечение в строчке si5351.set_correction(хххххххх).
  //Нужно вычислить запустив "si5351calibration" в папке с примерами библиотеки si5351.
  
  //initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); //If you're using a 27Mhz crystal, put in 27000000 instead of 0
  // 0 is the default crystal frequency of 25Mhz.

  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  // Set CLK0 to output the starting "vfo" frequency as set above by vfo = ?

#ifdef IF_Offset
  si5351.set_freq((vfo * SI5351_FREQ_MULT) + bfo, SI5351_PLL_FIXED, SI5351_CLK0);
  volatile uint32_t vfoT = (vfo * SI5351_FREQ_MULT) + bfo;
  tbfo = "USB";
  // Set CLK2 to output bfo frequency
  si5351.set_freq( bfo, 0, SI5351_CLK2);
  //si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_2MA); //you can set this to 2MA, 4MA, 6MA or 8MA
  //si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_2MA); //be careful though - measure into 50ohms
  //si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA); //
#endif

#ifdef Direct_conversion
  si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);
#endif

#ifdef FreqX4
  si5351.set_freq((vfo * SI5351_FREQ_MULT) * 4, SI5351_PLL_FIXED, SI5351_CLK0);
#endif

#ifdef FreqX2
  si5351.set_freq((vfo * SI5351_FREQ_MULT) * 2, SI5351_PLL_FIXED, SI5351_CLK0);
#endif

  pinMode(ENCODER_BTN, INPUT_PULLUP);
  PCICR |= (1 << PCIE2);           // Enable pin change interrupt for the encoder
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();
  display_frequency();  // Update the display
  display_radix();

// Порты, пины для управл. напр. УВЧ и АТТ 
 pinMode(12,OUTPUT);  // для кнопки УВЧ = A2
 pinMode(13,OUTPUT);  //  для кнопки АТТ = A1
 
 // Порты, пины управл. напр. для дешифр. CD4028 
 pinMode(14,OUTPUT);  // b0 для A
 pinMode(15,OUTPUT);  // b1 для B
 pinMode(16,OUTPUT);  // b2 для D
 pinMode(17,OUTPUT);  // b3 для C

}


void loop()

{
  // Update the display if the frequency has been changed
  if (changed_f)
  {
    display_frequency();

#ifdef IF_Offset
    si5351.set_freq((vfo * SI5351_FREQ_MULT) + bfo, SI5351_PLL_FIXED, SI5351_CLK0);
    // Вы также можете вычесть BFO, чтобы удовлетворить ваши потребности
    //si5351.set_freq((vfo * SI5351_FREQ_MULT) - bfo  , SI5351_PLL_FIXED, SI5351_CLK0);

    if (vfo >= 10000000ULL & tbfo != "USB")
    {
      bfo = USB;
      tbfo = "USB";
      si5351.set_freq( bfo, 0, SI5351_CLK2);
      Serial.println("We've switched from LSB to USB");
    }
    else if (vfo < 10000000ULL & tbfo != "LSB")
    {
      bfo = LSB;
      tbfo = "LSB";
      si5351.set_freq( bfo, 0, SI5351_CLK2);
      Serial.println("We've switched from USB to LSB");
    }

#endif

#ifdef Direct_conversion
    si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);
    tbfo = "";
#endif

#ifdef FreqX4
    si5351.set_freq((vfo * SI5351_FREQ_MULT) * 4, SI5351_PLL_FIXED, SI5351_CLK0);
    tbfo = "";
#endif

#ifdef FreqX2
    si5351.set_freq((vfo * SI5351_FREQ_MULT) * 2, SI5351_PLL_FIXED, SI5351_CLK0);
    tbfo = "";
#endif

    changed_f = 0;
  }
  
// Кнопки УВЧ и АТТ ---------------------------------
{ 
     if(digitalRead(4)==HIGH&&flag==0)//если кнопка нажата   
     // и перемення flag равна 0 , то ... 
     { 
       regim++;   
       flag=1; 
         
        //это нужно для того что бы с каждым нажатием кнопки 
        //происходило только одно действие 
        // плюс защита от "дребезга"  100% 
          
        if(regim>4)//ограничим количество режимов 
        { 
          regim=1;//так как мы используем только одну кнопку, 
                    // то переключать режимы будем циклично 
        } 
       
     }   
      if(digitalRead(4)==LOW&&flag==1)//если кнопка НЕ нажата 
     //и переменная flag равна - 1 ,то ... 
     {     
        flag=0;//обнуляем переменную "knopka" 
     } 
             
    if(regim==1)//первый режим - очистка экрана
    { 
      digitalWrite(12,LOW);// на пине нулевой уровень
      digitalWrite(13,LOW); 
      lcd.setCursor(5, 1); 
      lcd.print("   "); //  "пустое место"        
        
      //здесь может быть любое ваше действие 
    } 
    if(regim==2)//второй режим  - вкл. УВЧ
    { 
      digitalWrite(12,LOW);//включает PRE
      digitalWrite(13,HIGH); 
      lcd.setCursor(5, 1); // место на экране для PRE 
      lcd.print("PRE"); 
          
      //здесь может быть любое ваше действие 
    } 

    if(regim==3)//третий режим - очистка экрана
    
    { 
      digitalWrite(12,LOW);//
      digitalWrite(13,LOW); 
      lcd.setCursor(5, 1); // место текста на экране 
      lcd.print("   ");    //  "пустое место"       
        
      //здесь может быть любое ваше действие 
    } 

      
    if(regim==4)//третий режим - вкл. АТТ
    {  
      digitalWrite(12,HIGH);//включает АТТ
      digitalWrite(13,LOW); 
      lcd.setCursor(5, 1); // место на экране для АТТ  
      lcd.print("ATT");    
    } 
//  --------------------------------
//  для кнопки РТТ -----------------



//  ---------------------------------

// Для управления CD4028
//---A0-A1-A2-A3 ---pin, porn Arduino Pro Mini
//---b0-b1-b2-b3----band
//---00-00-00-00----160m 
//---11-00-00-00-----80m 
//---00-11-00-00-----40m 
//---11-11-00-00-----30m 
//---00-00-11-00-----20m 
//---11-00-11-00-----17m 
//---00-11-11-00-----15m 
//---11-11-11-00-----12m 
//---00-00-00-11-----10m 

// Band 160
         if (vfo >= 1000000ULL && vfo <= 3000000ULL)
       {  
     digitalWrite(14,LOW); // на пине нулевой уровень
     digitalWrite(15,LOW); // на пине нулевой уровень
     digitalWrite(16,LOW); // на пине нулевой уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
        }
       
// Band 80
        if (vfo >= 3000001ULL && vfo <= 5000000ULL)
       {
     digitalWrite(14,HIGH); // на пине высокий уровень
     digitalWrite(15,LOW); // на пине нулевой уровень
     digitalWrite(16,LOW); // на пине нулевой уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
       }
// Band 40
        if (vfo >= 5000001ULL && vfo <= 8000000ULL)
        {
     digitalWrite(14,LOW); // на пине нулевой уровень
     digitalWrite(15,HIGH); // на пине высокий уровень
     digitalWrite(16,LOW); // на пине нулевой уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
        }
// Band 30
        if (vfo >= 8000001ULL && vfo <= 120000000ULL)
        {
     digitalWrite(14,HIGH); // на пине высокий уровень
     digitalWrite(15,HIGH); // на пине высокий уровень
     digitalWrite(16,LOW); // на пине нулевой уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
        }
// Band 20
        if (vfo >= 12000001ULL && vfo <= 15000000ULL)
        {
     digitalWrite(14,LOW); // на пине нулевой уровень
     digitalWrite(15,LOW); // на пине нулевой уровень
     digitalWrite(16,HIGH); // на пине высокий уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
        }
// Band 17
        if (vfo >= 15000001ULL && vfo <= 19000000ULL)
        {
     digitalWrite(14,HIGH); // на пине высокий уровень
     digitalWrite(15,LOW); // на пине нулевой уровень
     digitalWrite(16,HIGH); // на пине высокий уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
        }
// Band 15
        if (vfo >= 19000001ULL && vfo <= 23000000ULL)
       { 
     digitalWrite(14,LOW); // на пине нулевой уровень
     digitalWrite(15,HIGH); // на пине высокий уровень
     digitalWrite(16,HIGH); // на пине высокий уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
       }
// Band 12
        if (vfo >= 23000001ULL && vfo <= 26000000ULL)
       {
     digitalWrite(14,HIGH); // на пине высокий уровень
     digitalWrite(15,HIGH); // на пине высокий уровень
     digitalWrite(16,HIGH); // на пине высокий уровень
     digitalWrite(17,LOW); // на пине нулевой уровень
       }
// Band 10
        if (vfo >= 26000001ULL && vfo <= 30000000ULL)
        {
     digitalWrite(14,LOW); // на пине нулевой уровень
     digitalWrite(15,LOW); // на пине нулевой уровень
     digitalWrite(16,LOW); // на пине нулевой уровень
     digitalWrite(17,HIGH); // на пине высокий уровень
        }

// HAM BAND ----- Границы диапазонов ---------
// 160-метровый (1,81 - 2 МГц)
         if (vfo >= 1810000ULL && vfo <= 2000000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("160m"); 
         }

          else
// 80-метровый (3,5 - 3,8 МГц)
         if (vfo >= 3500000ULL && vfo <= 3800000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("80m "); 
         }
else
// 40-метровый (7 - 7,2 МГц)
         if (vfo >= 7000000ULL && vfo <= 7200000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("40m "); 
         }
else
// 30-метровый (только телеграф 10,1 - 10,15 МГц)
         if (vfo >= 10100000ULL && vfo <= 10150000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("30m "); 
         }
else
// 20-метровый (14 - 14,35 МГц)
         if (vfo >= 14000000ULL && vfo <= 14350000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("20m "); 
         }
else
// 17-метровый (18,068 - 18,168 МГц)
         if (vfo >= 18068000ULL && vfo <= 18168000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("17m "); 
         }
else
// 15-метровый (21 - 21,45 МГц)
         if (vfo >= 21000000ULL && vfo <= 21450000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("15m "); 
         }
else
// 12-метровый (24,89 - 25,14 МГц)
         if (vfo >= 24890000ULL && vfo <= 25140000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("12m "); 
         }
else
// 10-метровый (28 - 29,7 МГц)
         if (vfo >= 28000000ULL && vfo <= 29700000ULL)
         {
         lcd.setCursor(0, 1);
         lcd.print("10m "); 
         }
else
// Если за границей любительских - очистка экрана
         {
         lcd.setCursor(0, 1);
         lcd.print("    "); 
         }

  //-----------------------------------       
  // Button press changes the frequency change step for 1 Hz steps
  if (get_button())
  {
    switch (radix)
    {
      case 1:
        radix = 10;
        break;
      case 10:
        radix = 100;
        break;
      case 100:
        radix = 1000;
        break;
      case 1000:
        radix = 10000;
        break;
      case 10000:
        radix = 100000;
        break;
      case 100000:
        radix = 1000000;
        break;
       case 1000000:
        radix = 1;
        break;
    }
    display_radix();
  }
     

}

  
}



Данный синтезатор однодиапазонный.

Пределы перестройки заданы в начале  переменными:

 #define F_MIN        1000000L               // Нижний предел частоты
 #define F_MAX        30000000L              // Верхний предел частоты

 и начальная частота при включении:

volatile uint32_t vfo = 710000000ULL / SI5351_FREQ_MULT; //стартовая частота при запуске синтезатора.

Хотелось сделать данный синтезатор трёхдиапазонным с использованием двух пинов для управления

переключения диапазонов.

При подаче "1" на первый пин синтез переходит на частоту 3600 и работает
в диапазоне 3500-3800 .

Понятно что надо изменить значения переменных

#define F_MIN         35000000L               // Нижний предел частоты
#define F_MAX        38000000L              // Верхний предел частоты

volatile uint32_t vfo = 360000000ULL

по нажатию кнопки. Но как менять дальше значение volatile uint32_t vfo при вращении

энкодера? Ведь кнопка нажата и переменная будет принимать значение 360000000ULL

Понимаю какой то триггер надо реализовать, но как?

Дальнейшая логика работы:
При подаче "1" на второй пин синтез переходит на частоту 14100 и работает в диапазоне 14000-14350 (-ПЧ).
При отсутствии "1" на обоих пинах синтез переходит на частоту 7050 и работает в диапазоне 7000-7200 (+ПЧ).
 

 

ic746
Offline
Зарегистрирован: 04.12.2016

Уточню вопрос.

Есть два управляющих пина. Управляют загрузкой значений переменных.

При старте загружаются значения переменных:

#define F_MIN        10               // Нижний предел частоты
#define F_MAX        30              // Верхний предел частоты

volatile uint32_t vfo = 20 / SI5351_FREQ_MULT; //стартовая частота при запуске синтезатора.

Как сделать чтобы при изменении уровня на первом пине переменные принимали новые значения.

На 1 пине  был "0", появилась "1" должны прописаться новые значения переменных F_MIN=40, F_MAX=60, vfo=50.

Причём отслеживаться должно только изменение уровня, поскольку "1" на 1 пине висит всегда включён 1 диапазон и значение

vfo должно меняться при вращении энкодера.

Соответственно "1" на 2 пине висит всегда когда включён 2 диапазон.

Аналогично и для второго пина, только прописываются другие значения переменных F_MIN=70, F_MAX=90, vfo=80.

При пропадании "0" на двух пинах переменные должны принять первоначальные значения  F_MIN=10, F_MAX=30, vfo=20

 

sadman41
Offline
Зарегистрирован: 19.10.2016

А какие идеи по этому поводу есть лично у вас?

Вот я в автомобилях ничево не понимаю, нашел у деда в гараже "Победу" - как на ней ездить, чтобы там побыстрее или помедленнее... Ну или чтобы направо завернуть, к примеру.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

У Вас тут все завязано на библиотеку si5351 - я ее не знаю, и большинству, я бы сказал подавляющему большинству, она неизвестна. ИМХО - изучите все ее функции или допишите и будет Вам счастье!

SSb 3600
Offline
Зарегистрирован: 02.10.2019

Приветствую кулибинов и ic746.

 

Как успехи в переделке синтезатора ?

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

sadman41 пишет:

А какие идеи по этому поводу есть лично у вас?

Вот я в автомобилях ничево не понимаю, нашел у деда в гараже "Победу" - как на ней ездить, чтобы там побыстрее или помедленнее... Ну или чтобы направо завернуть, к примеру.

...говорила баба деду
- ты купи мине "Победу",
а не купишь мне "Победу"
я уйду к другому деду...

 

SSb 3600
Offline
Зарегистрирован: 02.10.2019

Бабе никчему победа,

Если можно ездить на Деде,

Возить, пахать, грузовики с болота тягать.

А не будет Деда пахать -

баба с под юбки ботага доставать.

И нафига бабе победа,

если всё будет делать нашару Деда.

SSb 3600
Offline
Зарегистрирован: 02.10.2019

Как успехи в переделке синтезатора ?

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Ну либо все хорошо, либо забил на проект. Это же очевидно, как последняя фраза на всех форумах - «Спасибо! О результатах отпишусь!» и привет....

SSb 3600
Offline
Зарегистрирован: 02.10.2019

Мдаа, ну и ладно,  баба з возу и деду легче.

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018
SSb 3600
Offline
Зарегистрирован: 02.10.2019

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

ic746
Offline
Зарегистрирован: 04.12.2016

SSb 3600 пишет:

Приветствую кулибинов и ic746.

 

Как успехи в переделке синтезатора ?

Благодаря помощи sadman41 и mykaida синтезатор успешно запущен и прекрасно работает в ламповом приёмнике! 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Ай, зачем ламповый приём сраньем от синтеза забивать? Или все подавилось хорошо? Очень интересно... 

ЗЫ: а если не жалко и скетч бы глянул. Я все до такого не дойду (синтезаторы сам программировать). 

ic746
Offline
Зарегистрирован: 04.12.2016

Я по не знанию сделал приёмник на плате. Хоть катушка и в экране, а от ламп нагрев и дрейф приличный. 15 кГц выбег после включения, не смотря на стабилизацию анода и накала, а так же термокомпенсацию. Потом верньер с гистерезисом. От синтеза помех не наблюдаю. Может есть пара слабых спуров. Прикупил тут энкодер bourns оптический за дёшево и ручку от IC 735. Приём бесподобный! Скетч советую от veso74 http://qrp.ru/forum/9-%D0%A1%D0%B0%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F-%D1%82%D0%B5%D1%85%D0%BD%D0%B8%D0%BA%D0%B0/13018-%D0%A1%D0%B8%D0%BD%D1%82%D0%B5%D0%B7%D0%B0%D1%82%D0%BE%D1%80-%D0%B4%D0%BB%D1%8F-QRP-CW-%D1%82%D1%80%D0%B0%D0%BD%D1%81%D0%B8%D0%B2%D0%B5%D1%80%D0%B0?start=80

Там всё просто и понятно. Я его заливал в ардуино - работает без проблем. А там допилите под свои нужды.

Buldakov
Offline
Зарегистрирован: 17.01.2016

Поскольку тема уже открыта то добавлю про микросхему SI5351  тут.

По поводу стандартных  примеров библиотеки: Не понравилось - задание многих параметров фиг знает для чего. Но если что то надо то оно есть.

Теперь более подробно. Частота задается от 4 кГц и выше с шагом 0.01 Гц. Частота реально меняется с шагом 0.01 Гц. Понравилась корректировка частоты опорного генератора. Есть возможность включать и отключать раздельно каждый канал И управлять выходным током. Он может задаваться от 2 до 8 ма. Это влияет на время нарастания выходного импульса. При максимальном токе время нарастания около 4 нс. В данном примере частота задана в кГц.

//Минимальная частота 4 кГц.
//Максимальная частота 220 мГц.
//Минимальный шаг изменения частоты 0.01 Гц.
//
#include "si5351.h"
#include "Wire.h"
Si5351 si5351;
//
double freq = 1000.0;//стартовая частота кГц
bool i2c_found;
unsigned long vfo;
//
void setup()
{
vfo= freq*1000;
i2c_found = si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);//initialize the Si5351
si5351.set_correction(0, SI5351_PLL_INPUT_XO);         //корректировка частоты 25 MHz
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
//
Serial.begin(9600);// Start serial
if(i2c_found==0) {Serial.println("Device not found on I2C bus!");}
if(i2c_found==1) {Serial.println("Device SI5351 found");}
//
si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK2);
//
si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_8MA);//set Out to 2MA, 4MA, 6MA or 8MA
si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_2MA);//set Out to 2MA, 4MA, 6MA or 8MA
si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA);//set Out to 2MA, 4MA, 6MA or 8MA
//
si5351.output_enable(SI5351_CLK0,1); //Включаем  0 выход
si5351.output_enable(SI5351_CLK1,0); //Выключаем 1 выход
si5351.output_enable(SI5351_CLK2,0); //Выключаем 2 выход
}
void loop()
{
}

 

Als
Offline
Зарегистрирован: 17.05.2015
Если кто разобрался в следующем, то помогите, пожалуйста!
 
Задача такая: есть si5153, Arduino uno. Необходимо выдавать на один из выходов SI последовательно частоты от 90MHz до 170Mhz с шагом 250кГц, и так по кругу до бесконечности.
 
Если начальная частота не 90MHz, а например 101MHz (важно что > 100MHz), то всё работает как надо.
 
Как только выставляю начальную частоту < 100MHz, то один круг отрабатывается как надо, частоты выдаются (контролирую по осциллографу). Со второго круга SI зависает, и перестаёт генерить какие-либо частоты вообще. Программные резеты не помогают, только аппаратный.
 
Видимо не учёл какой-то нюанс этой микросхемы.
 
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Als, задавая такой вопрос как минимум нужно предоставить скетч, в котором проявляется проблема, но нет ничего лишнего (как в #15 например) . Если используется библиотека, то указать используемую версию и дать ссылку на библиотеку.

Als
Offline
Зарегистрирован: 17.05.2015

Прошу прощения, что я задал вопрос и пропал – дела выбели меня из колеи на несколько недель.

Пример о котором Вы спрашиваете, я сделал, он компилируется, но эффект о котором я писал саморассосался. Ранее, в процессе отладки девайса я забил на зависания, и использовал SI, на частотах выше 100 MHz.

Потом найду старые бэкапы, в которых эта проблема была – сравню что изменилось.

Ещё я за время отладки девайса я поменял USB кабель соединяющий компьютер и Arduino –вряд ли это на что-то могло повлиять. И однажды я утвердительно ответил на предложение IDE обновить библиотеки, какие библиотеки обновились я не посмотрел.

ingfa
Offline
Зарегистрирован: 15.09.2018

Скажите а в этом коде нет ошибок с типом переменных?

double freq = 1000.0;//стартовая частота кГц
 
11 unsigned long vfo;

vfo= freq*1000;

si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK0);

 

Просто написано что Минимальный шаг изменения частоты 0.01 Гц.

Не могу разобраться. Вообще 

что подавать si5351 double или unsigned long?

 

 

 

 

 

 

 

 

 

 

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

А что в библиотеке написано?

ingfa
Offline
Зарегистрирован: 15.09.2018

uint8_t set_freq(uint64_t, enum si5351_clock);

 

/*
 * set_freq(uint64_t freq, enum si5351_clock clk)
 *
 * Sets the clock frequency of the specified CLK output.
 * Frequency range of 8 kHz to 150 MHz
 *
 * freq - Output frequency in Hz
 * clk - Clock output
 *   (use the si5351_clock enum)
 */
uint8_t Si5351::set_freq(uint64_t freq, enum si5351_clock clk)
{
struct Si5351RegSet ms_reg;
uint64_t pll_freq;
uint8_t int_mode = 0;
uint8_t div_by_4 = 0;
uint8_t r_div = 0;
 
// Check which Multisynth is being set
BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Ну вот, какие еще вопросы?

ingfa
Offline
Зарегистрирован: 15.09.2018

Я начинающий, можно поподробней ответить, а то буду искать три дня инфу

rkit
Offline
Зарегистрирован: 23.11.2016

Тебе нужно читать учебник. И гораздо дольше трех дней.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

ingfa пишет:

буду искать три дня инфу

Какую информацию Вы собрались искать три дня? Ответ на Ваш вопрос в сообщении #21

ingfa
Offline
Зарегистрирован: 15.09.2018

BOOM пишет:

ingfa пишет:

буду искать три дня инфу

Какую информацию Вы собрались искать три дня? Ответ на Ваш вопрос в сообщении #21

Так получается uint64_t это целочисленная переменная из C++. Например могу передать 100000000Гц. Какой тогда шаг 0.01гц так и не понял?

 

//Минимальная частота 4 кГц.
//Максимальная частота 220 мГц.
//Минимальный шаг изменения частоты 0.01 Гц.
//
#include "si5351.h"
#include "Wire.h"
Si5351 si5351;
//
double freq = 1000.0;//стартовая частота кГц
bool i2c_found;
unsigned long vfo;
//
void setup()
{
vfo= freq*1000;
i2c_found = si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);//initialize the Si5351
si5351.set_correction(0, SI5351_PLL_INPUT_XO);         //корректировка частоты 25 MHz
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
//
Serial.begin(9600);// Start serial
if(i2c_found==0) {Serial.println("Device not found on I2C bus!");}
if(i2c_found==1) {Serial.println("Device SI5351 found");}
//
si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK0);
si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK1);
si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK2);
//
si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_8MA);//set Out to 2MA, 4MA, 6MA or 8MA
si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_2MA);//set Out to 2MA, 4MA, 6MA or 8MA
si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA);//set Out to 2MA, 4MA, 6MA or 8MA
//
si5351.output_enable(SI5351_CLK0,1); //Включаем  0 выход
si5351.output_enable(SI5351_CLK1,0); //Выключаем 1 выход
si5351.output_enable(SI5351_CLK2,0); //Выключаем 2 выход
}
void loop()
{
}

Я про этот пример.

b707
Offline
Зарегистрирован: 26.05.2017

а самому в библиотеку заглянуть? - частота задается целым числом в сотых герца

В примере выше в строчке

si5351.set_freq(vfo *SI5351_FREQ_MULT, SI5351_CLK0);

в синтезатор грузится целая частота в герцах - vfo и домножается на мультиплайер 100. Хотите частоту в точности до сотых - просто умножьте ее на 100 сами и передайте вместо этого произведения :

si5351.set_freq(123455ULL, SI5351_CLK0);  // freq 1234.55 Hz

 

b707
Offline
Зарегистрирован: 26.05.2017

добавлю, способ задания частот прописан в описании библиотеки, главное внимательно читать:

Frequencies are indicated in units of 0.01 Hz. Therefore, if you prefer to work in 1 Hz increments in your own code, simply multiply each frequency passed to the library by 100ULL (better yet, use the define called SI5351_FREQ_MULT in the header file for this multiplication).

Next, let's set the CLK0 output to 14 MHz:

si5351.set_freq(1400000000ULL, SI5351_CLK0);

 

ingfa
Offline
Зарегистрирован: 15.09.2018

а как выставить частоту 100000.35 Гц?

10000035 * 1000ULL    ?

b707
Offline
Зарегистрирован: 26.05.2017

ingfa пишет:

а как выставить частоту 100000.35 Гц?

10000035 * 1000ULL    ?

пипец, ну и бред.... Ведь вроде все расписал, выдержки из доков привел.

Головой думайте.

ingfa
Offline
Зарегистрирован: 15.09.2018

Установка выходной частоты

Как указано выше, библиотека принимает и указывает тактовые частоты и частоты ФАПЧ в единицах 0,01 Гц как беззнаковый длинный длинный тип переменной (или uint64_t ). При вводе буквальных значений добавьте, ULLчтобы явное длинное число без знака получилось для обеспечения правильной настройки. Поскольку многие приложения не требуют настройки ниже герцовой частоты , вы можете использовать переменную типа unsigned long (или uint32_t ) для хранения частоты настройки, а затем масштабировать ее, умножая на 100ULL перед передачей в метод set_freq () .

 

Честно не понятно.  

Нужен пример. Или ссылка где обучиться  работе с unsigned long long типом 

b707
Offline
Зарегистрирован: 26.05.2017

ingfa пишет:

Честно не понятно.  Нужен пример.

последняя строчка сообщения #27 - пример задания частоты 1234.55 гц. Другой пример - последняя строчка сообщения 28 .

Что не хватает? ваши числа в пример подставить?

ingfa
Offline
Зарегистрирован: 15.09.2018

Куда смотрел не знаю. В 27 сообщении все было. 

Я слепил из двух кодов скетч, который принимает значение частоты для каждого выхода clk0 clk1 clk2 с serial порта, по одному и добавляет в переменную float variableValue = atof(ptr);

а дальше, что с ней делать не знаю. 

// пример пакета
// $&a12345.56&b12345.56&c12345.56#
//

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

enum AUTOMATA_STATE { // Возможные состояния разборщика
  WAITING,  // ожидание начала пакета
  PARSING   //  разбор пакета
};

#define PACKET_BEGIN  '$'
#define PACKET_END  '#'
#define VALUE_BEGIN '&'
#include "si5351.h"
#include "Wire.h"
Si5351 si5351;
bool i2c_found;
uint64_t chastota1;
uint64_t chastota2;
uint64_t chastota3;


void setup(void) {
  Serial.begin(115200);
  Serial << "Enter packet:\n";
  i2c_found = si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(0, SI5351_PLL_INPUT_XO);         //корректировка частоты 25 MHz
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  if(i2c_found==0) {Serial.println("Device not found on I2C bus!");}
  if(i2c_found==1) {Serial.println("Device SI5351 found");}
  si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_8MA);//set Out to 2MA, 4MA, 6MA or 8MA
  si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_8MA);//set Out to 2MA, 4MA, 6MA or 8MA
  si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_8MA);//set Out to 2MA, 4MA, 6MA or 8MA
}

void parseString(char * szBuffer) {
  Serial << "GOT Packet: " << szBuffer << '\n';
  for (char *ptr = szBuffer; ptr; ptr = strchr(ptr, VALUE_BEGIN))  {
    if (*ptr++ != VALUE_BEGIN) {
      Serial << "*** ERROR: packet malformed\n";
      return;
    }
    char variableName = *ptr++;
    float variableValue = atof(ptr);
    Serial << "Name=" << variableName << "; Value=" << variableValue << '\n';
   
    if(variableName == 'a'){
      chastota1 = variableValue;
      si5351.set_freq(chastota1 *SI5351_FREQ_MULT, SI5351_CLK0);
      si5351.output_enable(SI5351_CLK0,1); //Включаем  0 выход
    }

    if(variableName == 'b'){
      chastota2 = variableValue;
      si5351.set_freq(chastota2 *SI5351_FREQ_MULT, SI5351_CLK1);
      si5351.output_enable(SI5351_CLK1,1); //Выключаем 1 выход
    }

     if(variableName == 'c'){
      chastota3 = variableValue;
      si5351.set_freq(chastota3 *SI5351_FREQ_MULT, SI5351_CLK2);
      si5351.output_enable(SI5351_CLK2,1); //Выключаем 2 выход
      
    }

  }
  Serial << "All Done!\n";
}


void loop(void) {
  // Изначально автомат в состоянии ожидания
  static AUTOMATA_STATE state = WAITING;
  static char szBuffer[64]; // буфер для накапливания строки
  static int8_t bufPtr = 0;
  
  if (! Serial.available()) return; // не пришёл символ? Ну, и нечего тут делать
  //
  const char ch = Serial.read();  // прочитали сивол 
  //
  // Что делать дальше пределяется состоянием автомата
  switch (state) {
    case WAITING:
      // В состоянии ожидания мы ждём символа PACKET_BEGIN и игнорируем любые другие
      if (ch != PACKET_BEGIN) return;
      // 
      // Пришёл символ начала пакета. Переходим в состояние PARSING
      state = PARSING;
      break;
    case PARSING:
      // В состоянии ожидания мы ждём символа PACKET_END. 
      // Любые другие символы - часть пакета. Их складываем в буфер.
      if (ch == PACKET_END) { // пришёл символ конца пакета
        szBuffer[bufPtr++] = 0;
        parseString(szBuffer);
        state = WAITING; // переходим в состояние ожидания нового пакета
        bufPtr = 0;
      } else {
        szBuffer[bufPtr++] = ch;
        if (bufPtr == sizeof(szBuffer)) {
          Serial << "*** ERROR *** Buffer overflow!!!\n";
          bufPtr--;
        }
      }
  }
}

 

 

 

b707
Offline
Зарегистрирован: 26.05.2017

ingfa пишет:

а дальше, что с ней делать не знаю.

так вроде все сделали уже? 

Хотя нет, вижу что неправильно.

Когда вы приравниваете float variableValue целому chastota1 - у вас дробная часть теряется и никакой точности в 0.01Гц не будет. Домножать на 100 надо до перевода в целое,  а не после

ingfa
Offline
Зарегистрирован: 15.09.2018

А в библиотеке SI5351_FREQ_MULT = 100ULL ее оставить как есть

в этой строке убрать SI5351_FREQ_MULT в моем скетче ?

si5351.set_freq(chastota1 *SI5351_FREQ_MULT, SI5351_CLK0);

Когда вы приравниваете float variableValue целому chastota1 - у вас дробная часть теряется и никакой точности в 0.01Гц не будет. Домножать на 100 надо до перевода в целое,  а не после

Умножать  на 100 или на 100ULL?   float variableValue = atof(ptr)*100

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Скажите честно - зачем Вам это всё? Книги по программированию читать Вы не хотите (хотя бы разделы «Типы данных» и «Приведение типов»), так чего хотите добиться в итоге?