Настроить кнопки генератора на si5351 и Arduino Nano

Здравствуйте. Помогите сделать изменения в скетче.
Имеется:
генератор частот на Ардуино Нано, совместно с si5351, вывод на дисплей 1602 по i2c.
Функции генератора:
Вывод на дисплей 2-х значений частоты от 10 КГц, до 210 МГц по каналам CLK0 и CLK1.
Перестройка частоты по одному каналу, по второму каналу и одновременно на двух каналах.
Кнопка выбора каналов:
#define VFO_USES_SW 4 // get_btn(1) кнопка выбора текущего канала: CLK0, CLK1, CLK0+CLK1
Кнопка вкл/выкл каналов:
#define CLK_CN_OFF 15 // get_btn(2) кнопка вкл/выкл каналов ON/OFF
Проблема:
При выборе канала CLK0 частота генератора меняется, при выборе CLK1 частота генератора тоже меняется. При выборе обоих генераторов CLK0+CLK1 частота на НИХ одновременно не меняется. Как исправить?
Я действительно новичок и это моя первая ардуинка. :slight_smile:
Вод код, который я выдернул из другого скетча и совместно с нейросетью сделал полу-рабочий вариант.

#include "si5351mcu.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h> // библиотека управления экраном lcd1602 по I2C

/***********************************************************************************************/

#define F_MIN        10000UL     // Нижний предел частоты
#define F_MAX        210000000UL // Верхний предел частоты
#define quartz       25000000    // Действительная частота кварца 
/* При наличии точного частотомера, подключить прибор, выставить на выходе С1 или С0, частоту
    25 000 000 Гц,  затем вращая ручку энкодера получить на дисплее частотомера
    показания 25 000 000 герц,  полученное значение ввести в поле #define quartz
*/
#define ENCODER_A    2           // Encoder pin A
#define ENCODER_B    3           // Encoder pin B
#define ENCODER_BTN  11          // get_btn(0) кнопка "STEP" шаг изменения частоты      
#define VFO_USES_SW  4           // get_btn(1) кнопка выбора текущего канала: CLK0, CLK1, CLK0+CLK1
#define CLK_CN_OFF   15          // get_btn(2) кнопка вкл/выкл каналов ON/OFF
/***********************************************************************************************/

LiquidCrystal_I2C  lcd(0x27, 16, 2);    //I2C Address 0x27 (or 0x3F)  используется для новых библиотек lcd_1602 и подобных экранов
Si5351mcu si;

const byte act_vfo_simbol[8] = {
  B00010,
  B00110,
  B01110,
  B11110,
  B01110,
  B00110,
  B00010,
  0
};// программируемый символ активного генератора

const uint32_t radix_size[8] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000}; // шаги частоты

const char* radix_lcd[8] = {"   1", "  10", " 100", "  1K", " 10K", "100K", "  1M", " 10M"};
// массив значений выводимых на экран

volatile byte radix_num = 6;// порядковый номер в таблице шагов, должен быть равен старт radix

volatile uint32_t radix = radix_size[6];  // Шаг перестройки по умолчанию при старте = 1MГц
volatile uint32_t vfo[4] = {30000000UL, 31000000UL}; //стартовая частота при запуске синтезатора.

const byte SW[3] = {ENCODER_BTN, VFO_USES_SW, CLK_CN_OFF};
volatile boolean  SW_save[3];

boolean  changed_f = 0;  // флаг разрешения изменения частоты, 0 - запрет

boolean  encA_sav = 1;
boolean  encB_sav = 1;

boolean  dispF_on = 1;   // флаг отображения частоты
boolean  dispF_on_save;

byte     vfo_act0 = 0;   // флаг активности канала CLK0
byte     vfo_act1 = 0;   // флаг активности канала CLK1

//byte       swp_on = 0;   // выбранный режим работы, 0,1 (1 = ГКЧ)
byte     vfo_uses = 0;   // выбранный канал
short    incr;           // направление приращения частоты, значения : -1, 1, 0
volatile uint32_t f_swp = 0;

/**************************************/
/* Установка частоты                  */
/* incr - направление приращения      */
/* vfo_num - номер канала si5351      */
/**************************************/
void set_frequency(byte vfo_num)
{
  uint32_t t_vfo;
  t_vfo = vfo[vfo_num];
  if (incr == 1)
    t_vfo += radix;
  if (incr == -1)
    t_vfo -= radix;

  if ((t_vfo <= F_MAX) & (t_vfo >= F_MIN))
    vfo[vfo_num] = t_vfo;
}

/*********************************************/
/* обработка включения/выключения каналов Si */
/*********************************************/
void vfo_enable_sw()
{
  if (get_btn(2))
  {
      if (vfo_uses == 0) if (vfo_act0) vfo_act0 = 0; else vfo_act0 = 1; // если CLK0 = ON то OFF
      else if (vfo_uses == 1) if (vfo_act1) vfo_act1 = 0; else vfo_act1 = 1; // если CLK1 = ON то OFF

    else if (vfo_uses == 2)
    {
      if (vfo_act0 & vfo_act1) {
       vfo_act0 = 0; vfo_act1 = 0;
      }
      else {
        vfo_act0 = 1; vfo_act1 = 1;
      }
    }
    out_clk_en();
    display_active_VFO();
  }
}

 

/*void vfo_enable_sw()
{
  if (get_btn(2))
  {
    // Переключаем состояние обоих каналов одновременно
    if (vfo_act0 & vfo_act1) { // Если оба включены
      vfo_act0 = 0;
      vfo_act1 = 0;
    } else { // Если хотя бы один выключен
      vfo_act0 = 1;
      vfo_act1 = 1;
    }
    out_clk_en();
    display_active_VFO();
  }
}*/


/**************************************/
/*         Обработка кнопок           */
/**************************************/

boolean get_btn(byte btn_num)
{
  boolean _tmp;
  _tmp = digitalRead(SW[btn_num]);
  if (!_tmp & SW_save[btn_num])
  {
    SW_save[btn_num] = _tmp;
    return 1;
  }
  SW_save[btn_num] = _tmp;
  return 0;
}


/**************************************/
/*          Обработка энкодера        */
/**************************************/
void encoder()
{
  boolean encA, encB;
  encA = digitalRead(ENCODER_A);
  encB = digitalRead(ENCODER_B);
  if ((!encA && encA_sav) or (!encB && encB_sav))
  {
    if (encA > encB) {
      incr = 1;
      return;
    }
    else if (encA < encB) {
      incr = -1;
      return;
    }
    encA_sav = encA;
    encB_sav = encB;
    changed_f = 1;
    return;
  }
  encA_sav = encA;
  encB_sav = encB;
  changed_f = 0;
  return;
}

/************************************* ОТОБРАЖЕНИЕ ИНФОРМАЦИИ НА LCD ************************/

/*******************************************/
/* Отображение частоты текущего генератора */
/*******************************************/
void display_frequency(byte f_num)
{
  uint16_t f, fs;
  uint32_t x_vfo;

  if (dispF_on)
  {
    x_vfo = vfo[f_num];
    lcd.setCursor(0, f_num);
    lcd.print(' ');
    fs = x_vfo / 1000000; 	// делим частоту до мегагерц
    if (fs < 10)
      lcd.print(' ');
    if (fs > 99)
      lcd.setCursor(0, f_num);
    if (fs > 0)
    { lcd.print(fs);
      lcd.print('.');
    }
    else
    { lcd.print(' ');
      lcd.print(' ');
    }
    f = (x_vfo % 1000000) / 1000; // остаток деления на 1 000 000,  делим на 1000 до килогец

    if (f < 100 and fs > 0)
      lcd.print('0');

    if (f < 100 and fs < 1)
      lcd.print(' ');

    if (f < 10)
      lcd.print('0');

    lcd.print(f);
    lcd.print('.');

    f = x_vfo % 1000; // остаток деления,  сотни герц

    if (f < 100)
      lcd.print('0');

    if (f < 10)
      lcd.print('0');

    lcd.print(f);
  }
}

/*********************************/
/* Отображаем активный генератор */
/*********************************/
void display_active_VFO()
{
  char sign1, sign2;

  if (vfo_act0) sign1 = 0; else sign1 = '<';
  if (vfo_act1) sign2 = 0; else sign2 = '<';

  if  (vfo_uses == 0)
    sign2 = ' ';
  else if (vfo_uses == 1)
    sign1 = ' ';

  lcd.setCursor(11, 0);
  lcd.print(sign1);
  lcd.setCursor(11, 1);
  lcd.print(sign2);
}

/********************************** */
/* Отображаем шаг изменения частоты */
/************************************/
void display_radix()
{
  lcd.setCursor(12, 0);
  lcd.print(radix_lcd[radix_num]); // на экран значение приращения из таблицы
}

/****************************************** ON | OFF VFO ************************************/
void out_clk_en()
{
  if (vfo_act0) si.enable(0); else si.disable(0); // при "истинно" вкл. выхода Si
  if (vfo_act1) si.enable(1); else si.disable(1); // иначе выключить
}


/******************************************   MAIN   *****************************************/
void setup()

{
  lcd.init();                      // Инициализация дисплея
  lcd.backlight();                 // Подключение подсветки
  lcd.createChar(0, act_vfo_simbol); // загрузка символа 0 в LCD
  lcd.clear(); // очитска экрана и памяти LCD
  Wire.begin(); // запуск обмена по I2C

  // Инициализация  Si5351
  si.init(quartz);
  // если 27Mhz кварц, вводим 27000000, для 25Мгц вводим 25000000, затем:
  // изм. показания контр. частотомера / на отображаемую LCD частоту * 25МГц, вводим значение.
  si.setFreq(0, vfo[0]);    // предустановка частоты CLK0
  si.setFreq(1, vfo[1]);    // тоже для CLK1
  si.setPower(0, SIOUT_8mA);// ток выхода для 50 Ом
  si.setPower(1, SIOUT_8mA);// возможные значения тока выхода 2,4,8МА
  si.off();                 // все выходы в ноль

  pinMode(ENCODER_BTN,  INPUT_PULLUP);
  pinMode(ENCODER_A,    INPUT_PULLUP);
  pinMode(ENCODER_B,    INPUT_PULLUP);
  pinMode(VFO_USES_SW,  INPUT_PULLUP);
  pinMode(CLK_CN_OFF,   INPUT_PULLUP);

  display_frequency(0);  // обновление дисплея
  display_frequency(1);  // обновление дисплея
  display_active_VFO();  // отображение доступного для перестройки канала синтезатора
  display_radix();       // шаг приращения частоты на экран
}

void loop() {
  encoder(); // Обработка энкодера

  if (get_btn(0)) { // Кнопка "STEP"
    radix_num++;
    if (radix_num > 7) radix_num = 0;
    radix = radix_size[radix_num];
    display_radix();
  }

  if (get_btn(1)) { // Кнопка выбора VFO
    vfo_uses++;
    if (vfo_uses > 2) vfo_uses = 0;
    display_active_VFO();
  }

  vfo_enable_sw(); // Кнопка включения/выключения VFO

  if (changed_f) {
    set_frequency(vfo_uses); // Обновление частоты выбранного VFO

    // **Устанавливаем частоты для CLK0 и CLK1**
    si.setFreq(0, vfo[0]); // Установка частоты на Si5351 CLK0
    si.setFreq(1, vfo[1]); // Установка частоты на Si5351 CLK1

    display_frequency(0);   // Обновление дисплея
    display_frequency(1);   // Обновление дисплея
    changed_f = 0;          // Сброс флага
  }
}

 /*vfo_enable_sw(); // Кнопка включения/выключения VFO

  if (changed_f) {
    // Обновление частоты для обоих VFO
    set_frequency(0);
    set_frequency(1);

    // Устанавливаем частоты для CLK0 и CLK1
    si.setFreq(0, vfo[0]); // Установка частоты на Si5351 CLK0
    si.setFreq(1, vfo[1]); // Установка частоты на Si5351 CLK1

    display_frequency(0);   // Обновление дисплея
    display_frequency(1);   // Обновление дисплея
    changed_f = 0;          // Сброс флага
  }*/

В принципе для меня пойдет и такой вид генератора. но хотелось бы его немного адаптировать под свои потребности.

Никто не будет для Вас ковыряться в чужом (не Вами написанном) коде, да ещё и в пятницу. Скорее всего:

  1. Вас пошлют дальше к Вашей нейросети. Сделала неправильно - пусть исправляет!
  2. Посоветуют для начала “помигать светодиом”.

И будут правы. Учитесь программировать сами, учитесь отлаживать программу. Начинайте с простого. Постепенно усложняйте.Отладка может занимать в разы больше времени и сил, чем написание исходного варианта кода.
Пример: Вот у Вас “не меняется частота”. Найдите место, где у Вас в коде по Вашему мнению она должна меняться. Поставьте в этом месте печать чего-нибудь в serial или на дисплей. Таким образом убедитесь, что вы попадаете в это место в коде. Если Вы передаёте генератору какие-то значения, выведите и эти значения, чтобы убедиться, что они такие, как Вы думаете. И т.д., и т.п.
Разбейте программу на части. Например, поуправляйте Вашим генератором просто из программы без всяких дисплеев и энкодеров. Убедитесь, что у Вас получается перевести генератор в любой нужный Вам режим.
Изучите примеры от библиотеки. Правильно ли Вы работаете с Вашим генератором?
А сейчас Вы предлагаете кому-то заняться отладкой Вашего (точнее, ещё и не Вашего) скетча в уме.
Если же Вам срочно нужно подобное устройство, найдите и повторите готовую конструкцию без модификаций.

2 лайка

Всё что выше 120МГц на si5351 возможно ТОЛЬКО на гармониках (я говорю о si5351 из Китая, в оригинальной после 160МГц).
Да и ниже 50кГц у si5351 генерация не на всех экземплярах бывает, и уж точно не до 10кГц. Минимально мне удавалось на отдельном экземпляре 38кГц и то неустойчиво.

Спасибо добрый человек. Я всегда знал что люди вокруг осень отзывчивы.. :slight_smile:

Работает от 4 КГц до 225 МГц устойчиво.

Я рад за Вас, значит свой вопрос Вы можете решить и без внешнего (нашего) участия.

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

А нафига тогда ваш форум нужен? :slight_smile: Для чего вы тут торчите?
А, понял, вы здесь чтобы перемывать кости, собирать сплетни и самоутверждаться за счёт других. ))) В принципе как и на всех остальных форумах, ничего нового.

Для того, конечно же, чтоб барин пальцами щёлкнул и холопы ему за 5 минут код поправили

Денег не дам. )

Новый поцыэнт подъехал.

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

Тогда у вас всё впереди.
Начните с функции set_frequency(), разберитесь, как она работает, откуда вызывается.
Вот вариант решения, возможно ещё где-то придётся править
Проверить, конечно, не на чем

Спойлер
void set_frequency(byte vfo_num)
{
  uint32_t t_vfo;
  byte cycle = 1;
  
 if(vfo_num == 2)
 {
  cycle = 2;
  vfo_num = 0;
 }
 while(cycle--)
 {	 
  t_vfo = vfo[vfo_num++];
  if (incr == 1)
    t_vfo += radix;
  if (incr == -1)
    t_vfo -= radix;

  if ((t_vfo <= F_MAX) && (t_vfo >= F_MIN))
    vfo[vfo_num] = t_vfo;
 }
}

P.S. Исправил .
Вот правильный вариант.

Спойлер
void set_frequency(byte vfo_num)
{
  uint32_t t_vfo;
  byte cycle = 1;
  
 if(vfo_num == 2)
 {
  cycle = 2;
  vfo_num = 0;
 }
 while(cycle--)
 {	 
  t_vfo = vfo[vfo_num];
  if (incr == 1)
    t_vfo += radix;
  if (incr == -1)
    t_vfo -= radix;

  if ((t_vfo <= F_MAX) && (t_vfo >= F_MIN))
    vfo[vfo_num++] = t_vfo;
 }
}

Ничего я не понимаю. Перебираю варианты где что включить и ничего не получается. Ладно, не моё это…

Замените функцию set_frequency() в коде из #1 поста (стр69 - 80) на ту, что я написал (#14 пост)

Менял, логика вообще вся сбилась. Меняется частота сразу на двух генераторах,а по отдельности их нельзя выбрать.
Да ну его…

И то верно. Зачем он тебе сдался? Пиво/вотка и дефки интереснее )))

3 лайка

Ну да. С таким настроем лучше и не браться.

Тут недавно тема была про принтер ~ 700 постов!
Вот это терпение)))

И, кстати, @Android-I , это как раз хороший признак, того, что выбран верный путь, подобрались к нужным участкам кода.

Это я на всякий случай, если вдруг надумаете когда-нибудь доделать…