Sunday, March 29, 2015

Si5351 VHF VFO

Link to  VHF_VFO.ino
I can tune up to 160Mhz. Output with default current setting is about -10dbm.
 /*
  This entire program is taken from Jason Mildrum, NT7S and Przemek Sadowski, SQ9NJE and Ben     Buxton.
  
  ***The following code has been modified to use the updated library of NT7S. 
  As of this date, the library is still undergoing changes so be aware of that.
  This code was tested on an Arduino Uno ONLY and it works if you setup your
  Equally important is that you make sure that Jason's new library REPLACES any existing
  Si5351 libraries in places that the Arduino IDE will look for it. Remove the existing Si5351 folder   in the "Arduino/Libraries" folder and put it in another folder for safe keeping in case you need to use it again.  I made a folder called Lib_Temp to put user libraries not in use. If you get errors
  it will most likely be for this reason. Please spend the time to resolve this problem.
  MAKE SURE THE ARDUINO IDE IS CLOSED WHEN MAKEING CHANGES TO THE LIBRARY.
  For help on the proper place to put libraries look here:
  Jason's new library will break existing code using his older library.
  */

  #include <Rotary.h>
  #include <si5351.h>
  #include "Wire.h"
  #include <LiquidCrystal.h>
 
  #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

  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 frequency0 = 1000000000L / SI5351_FREQ_MULT; //10Mhz - change to suit your needs
  //just take care to count the right number of zeros.
//  volatile uint32_t frequency1 = 9000000L;
//  volatile uint32_t frequency2 = 10000000L;
  volatile uint32_t radix = 100;
  boolean changed_f = 0;

  /**************************************/
  /* 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)
      frequency0 += radix;
    if(dir == -1)
      frequency0 -= 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(3, 0);
    f = frequency0 / 1000000;
    if(f<10)
      lcd.print(' ');
    lcd.print(f);
    lcd.print('.');
    f = (frequency0 % 1000000)/1000;
    if(f<100)
      lcd.print('0');
    if(f<10)
      lcd.print('0');
    lcd.print(f);
    lcd.print('.');
    f = frequency0 % 1000;
    if(f<100)
      lcd.print('0');
    if(f<10)
      lcd.print('0');
    lcd.print(f);
    lcd.print("Hz");
  }

  /**************************************/
  /* Displays the frequency change step */
  /**************************************/
  void display_radix()
  {
    lcd.setCursor(10, 1);
    switch(radix)
    {
      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.print("100k");
        break;
        case 1000000:
        lcd.setCursor(9, 1);
        lcd.print("1000k"); //1MHz increments
        break;
    }
    lcd.print("Hz");
  }


  void setup()
  {
    lcd.begin(16, 2);                                                    // Initialize and clear the LCD
    lcd.clear();
    Wire.begin();
    // Start serial and initialize the Si5351 with load capacitance and crystal freq
//0 will provide default freq of 25Mhz. If you have a 27MHz crystal put in 27000000
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); //you could measure your crystal and put it here to    correct for errors.
// Set CLK0 to output 10 MHz with a fixed PLL frequency
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
//set frequency with 1 Hz resolution
si5351.set_freq(frequency0 * SI5351_FREQ_MULT, SI5351_PLL_FIXED, SI5351_CLK0);
 
     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();
  }


  void loop()
  {
    // Update the display if the frequency has been changed
    if(changed_f)
    {
      display_frequency();    
      si5351.set_freq(frequency0 * SI5351_FREQ_MULT, 0, SI5351_CLK0);
      changed_f = 0;
    }
 
    // Button press changes the frequency change step
    if(get_button())
    {
      switch(radix)
      {
        case 10:
          radix = 100;
          break;
        case 100:
          radix = 1000;
          break;
        case 1000:
          radix = 10000;
          break;
          case 10000:
          radix = 100000;
          break;
        case 100000: //change these lines to tune in 1MHz increments
          radix = 1000000;
          break;
        case 1000000:
          radix = 10;
          break;
      }
      display_radix();
    }
  }