VFO COM SI5351 até 225MHz*  - Variante do Multi-featured VFO
* valor testado na minha montagem

Este artigo refere-se a este link :

Multi-Featured VFO April, 6 , 2015

Veja tambem detalhes de layout em :

Si5351 simple VFO hardware setup
 

Fizemos algumas simples modificações no VFO anterior uma foi o aumento da frequencia de operação
, outro foi no step : pois para alterar o step ou passo era necessario comprimir o botão do encoder e o passo era aumentado, mas o passo somente caminhava em uma direção: subindo até o maximo e ai retornava ao inicio.
Modifiquei para que ao pressionar o botão do encode aparece um sublinhado (underline) que mantendo pressionado e girando o sublinhado muda de casa decimal (para cima ou para baixo) e ao  soltar o botão a casa decimal selecionanda podera ser alterada.
Outra modificação que fizemos foi gerar 3 sketches (o artigo original tambem tinha estas opções) sendo um para conversão direta, outro para SSB ou superjheterodino e um terceiro para operação com fase ou SDR com o VFO a quatro vezes a frequencia do display.

Esquema :


A cópia da biblioteca esta aqui  library NT7S  por motivos de update.

Outros sketches após este

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Sketch "conversão direta" DC - frequencia do display igual a frequencia de saida
(em CLK0).

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX



/*
This entire program is taken from Jason Mildrum, NT7S and Przemek Sadowski, SQ9NJE.
There is not enough original code written by AK2b to make it worth mentioning.
http://nt7s.com/
http://sq9nje.pl/
http://ak2b.blogspot.com/
I made some mods ...first updating the sketch to new library from NT7S
..in frequency coverage and the mode for frequency change..
pressing the encoder and turn it at same time ...it will move a underline showing
 the place where it is OK to change
 THIS SKETCH IS A VFO FOR Direct Conversion equipments or frequency generator
 http://py2ohh.w2c.com.br/
*/

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



#define F_MAX        23000000000UL

#define ENCODER_A    3                      // Encoder pin A  nano/uno pin D3
#define ENCODER_B    2                      // Encoder pin B  nano/uno pin D2
#define ENCODER_BTN  11
#define LCD_RS       5                     // LCD pin 4
#define LCD_E        6                  // LCD pin 6 nano/uno pin D6
#define LCD_D4        7                  // LCD pin11 nano/uno pin D7
#define LCD_D5        8                  // LCD pin12 nano/uno pin D8
#define LCD_D6        9                  // LCD pin13 nano/uno pin D9
#define LCD_D7        10                  // LCD pin14 nano/uno pin D10

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);

volatile uint32_t vfo = 700000000ULL / SI5351_FREQ_MULT; //start freq now 7MHz- change to suit
volatile uint32_t radix = 100;    //start step size - change to suit

boolean changed_f = 0;
String tbfo = "";
short und = 3;   //controle do underline
short pot = 3;   // controle de multiplicador

#define Direct_conversion //What you see on display is what you get

/**************************************/
/* 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 and underline  */
/* dir = 1    Increment               */
/* dir = -1   Decrement
/**************************************/
void set_frequency(short dir)
{
   if (!digitalRead(ENCODER_BTN)){
     lcd.setCursor( 12-und,0);
  if (dir == 1){
     und += 1;
     switch (und) {
       case 4 :
       und=5;
       break;
       case 8 :
       und=9;
        break;
       case 12 :
       und=11;
        break;
     }
   
      }
   
  if (dir == -1){
     und += -1;
     switch (und) {
       case 4 :
       und=3;
       break;
       case 8 :
       und=7;
        break;
       case 0 :
       und=1;
        break;
     }
      }
     pot = und;
    if (und > 3) (pot += -1);
     if (und > 7) (pot += -1);
    
    
    lcd.setCursor( 12-und,0);
 lcd.cursor();
    }
   
   else
    {lcd.noCursor();
      if (dir == 1)
     vfo += radix;
     if (dir == -1){
     if  (vfo > radix ) {
    vfo -= radix;
     }}
    
     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(1, 0);
 
  f = (vfo )/ 1000000;     //variable is now vfo instead of 'frequency'
  if (f < 100)  {
  lcd.print(' '); }
 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");
 
 

}


void setup()
{
  Serial.begin(19200);
  lcd.begin(16, 2);                                                    // Initialize and clear the LCD
  lcd.clear();
  Wire.begin();

  si5351.set_correction(140); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  //where you can determine the correction by using the serial monitor.

  //initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 27000000,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 = ?
 
  //si5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_2MA); //you can set this to 2MA, 4MA, 6MA or 8MA
  //be careful though - measure into 50ohms
 

#ifdef Direct_conversion
  si5351.set_freq((vfo * SI5351_FREQ_MULT), 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
 
}


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



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



    changed_f = 0;
  }

 
  if (get_button())
  {
    switch (pot)
    {
      case 1:
        radix = 1;
        break;
      case 2:
        radix = 10;
        break;
      case 3:
        radix = 100;
        break;
      case 4:
        radix = 1000;
        break;
        case 5:
        radix = 10000;
        break;
        case 6:
        radix = 100000;
        break;
        case 7:
        radix = 1000000;
        break;
        case 8:
        radix = 10000000;
        break;
        case 9:
        radix = 100000000;
        break;
       
    }
   
  }
}

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Sketch para equipamentos por fase ou SDR com o VFO em uma frequencia 4x a mostrada no display (em CLK0).

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

/*
This entire program is taken from Jason Mildrum, NT7S and Przemek Sadowski, SQ9NJE.
There is not enough original code written by me to make it worth mentioning.
http://nt7s.com/
http://sq9nje.pl/
http://ak2b.blogspot.com/
I made some mods ...first updating the sketch to new library from NT7S
..in frequency coverage and the mode for frequency change..
pressing the encoder and turn it at same time ...it will move a underline showing
 the place where it is OK to change
 THIS SKETCH IS A VFO FOR SDR equipments that uses VFO freq. at 4x
 http://py2ohh.w2c.com.br/
*/

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


#define F_MIN        100000000UL               // Lower frequency limit
#define F_MAX        23000000000UL

#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

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);


volatile uint32_t vfo = 700000000ULL / SI5351_FREQ_MULT; //start freq - change to suit
volatile uint32_t radix = 100;    //start step size - change to suit


boolean changed_f = 0;
String tbfo = "";
short und = 3;
short pot = 3;

#define FreqX4  //output is four times the display frequency
//--------------------------------------------------------------------------------------------------


/**************************************/
/* 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   Decrement56
/**************************************/
void set_frequency(short dir)
{
   if (!digitalRead(ENCODER_BTN)){
     lcd.setCursor( 12-und,0);
  if (dir == 1){
     und += 1;
     switch (und) {
       case 4 :
       und=5;
       break;
       case 8 :
       und=9;
        break;
       case 12 :
       und=11;
        break;
     }
   
      }
   
  if (dir == -1){
     und += -1;
     switch (und) {
       case 4 :
       und=3;
       break;
       case 8 :
       und=7;
        break;
       case 0 :
       und=1;
        break;
     }
      }
     pot = und;
    if (und > 3) (pot += -1);
     if (und > 7) (pot += -1);
    
    
    lcd.setCursor( 12-und,0);
 lcd.cursor();
    }
   
   else
    {lcd.noCursor();
      if (dir == 1)
     vfo += radix;
     if (dir == -1){
     if  (vfo > radix ) {
    vfo -= radix;
     }}
    
     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(1, 0);
 
  f = (vfo )/ 1000000;     //variable is now vfo instead of 'frequency'
  if (f < 100)  {
  lcd.print(' '); }
 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(1, 1);
 lcd.print(tbfo);
  //Serial.println(vfo + bfo);
  //Serial.println(tbfo);

}




void setup()
{
  Serial.begin(19200);
  lcd.begin(16, 2);                                                    // Initialize and clear the LCD
  lcd.clear();
  Wire.begin();

  si5351.set_correction(140); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  //where you can determine the correction by using the serial monitor.

  //initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 27000000,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 FreqX4
  si5351.set_freq((vfo * SI5351_FREQ_MULT) * 4, 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
 
}


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

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

    changed_f = 0;
  }

  // Button press changes the frequency change step for 1 Hz steps
  if (get_button())
  {
    switch (pot)
    {
      case 1:
        radix = 1;
        break;
      case 2:
        radix = 10;
        break;
      case 3:
        radix = 100;
        break;
      case 4:
        radix = 1000;
        break;
        case 5:
        radix = 10000;
        break;
        case 6:
        radix = 100000;
        break;
        case 7:
        radix = 1000000;
        break;
        case 8:
        radix = 10000000;
        break;
        case 9:
        radix = 100000000;
        break;
       
    }
   
  }
}


XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Sketch para equipos SSB como ARARINHA, BINGO (antigo) e BITX ou equipamentos superheterodinos que usam uma frequencia intermediaria FI (no caso os valores são para FI de 10MHz - podendo ser alterada). A frequencia de saida pode ser (FI- frequencia) desejada ou (FI+frequencia) desejada. Saida do VFO em CLK0 e do BFO em CLK2.  Para alterações nestas funções favor entrar em contato comigo via email ...
[email protected] remover os xxx...

XXXXXXXXXXXXXXXXXXXXXXXXXXXX



/*
This entire program is taken from Jason Mildrum, NT7S and Przemek Sadowski, SQ9NJE.
There is not enough original code written by me to make it worth mentioning.
http://nt7s.com/
http://sq9nje.pl/
http://ak2b.blogspot.com/
I made some mods ...first updating the sketch to new library from NT7S
..in frequency coverage and the mode for frequency change..
pressing the encoder and turn it at same time ...it will move a underline showing
 the place where it is OK to change
 THIS SKETCH IS A VFO FOR superheterodine or SSB equipments that uses IF
 http://py2ohh.w2c.com.br/
*/

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


#define F_MIN        100000000UL               // Lower frequency limit
#define F_MAX        23000000000UL

#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

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);
//Valores para um FI de 10MHz altere se necessario
//Values for IF=10MHz change if necessary
volatile uint32_t LSB = 999950000ULL; //LSB = IF - 1500Hz
volatile uint32_t USB = 1000150000ULL; // USB = IF +1500Hz
volatile uint32_t bfo = 1000000000ULL; //Intermediary frequency IF
//These USB/LSB frequencies are added to or subtracted from the vfo frequency in the "Loop()"
//In this example my start frequency will be 14.000000 plus 10.001500 or clk0 = 24.0015Mhz
volatile uint32_t vfo = 1400000000ULL / SI5351_FREQ_MULT; //start freq 7MHz - change to suit
volatile uint32_t radix = 100;    //

boolean changed_f = 0;
String tbfo = "";
short und = 3;
short pot = 3;
//-------------------------------  --------------------------------------

#define IF_Offset //Output is the display plus or minus the bfo frequency

/**************************************/
/* 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   Decrement56
/**************************************/
void set_frequency(short dir)
{
   if (!digitalRead(ENCODER_BTN)){
     lcd.setCursor( 12-und,0);
  if (dir == 1){
     und += 1;
     switch (und) {
       case 4 :
       und=5;
       break;
       case 8 :
       und=9;
        break;
       case 12 :
       und=11;
        break;
     }
   
      }
   
  if (dir == -1){
     und += -1;
     switch (und) {
       case 4 :
       und=3;
       break;
       case 8 :
       und=7;
        break;
       case 0 :
       und=1;
        break;
     }
      }
     pot = und;
    if (und > 3) (pot += -1);
     if (und > 7) (pot += -1);
    
    
    lcd.setCursor( 12-und,0);
 lcd.cursor();
    }
   
   else
    {lcd.noCursor();
      if (dir == 1)
     vfo += radix;
     if (dir == -1){
     if  (vfo > radix ) {
    vfo -= radix;
     }}
    
     changed_f = 1;
  }

    // 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(1, 0);
 
  f = (vfo )/ 1000000;     //variable is now vfo instead of 'frequency'
  if (f < 100)  {
  lcd.print(' '); }
 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(1, 1);
 lcd.print(tbfo);
 

}


void setup()
{
  Serial.begin(19200);
  lcd.begin(16, 2);                                                    // Initialize and clear the LCD
  lcd.clear();
  Wire.begin();

  si5351.set_correction(140); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  //where you can determine the correction by using the serial monitor.

  //initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 27000000,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_CLK0); //desligada
  volatile uint32_t vfoT = (vfo * SI5351_FREQ_MULT) + bfo;
  tbfo = "USB";
  // Set CLK2 to output bfo frequency
  si5351.set_freq( bfo, 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



  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
 
}


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

#ifdef IF_Offset
 
 
   if (vfo >= 10000000 )
    {
     bfo = USB;
      tbfo = "USB";
  si5351.set_freq((vfo * SI5351_FREQ_MULT) + bfo, SI5351_CLK0);
    si5351.set_freq( bfo, SI5351_CLK2);
     
    }
    else if (vfo < 10000000 )
    {
      bfo = LSB;
      tbfo = "LSB";
    
      si5351.set_freq((bfo -(vfo * SI5351_FREQ_MULT)) , SI5351_CLK0);
      si5351.set_freq( bfo, SI5351_CLK2);
     
    }
#endif

    changed_f = 0;
  }

 
  if (get_button())
  {
    switch (pot)
    {
      case 1:
        radix = 1;
        break;
      case 2:
        radix = 10;
        break;
      case 3:
        radix = 100;
        break;
      case 4:
        radix = 1000;
        break;
        case 5:
        radix = 10000;
        break;
        case 6:
        radix = 100000;
        break;
        case 7:
        radix = 1000000;
        break;
        case 8:
        radix = 10000000;
        break;
        case 9:
        radix = 100000000;
        break;
       
    }
    //display_radix();
  }
}


XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

73 de py2ohh may -2017