tiistai 6. syyskuuta 2016


 VHF 145MHz / 2m VCO using Adafruit si5351 and Arduino Nano.

Please look more refined code here:
https://oh2btg.blogspot.com/2018/10/si5351-phase-shift-measurements.html


Oscillator is covering frequency band 130...150MHz.
Frequency step is selectable from 1kHz...1MHz. Output frequency is not absolutely accurate. There can be few kHz error. Anyway it is suitable for radio amateur experiments
Here is Arduino code. It is heavily modified from other si5351 code made by
nt7s
sq9nje
ak2b

Eero
oh2btg(at)sral.fi

#include <Wire.h>
#include <Adafruit_SI5351.h>
#include <LiquidCrystal.h>
#include <rotary.h>
#include <si5351.h>

Adafruit_SI5351 clockgen = Adafruit_SI5351();

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

/* OH2BTG VHF version v 0,0,4

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

#define ENCODER_A    3                      // Encoder pin A
#define ENCODER_B    2                      // Encoder pin B
#define ENCODER_BTN  4 // Encoder c button
Rotary r = Rotary(ENCODER_A, ENCODER_B);
volatile uint32_t vfo = 145500000 ;//start freq
uint32_t radix = 12500; //start step size 12.5kHz
uint32_t si5351ctl;
uint32_t si5351apu;
uint32_t si5351apu2;
boolean changed_f = 1;
String tbfo = "";
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); //  LCD: RS,E,D4,D5,D6,D7
/**************************************/
/* Displays the frequency             */
/**************************************/
void display_frequency()
{
  uint16_t f, g;
 lcd.clear();
  lcd.setCursor(3,0);
  f = vfo / 1000000;   //variable is now vfo instead of 'frequency' vfo esim 145787500
  si5351ctl = vfo * 24 / 100000;  // simple calculation for ctl word
  si5351apu = si5351ctl /1000;  // feedback divider integer
  si5351apu2 = si5351ctl % 1000; // feedback divider fraktion
  Serial.println(" si5351apu");
  Serial.println(si5351apu);
  Serial.println(" si5351apu2");
  Serial.println(si5351apu2);
  Serial.println(" si5351ctl");
  Serial.println(si5351ctl);
  Serial.println(" vfo");
  Serial.println( vfo);
 // Serial.println(f = vfo / 1000000); // printtaa f 145.XXX.XXX
  if (f < 10)
   lcd.print("");
  lcd.print(f);
  lcd.print(",");
  f = (vfo % 1000000) / 1000; // printtaa taajuuden 3 viim numeroa XXX.550.XXX
 // Serial.println (f = (vfo % 1000000) / 1000);
  if (f < 100)
    lcd.print("0");
  if (f < 10)
    lcd.print("0");
  lcd.print(f);
  lcd.print(".");
 // f = vfo % 1000;
   f = (vfo % 1000) / 100; // removing 2 last digit from frequency reading
 // Serial.println( f = vfo % 1000); // printtaa XXX.XXX.000
 // if (f < 100)
   // lcd.print("0");
 // if (f < 10)
  //  lcd.print("0");
  lcd.print(f); //
  lcd.print("MHz");
 // lcd.setCursor(0, 0);
 // lcd.print(tbfo);
//  Serial.println(vfo + bfo);
//  Serial.println(tbfo);
}

/**************************************/
/* Displays the frequency change step */
/**************************************/
void display_radix()
{
  lcd.setCursor(0, 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 12500:
      lcd.print("12.5k");
      break;
    case 100000:
      lcd.setCursor(0, 1);
      lcd.print(" 100k");
      break;
    case 1000000:
    lcd.setCursor(1, 1);
    lcd.print("  1M"); //1MHz increments
    break;
  }
  lcd.print("Hz");
        Serial.println("radix");
       Serial.println(radix);
}
/**************************************/
/* 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;
}

void setup(void)
{
    Serial.begin(115200);
   Serial.println(" Erska Testaa");
 // lcd.begin(16, 2);                        // Initialize and clear the LCD
 lcd.clear();
 lcd.setCursor(0,0);
    lcd.print("  OH2BTG ");
     lcd.setCursor(0,1);
    lcd.print("VHF v.0.0.4");
  delay(2000);  //2seconds
  Wire.begin();

  /* Initialise the sensor */
  if (clockgen.begin() != ERROR_NONE)
  {

    while(1);
  }

  /* Enable the clocks */
  clockgen.enableOutputs(true);
    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(void)
{
 // Update the display if the frequency has been changed
  if (changed_f)
  {
    display_frequency();
  clockgen.setupPLL(SI5351_PLL_A, (si5351apu),(si5351apu2), 1000); // write si5351ctl divider word
  clockgen.setupMultisynthInt(0, SI5351_PLL_A, SI5351_MULTISYNTH_DIV_6);

      changed_f = 0;
}
  // Button press changes the frequency step
  if (get_button())
  {
    switch (radix)
    {

   //   case 1:
   //     radix = 10;
   //     break;
   //   case 10:
    //    radix = 100;
    //    break;
     case 100:
        radix = 1000;
        break;
      case 1000:
        radix = 12500;
        break;
      case 12500:
        radix = 100000;
        break;
      case 100000:
        radix = 1000000;
        break;
      case 1000000:
      radix = 1000;
        break;
    }
    display_radix();
  }
}