Официальный сайт компании Arduino по адресу arduino.cc
Синтезатор Si5351
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Приветствую всех!
Решил тут синтезатор частоты собрать и заплутал в 3 соснах.
Код: /* Вся эта программа изначально написана 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 (+ПЧ).
Уточню вопрос.
Есть два управляющих пина. Управляют загрузкой значений переменных.
При старте загружаются значения переменных:
#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
А какие идеи по этому поводу есть лично у вас?
Вот я в автомобилях ничево не понимаю, нашел у деда в гараже "Победу" - как на ней ездить, чтобы там побыстрее или помедленнее... Ну или чтобы направо завернуть, к примеру.
У Вас тут все завязано на библиотеку si5351 - я ее не знаю, и большинству, я бы сказал подавляющему большинству, она неизвестна. ИМХО - изучите все ее функции или допишите и будет Вам счастье!
Приветствую кулибинов и ic746.
Как успехи в переделке синтезатора ?
А какие идеи по этому поводу есть лично у вас?
Вот я в автомобилях ничево не понимаю, нашел у деда в гараже "Победу" - как на ней ездить, чтобы там побыстрее или помедленнее... Ну или чтобы направо завернуть, к примеру.
...говорила баба деду
- ты купи мине "Победу",
а не купишь мне "Победу"
я уйду к другому деду...
Бабе никчему победа,
Если можно ездить на Деде,
Возить, пахать, грузовики с болота тягать.
А не будет Деда пахать -
баба с под юбки ботага доставать.
И нафига бабе победа,
если всё будет делать нашару Деда.
Как успехи в переделке синтезатора ?
Ну либо все хорошо, либо забил на проект. Это же очевидно, как последняя фраза на всех форумах - «Спасибо! О результатах отпишусь!» и привет....
Мдаа, ну и ладно, баба з возу и деду легче.
Баба с возу, кобыле легче.
(https://dic.academic.ru/dic.nsf/michelson_new/346/%D0%B1%D0%B0%D0%B1%D0%B0)
Кобыле легче-значит быстрее едет, дед проедет с ветерком
Приветствую кулибинов и ic746.
Как успехи в переделке синтезатора ?
Благодаря помощи sadman41 и mykaida синтезатор успешно запущен и прекрасно работает в ламповом приёмнике!
Ай, зачем ламповый приём сраньем от синтеза забивать? Или все подавилось хорошо? Очень интересно...
ЗЫ: а если не жалко и скетч бы глянул. Я все до такого не дойду (синтезаторы сам программировать).
Я по не знанию сделал приёмник на плате. Хоть катушка и в экране, а от ламп нагрев и дрейф приличный. 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
Там всё просто и понятно. Я его заливал в ардуино - работает без проблем. А там допилите под свои нужды.
Поскольку тема уже открыта то добавлю про микросхему SI5351 тут.
По поводу стандартных примеров библиотеки: Не понравилось - задание многих параметров фиг знает для чего. Но если что то надо то оно есть.
Теперь более подробно. Частота задается от 4 кГц и выше с шагом 0.01 Гц. Частота реально меняется с шагом 0.01 Гц. Понравилась корректировка частоты опорного генератора. Есть возможность включать и отключать раздельно каждый канал И управлять выходным током. Он может задаваться от 2 до 8 ма. Это влияет на время нарастания выходного импульса. При максимальном токе время нарастания около 4 нс. В данном примере частота задана в кГц.
Als, задавая такой вопрос как минимум нужно предоставить скетч, в котором проявляется проблема, но нет ничего лишнего (как в #15 например) . Если используется библиотека, то указать используемую версию и дать ссылку на библиотеку.
Прошу прощения, что я задал вопрос и пропал – дела выбели меня из колеи на несколько недель.
Пример о котором Вы спрашиваете, я сделал, он компилируется, но эффект о котором я писал саморассосался. Ранее, в процессе отладки девайса я забил на зависания, и использовал SI, на частотах выше 100 MHz.
Потом найду старые бэкапы, в которых эта проблема была – сравню что изменилось.
Ещё я за время отладки девайса я поменял USB кабель соединяющий компьютер и Arduino –вряд ли это на что-то могло повлиять. И однажды я утвердительно ответил на предложение IDE обновить библиотеки, какие библиотеки обновились я не посмотрел.