В данной статье мы рассмотрим создание генератора перестраиваемой частоты на основе платы Arduino и модуля Si5351, работающего в диапазоне 10 кГц – 225 МГц. Данный генератор может пригодиться для тестирования работы различных радиоприемников, может использоваться в качестве генератора тактовых сигналов, в качестве гетеродина в супергетеродинных приемниках, в синтезаторах частоты и многих других похожих приложениях.

Также на нашем сайте вы можете посмотреть похожие проекты:
- генератор сигналов на Arduino и DDS модуле AD9833;
- генератор сигналов прямоугольной и синусоидальной формы на Arduino.
Необходимые компоненты
- Плата Arduino Nano (купить на AliExpress).
- Инкрементальный энкодер с кнопкой (купить на AliExpress).
- OLED дисплей 128х64 (купить на AliExpress — для данного проекта можно покупать модель с 4-мя контактами поскольку используется его подключение по интерфейсу I2C).
- Adafruit SI5351 CLOCK GEN (генератор тактовых частот) (купить на AliExpress).
- Toggle Switch, SPDT (переключатель).
- Panasonic RCA JACK (выходной радиочастотный разъем).
- Конденсаторы 10 нФ и 100 нФ (купить на AliExpress).
- Конденсатор 10 мкФ (купить на AliExpress).
- Резистор 1 кОм (купить на AliExpress).
- Катушка индуктивности 100 мкГн (Inductor 100 uH) (купить на AliExpress).
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Общие принципы работы проекта
В данном проекте рассматривается генератор перестраиваемой частоты (variable-frequency oscillator, VFO), пригодный для использования в «домашних» (Do It Yourself , DIY) условиях. Этот генератор может пригодиться в синтезаторах частоты, супергетеродинных радиоприемниках, SDR-приемопередатчиках и т.д. Генератор имеет шкальный индикатор (Bargraph indicator) для отображения мощности сигнала (S-Meter) и 20 заранее установленных диапазонов частот.

Основные особенности проекта:
- рабочий диапазон от 10 кГц до 225 МГц;
- шаг настройки: 1 Гц, 10 Гц, 1 кГц, 5 кГц, 10 кГц и 1 МГц;
- регулируемое смещение (+ или -) промежуточной частоты (ПЧ);
- 20 заранее установленных диапазонов частот (с быстрым доступом) в полосах частот АМ-вещания (BCB) и радиолюбительских диапазонах (HAM frequencies);
- режим генерации сигналов (функциональный генератор);
- для использования в качестве местного генератора на самодельных супергетеродинных радиоприемниках или радиоприемниках с прямым преобразованием;
- для использования в качестве генератора переменной частоты для радиолюбителей;
- для использования в качестве простого тактового генератора для калибровки или генерации тактовых импульсов;
- шкальный индикатор для отображения мощности сигнала через вход АЦП (аналого-цифрового преобразователя);
- возможность работы с платами Arduino Uno, Nano и Pro Mini;
- использует стандартный дисплей 128×64 I2C OLED SSD1306 и модуль Si5351;
- передача данных по интерфейсу I2C, необходимо всего 2 провода для подключения дисплея и модуля Si5351 к плате Arduino;
- высокая стабильность и точность генерации частоты;
- хорошая эффективность, невысокая стоимость, можно собрать в домашних условиях.
Микросхема (модуль) Si5351

Микросхема Si5351 это конфигурируемый через I2C генератор тактовых частот, идеально подходящий для замены кварцев, кварцевых генераторов, генераторов VCXO (voltage-controlled crystal oscillator – кварцевый генератор, управляемый напряжением), синтезаторов с ФАПЧ (PLL), буферов развязки в приложениях, критичных к общей стоимости. Базируясь на архитектуре PLL/VCXO + high resolution MultiSynth fractional divider, Si5351 может генерировать любую частоту до 200 МГц на каждом из выходов с нулевым отклонением от заданного значения (0 ppm error). Для удовлетворения различным требованиям приложений Si5351 выпускается в 3 версиях. Si5351A генерирует до 8 не зависящих друг от друга тактовых сигналов, используя внутренний генератор, что позволяет заменить несколько кварцев или кварцевых генераторов. В Si5351B добавлен внутренний VCXO, что дает возможность заменить как свободно (независимо друг от друга), так и синхронно генерируемые тактовые частоты. Это устраняет необходимость применения дорогих специальных кварцев, предоставляя при этом высокую надежность работы в широком диапазоне настраиваемых частот. Si5351C предоставляет такую же гибкость, но синхронизируется при этом с внешним опорным генератором (CLKIN).
Узнать более подробную информацию о микросхеме Si5351 и ее подключение к плате Arduino вы можете на сайте ее разработчика. Также принципы ее работы неплохо описаны на сайте microsin.net.
Схема проекта
Схема генератора перестраиваемой частоты на Arduino и модуле Si5351 представлена на следующем рисунке.

Внешний вид собранной конструкции проекта показан на следующем рисунке.
Реклама
Sony PlayStation 5 – мощь, скорость, погружение!
Реклама
Реклама•18+
Сетевые нереплицируемые диски в облаке как новое явление

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


Инструкции по работе с проектом
Для работы с проектом выполните следующую последовательность шагов:
- подготовьте аппаратную часть проекта согласно представленной схемы;
- подайте питание на плату Arduino;
- откройте код программы в Arduino IDE, установите все необходимые библиотеки;
- установите настройки проекта (preferences) (описаны далее в статье), скомпилируйте скетч и загрузите его в плату Arduino Nano, Uno или Pro Mini;
- вращайте ручку инкрементального энкодера для увеличения или уменьшения генерируемой частоты;
- нажимайте кнопку 1 для изменения шага настройки. Возможные шаги настройки: 1 Гц, 10 Гц, 1 кГц, 5 кГц, 10 кГц и 1 МГц;
- нажимайте кнопку 2 для выбора одного из заранее установленных частотных диапазонов или выберите режим генератора (generator mode);
- включайте/выключайте переключатель SW 2 для переключения между режимами RX и TX. В режиме RX переключатель SW 2 открыт, а в режиме TX он замкнут на землю (GND). В режиме TX значение IF (промежуточной частоты) не добавляется/вычитается из выхода RF (радиочастоты) – этот режим отлично подходит для использования в домашних приемопередатчиках;
- подключите выходной сигнал с измерителя мощности (S-Meter) от вашего радиоприемника (радиостанции) к разъему X2 (вход S-Meter’а). Этот вход имеет настраиваемую чувствительность, его коэффициент усиления можно настроить в приведенном скетче. На данный вход можно подавать сигналы от 500mV до 5V (max);
- важное дополнение: if it freezes in the initialization text, comment (put a //) at the line 77 statup_text ();
Внесение изменений в настройки проекта (User Preferences)
Вы можете изменить следующие строки в скетче:
#define IF 455 //введите вашу IF (промежуточную) частоту, ex: 455 = 455kHz, 10700 = 10.7MHz, 0 = прямое преобразование частоты приемника или радиочастоты генератора, «+» будет добавляться, а «-» будет вычитаться сдвиг промежуточной частоты.
#define BAND_INIT 7 // введите ваш начальный диапазон (Band) (1-21) в начале работы проекта, ex: 1 = Freq Generator, 2 = 800kHz (MW – средние волны), 7 = 7.2MHz (40m), 11 = 14.1MHz (20m).
#define XT_CAL_F 33000 // коэффициент калибровки модуля Si5351, можно настроить чтобы получить точно 10MHz. Увеличение этого значения будет уменьшать частоту и наоборот.
#define S_GAIN 303 //настройка чувствительности входа измерителя мощности (Signal Meter A/D input): 101 = 500mv; 202 = 1v; 303 = 1.5v; 404 = 2v; 505 = 2.5v; 1010 = 5v (max).
#define tunestep A0 //контакт, к которому подключена кнопка для настройки шага настройки.
#define band A1 //контакт, к которому подключена кнопка для выбора частотного диапазона.
#define rx_tx A2 // контакт, к которому подключена кнопка для выбора режима RX / TX, RX = switch open (переключатель открыт), TX = switch closed to GND (переключатель замкнут на землю). В режиме TX частота IF (промежуточная) не учитывается.
#define adc A3 //контакт, используемый как вход измерителя мощности (Signal Meter A/D input).

Исходный код программы (скетча)
Arduino
| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 | /********************************************************************************************************** 10kHz to 225MHz VFO / RF Generator with Si5351 and Arduino Nano, with Intermediate Frequency (IF) offset (+ or -), RX/TX Selector for QRP Transceivers, Band Presets and Bargraph S-Meter. See the schematics for wiring and README.txt for details. By J. CesarSound — ver 2.0 — Feb/2021.***********************************************************************************************************///Libraries#include <Wire.h> //библиотека для работы с интерфейсом I2C#include <Rotary.h> //Ben Buxton https://github.com/brianlow/Rotary#include <si5351.h> //Etherkit https://github.com/etherkit/Si5351Arduino#include <Adafruit_GFX.h> //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library#include <Adafruit_SSD1306.h> //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306//пользовательские настройки//————————————————————————————————————#define IF 455 // введите вашу IF (промежуточную) частоту, ex: 455 = 455kHz, 10700 = 10.7MHz, 0 = прямое преобразование частоты приемника или радиочастоты генератора, «+» будет добавляться, а «-» будет вычитаться сдвиг промежуточной частоты.#define BAND_INIT 7 // введите ваш начальный диапазон (Band) (1-21) в начале работы проекта, ex: 1 = Freq Generator, 2 = 800kHz (MW – средние волны), 7 = 7.2MHz (40m), 11 = 14.1MHz (20m).#define S_GAIN 303 // настройка чувствительности входа измерителя мощности (Signal Meter A/D input): 101 = 500mv; 202 = 1v; 303 = 1.5v; 404 = 2v; 505 = 2.5v; 1010 = 5v (max).#define tunestep A0 // контакт, к которому подключена кнопка для настройки шага настройки.#define band A1 // контакт, к которому подключена кнопка для выбора частотного диапазона.#define rx_tx A2 //контакт, к которому подключена кнопка для выбора режима RX / TX, RX = switch open (переключатель открыт), TX = switch closed to GND (переключатель замкнут на землю). В режиме TX частота IF (промежуточная) не учитывается.#define adc A3 // контакт, используемый как вход измерителя мощности (Signal Meter A/D input).#define XT_CAL_F 33000//————————————————————————————————————Rotary r = Rotary(2, 3);Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);Si5351 si5351(0x60); //Si5351 I2C Address 0x60 (адрес I2C для Si5351)unsigned long freq, freqold, fstep;long interfreq = IF, interfreqold = 0;long cal = XT_CAL_F;unsigned int smval;byte encoder = 1;byte stp, n = 1;byte count, x, xo;bool sts = 0;unsigned int period = 100;unsigned long time_now = 0;ISR(PCINT2_vect) { char result = r.process(); if (result == DIR_CW) set_frequency(1); else if (result == DIR_CCW) set_frequency(-1);}void set_frequency(short dir) { if (encoder == 1) { //Up/Down frequency if (dir == 1) freq = freq + fstep; if (freq >= 225000000) freq = 225000000; if (dir == -1) freq = freq — fstep; if (fstep == 1000000 && freq <= 1000000) freq = 1000000; else if (freq < 10000) freq = 10000; } if (encoder == 1) { //Up/Down graph tune pointer if (dir == 1) n = n + 1; if (n > 42) n = 1; if (dir == -1) n = n — 1; if (n < 1) n = 42; }}void setup() { Wire.begin(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.setTextColor(WHITE); display.display(); pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); pinMode(tunestep, INPUT_PULLUP); pinMode(band, INPUT_PULLUP); pinMode(rx_tx, INPUT_PULLUP); //statup_text(); //If you hang on startup, comment si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); si5351.set_correction(cal, SI5351_PLL_INPUT_XO); si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); si5351.output_enable(SI5351_CLK0, 1); //1 — Enable / 0 — Disable CLK si5351.output_enable(SI5351_CLK1, 0); si5351.output_enable(SI5351_CLK2, 0); PCICR |= (1 << PCIE2); PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); sei(); count = BAND_INIT; bandpresets(); stp = 4; setstep();}void loop() { if (freqold != freq) { time_now = millis(); tunegen(); freqold = freq; } if (interfreqold != interfreq) { time_now = millis(); tunegen(); interfreqold = interfreq; } if (xo != x) { time_now = millis(); xo = x; } if (digitalRead(tunestep) == LOW) { time_now = (millis() + 300); setstep(); delay(300); } if (digitalRead(band) == LOW) { time_now = (millis() + 300); inc_preset(); delay(300); } if (digitalRead(rx_tx) == LOW) { time_now = (millis() + 300); sts = 1; } else sts = 0; if ((time_now + period) > millis()) { displayfreq(); layout(); } sgnalread();}void tunegen() { si5351.set_freq((freq + (interfreq * 1000ULL)) * 100ULL, SI5351_CLK0);}void displayfreq() { unsigned int m = freq / 1000000; unsigned int k = (freq % 1000000) / 1000; unsigned int h = (freq % 1000) / 1; display.clearDisplay(); display.setTextSize(2); char buffer[15] = «»; if (m < 1) { display.setCursor(41, 1); sprintf(buffer, «%003d.%003d», k, h); } else if (m < 100) { display.setCursor(5, 1); sprintf(buffer, «%2d.%003d.%003d», m, k, h); } else if (m >= 100) { unsigned int h = (freq % 1000) / 10; display.setCursor(5, 1); sprintf(buffer, «%2d.%003d.%02d», m, k, h); } display.print(buffer);}void setstep() { switch (stp) { case 1: stp = 2; fstep = 1; break; case 2: stp = 3; fstep = 10; break; case 3: stp = 4; fstep = 1000; break; case 4: stp = 5; fstep = 5000; break; case 5: stp = 6; fstep = 10000; break; case 6: stp = 1; fstep = 1000000; break; }}void inc_preset() { count++; if (count > 21) count = 1; bandpresets(); delay(50);}void bandpresets() { switch (count) { case 1: freq = 100000; tunegen(); break; case 2: freq = 800000; break; case 3: freq = 1800000; break; case 4: freq = 3650000; break; case 5: freq = 4985000; break; case 6: freq = 6180000; break; case 7: freq = 7200000; break; case 8: freq = 10000000; break; case 9: freq = 11780000; break; case 10: freq = 13630000; break; case 11: freq = 14100000; break; case 12: freq = 15000000; break; case 13: freq = 17655000; break; case 14: freq = 21525000; break; case 15: freq = 27015000; break; case 16: freq = 28400000; break; case 17: freq = 50000000; break; case 18: freq = 100000000; break; case 19: freq = 130000000; break; case 20: freq = 144000000; break; case 21: freq = 220000000; break; } si5351.pll_reset(SI5351_PLLA); stp = 4; setstep();}void layout() { display.setTextColor(WHITE); display.drawLine(0, 20, 127, 20, WHITE); display.drawLine(0, 43, 127, 43, WHITE); display.drawLine(105, 24, 105, 39, WHITE); display.drawLine(87, 24, 87, 39, WHITE); display.drawLine(87, 48, 87, 63, WHITE); display.drawLine(15, 55, 82, 55, WHITE); display.setTextSize(1); display.setCursor(59, 23); display.print(«STEP»); display.setCursor(54, 33); if (stp == 2) display.print(» 1Hz»); if (stp == 3) display.print(» 10Hz»); if (stp == 4) display.print(» 1kHz»); if (stp == 5) display.print(» 5kHz»); if (stp == 6) display.print(«10kHz»); if (stp == 1) display.print(» 1MHz»); display.setTextSize(1); display.setCursor(92, 48); display.print(«IF:»); display.setCursor(92, 57); display.print(interfreq); display.print(«k»); display.setTextSize(1); display.setCursor(110, 23); if (freq < 1000000) display.print(«kHz»); if (freq >= 1000000) display.print(«MHz»); display.setCursor(110, 33); if (interfreq == 0) display.print(«VFO»); if (interfreq != 0) display.print(«L O»); display.setCursor(91, 28); if (!sts) display.print(«RX»); if (!sts) interfreq = IF; if (sts) display.print(«TX»); if (sts) interfreq = 0; bandlist(); drawbargraph(); display.display();}void bandlist() { display.setTextSize(2); display.setCursor(0, 25); if (count == 1) display.print(«GEN»); if (count == 2) display.print(«MW»); if (count == 3) display.print(«160m»); if (count == 4) display.print(«80m»); if (count == 5) display.print(«60m»); if (count == 6) display.print(«49m»); if (count == 7) display.print(«40m»); if (count == 8) display.print(«31m»); if (count == 9) display.print(«25m»); if (count == 10) display.print(«22m»); if (count == 11) display.print(«20m»); if (count == 12) display.print(«19m»); if (count == 13) display.print(«16m»); if (count == 14) display.print(«13m»); if (count == 15) display.print(«11m»); if (count == 16) display.print(«10m»); if (count == 17) display.print(«6m»); if (count == 18) display.print(«WFM»); if (count == 19) display.print(«AIR»); if (count == 20) display.print(«2m»); if (count == 21) display.print(«1m»); if (count == 1) interfreq = 0; else if (!sts) interfreq = IF;}void sgnalread() { smval = analogRead(adc); x = map(smval, 0, S_GAIN, 1, 14); if (x > 14) x = 14;}void drawbargraph() { byte y = map(n, 1, 42, 1, 14); display.setTextSize(1); //Pointer display.setCursor(0, 48); display.print(«TU»); switch (y) { case 1: display.fillRect(15, 48, 2, 6, WHITE); break; case 2: display.fillRect(20, 48, 2, 6, WHITE); break; case 3: display.fillRect(25, 48, 2, 6, WHITE); break; case 4: display.fillRect(30, 48, 2, 6, WHITE); break; case 5: display.fillRect(35, 48, 2, 6, WHITE); break; case 6: display.fillRect(40, 48, 2, 6, WHITE); break; case 7: display.fillRect(45, 48, 2, 6, WHITE); break; case 8: display.fillRect(50, 48, 2, 6, WHITE); break; case 9: display.fillRect(55, 48, 2, 6, WHITE); break; case 10: display.fillRect(60, 48, 2, 6, WHITE); break; case 11: display.fillRect(65, 48, 2, 6, WHITE); break; case 12: display.fillRect(70, 48, 2, 6, WHITE); break; case 13: display.fillRect(75, 48, 2, 6, WHITE); break; case 14: display.fillRect(80, 48, 2, 6, WHITE); break; } //Bargraph (индикатор мощности) display.setCursor(0, 57); display.print(«SM»); switch (x) { case 14: display.fillRect(80, 58, 2, 6, WHITE); case 13: display.fillRect(75, 58, 2, 6, WHITE); case 12: display.fillRect(70, 58, 2, 6, WHITE); case 11: display.fillRect(65, 58, 2, 6, WHITE); case 10: display.fillRect(60, 58, 2, 6, WHITE); case 9: display.fillRect(55, 58, 2, 6, WHITE); case 8: display.fillRect(50, 58, 2, 6, WHITE); case 7: display.fillRect(45, 58, 2, 6, WHITE); case 6: display.fillRect(40, 58, 2, 6, WHITE); case 5: display.fillRect(35, 58, 2, 6, WHITE); case 4: display.fillRect(30, 58, 2, 6, WHITE); case 3: display.fillRect(25, 58, 2, 6, WHITE); case 2: display.fillRect(20, 58, 2, 6, WHITE); case 1: display.fillRect(15, 58, 2, 6, WHITE); }}void statup_text() { display.setTextSize(1); display.setCursor(13, 18); display.print(«Si5351 VFO/RF GEN»); display.setCursor(6, 40); display.print(«JCR RADIO — Ver 2.0»); display.display(); delay(2000);} |
Поддержка друг друга добрыми согревающими словами участия в трудную минуту. Искренние пожелания удачи и радости в жизни.
Добрые слова поддержки и участия совершенно незнакомых людей. Искреннее общение на уровне доброты и помощи. Поддержка друг друга согревающими словами.
Добрые длинные слова, душевные раздумья. Согревающие слова участия, полные заботы, сил, любви многих людей.
Короткие добрые слова опоры и участия в трудную минуту. Чтение добрых слов – это жизнеутверждающее действо.
Добрые слова, согревающие фразы из книг, ставшие для людей палочкой-выручалочкой в трудную минуту.
К Вашим услугам «краткая всемирная история искусств», в которой моменты мировой истории искусств изложены в краткой форме. История искусств говорит о красоте и таинстве цвета и линий.
100 тем по изобразительному искусству и архитектуре мира изложены в краткой форме. Нужно для быстрого самообразования, турпоездок и невероятно любопытно.
Фразы о жизни с её трудностями и проблемами великих мира сего. Фразы, которые хочется повторить, несут в себе мудрость поколений.
Пословицы и поговорки народов России. Интересно и, что удивительно, ещё и верно. Мы не Иваны, не помнящие родства. Чтение и осмысление.
Публикация стихов пользователей. Бывают и всем интересны такие ненапечатанные стихи, от которых просто оторваться невозможно.



