Saturday, 26 January 2019

Si5351 Quadrature Clock Output down to 3MHz

Credit to Brian Harper M1CEM and Miguel BartiĆ© PY2OHH


Step 1. Edit si5351.h file. Change the SI5351_PLL_VCO_MIN to 380000000, i.e.,

#define SI5351_PLL_VCO_MIN              380000000


Step 2. Example code snippet:



volatile long freq = 3500000;
volatile int Even_Divisor = 0;
volatile int oldEven_Divisor = 0;




void EvenDivisor()
{
  if (freq < 6850000)
  {
    Even_Divisor = 126;
  }
  if ((freq >= 6850000) && (freq < 9500000))
  {
    Even_Divisor = 88;
  }
  if ((freq >= 9500000) && (freq < 13600000))
  {
    Even_Divisor = 64;
  }
  if ((freq >= 13600000) && (freq < 17500000))
  {
    Even_Divisor = 44;
  }
  if ((freq >= 17500000) && (freq < 25000000))
  {
    Even_Divisor = 34;
  }
  if ((freq >= 25000000) && (freq < 36000000))
  {
    Even_Divisor = 24;
  }
  if ((freq >= 36000000) && (freq < 45000000)) {
    Even_Divisor = 18;
  }
  if ((freq >= 45000000) && (freq < 60000000)) {
    Even_Divisor = 14;
  }
  if ((freq >= 60000000) && (freq < 80000000)) {
    Even_Divisor = 10;
  }
  if ((freq >= 80000000) && (freq < 100000000)) {
    Even_Divisor = 8;
  }
  if ((freq >= 100000000) && (freq < 146600000)) {
    Even_Divisor = 6;
  }
  if ((freq >= 150000000) && (freq < 220000000)) {
    Even_Divisor = 4;
  }
}


void SendFrequency()
{
  EvenDivisor();
  si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK0);
  si5351.set_freq_manual(freq * SI5351_FREQ_MULT, Even_Divisor * freq * SI5351_FREQ_MULT, SI5351_CLK2);
  si5351.set_phase(SI5351_CLK0, 0);
  si5351.set_phase(SI5351_CLK2, Even_Divisor);
 
if(Even_Divisor != oldEven_Divisor)
  {
    si5351.pll_reset(SI5351_PLLA);
    oldEven_Divisor = Even_Divisor;
  }
}




Monday, 14 January 2019

Homebrew Power/SWR Meter

Please see YouTube for details:

https://www.youtube.com/channel/UCSNPW3_gzuMJcX_ErBZTv2g

This is my first idea for a directional coupler. Please note that this is not suppose to be a competition or commercial grade device. My aim is to keep the costs down, but still have a functional power/SWR meter at the end.

Note also the 51 ohm (below) termination resistor is now 150 ohm.


Tandem coupler experiments. This is looking very promising with a wide frequency and power range.










Final Software:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

volatile float FwdVoltage = 0;
volatile float RevVoltage = 0;
volatile float PWR_Cal = 0;
volatile float SWR_Cal = 0;
volatile float PWR = 0;
volatile float SWR = 0;
volatile float FwdVoltageReadings[10];
volatile float FwdVoltageAverage;
volatile float RevVoltageReadings[10];
volatile float RevVoltageAverage;
volatile int FwdNumberOfLines = 0;
volatile int RevNumberOfLines = 0;
volatile int FwdNumberOfLinesToBlank = 0;
volatile int RevNumberOfLinesToBlank = 0;
volatile int AvCount = 0;

volatile double oldPWR = 0;
volatile double oldSWR = 0;

// Instantiate the Objects
LiquidCrystal_I2C lcd(0x27, 16, 2);

//Custom bar characters
const byte Bar1Array[8] = {B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000};
const byte Bar2Array[8] = {B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000};
const byte Bar3Array[8] = {B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100};
const byte Bar4Array[8] = {B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110};
const byte Bar5Array[8] = {B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111};

void setup()
{
  pinMode(A0, INPUT);                     //Fwd power voltage pin
  pinMode(A1, INPUT);                     //Rev power voltage pin
  pinMode(A2, INPUT);                     //PWR cal pin
  pinMode(A3, INPUT);                     //SWR cal pin

  //analogReference(EXTERNAL);

  Serial.begin(9600);
  // Initialize the display
  lcd.begin();
  lcd.backlight();
  lcd.createChar(1, Bar1Array);           //Special charaters for the PWR and SWR bar display
  lcd.createChar(2, Bar2Array);
  lcd.createChar(3, Bar3Array);
  lcd.createChar(4, Bar4Array);
  lcd.createChar(5, Bar5Array);
  UpdateDisplay();
}


void loop()
{
  FwdVoltage = analogRead(A0);
  RevVoltage = analogRead(A1);
  PWR_Cal = analogRead(A2);
  SWR_Cal = analogRead(A3);

  FwdVoltageReadings[AvCount] = FwdVoltage;             // Put fwd power reading into array
  RevVoltageReadings[AvCount] = RevVoltage;             // Put rev power reading into array
  AvCount++;

  if (AvCount == 9)                                     // 0 to 9 = 10 bins
  {
    FwdVoltageAverage = 0;
    RevVoltageAverage = 0;

    for (int x = 0; x <= 9; x++)
      FwdVoltageAverage = FwdVoltageAverage + FwdVoltageReadings[x];
    FwdVoltageAverage = FwdVoltageAverage / 10;                           // Calc average

    FwdVoltageAverage = FwdVoltageAverage - 136;                          // Subtract noise
    FwdVoltageAverage = abs(FwdVoltageAverage);                           // Make absolute (remove any negative)
    FwdVoltageAverage = FwdVoltageAverage * 5 / 1024;                     // covert into voltage
    FwdVoltageAverage = FwdVoltageAverage + (PWR_Cal * 5 / 1024);         // Cal to scope (no between 0 and 5)

    for (int x = 0; x <= 9; x++)
      RevVoltageAverage = RevVoltageAverage + RevVoltageReadings[x];

    RevVoltageAverage = RevVoltageAverage / 10;                           // Calc average
    RevVoltageAverage = RevVoltageAverage - 166;                          // Subtract noise
    RevVoltageAverage = abs(RevVoltageAverage);                           // Make absolute (remove any negative)
    RevVoltageAverage = RevVoltageAverage * 5 / 1024;                     // covert into voltage

    // Lookup table for forward power
    if (FwdVoltageAverage < 1.855)
      PWR = 0;
    else if ((FwdVoltageAverage >= 1.855) && (FwdVoltageAverage < 1.97))
      PWR = 1;
    else if ((FwdVoltageAverage >= 1.97) && (FwdVoltageAverage < 2.017))
      PWR = 2;
    else if ((FwdVoltageAverage >= 2.017) && (FwdVoltageAverage < 2.051))
      PWR = 3;
    else if ((FwdVoltageAverage >= 2.051) && (FwdVoltageAverage < 2.056))
      PWR = 4;
    else if ((FwdVoltageAverage >= 2.056) && (FwdVoltageAverage < 2.07))
      PWR = 5;
    else if ((FwdVoltageAverage >= 2.07) && (FwdVoltageAverage < 2.085))
      PWR = 6;
    else if ((FwdVoltageAverage >= 2.085) && (FwdVoltageAverage < 2.109))
      PWR = 7;
    else if ((FwdVoltageAverage >= 2.109) && (FwdVoltageAverage < 2.124))
      PWR = 8;
    else if ((FwdVoltageAverage >= 2.124) && (FwdVoltageAverage < 2.134))
      PWR = 9;
    else if ((FwdVoltageAverage >= 2.134) && (FwdVoltageAverage < 2.144))
      PWR = 10;
    else if ((FwdVoltageAverage >= 2.144) && (FwdVoltageAverage < 2.153))
      PWR = 11;
    else if ((FwdVoltageAverage >= 2.153) && (FwdVoltageAverage < 2.163))
      PWR = 12;
    else if ((FwdVoltageAverage >= 2.163) && (FwdVoltageAverage < 2.173))
      PWR = 13;
    else if ((FwdVoltageAverage >= 2.173) && (FwdVoltageAverage < 2.183))
      PWR = 14;
    else if ((FwdVoltageAverage >= 2.183) && (FwdVoltageAverage < 2.192))
      PWR = 15;
    else if ((FwdVoltageAverage >= 2.192) && (FwdVoltageAverage < 2.197))
      PWR = 16;
    else if ((FwdVoltageAverage >= 2.197) && (FwdVoltageAverage < 2.212))
      PWR = 17;
    else if ((FwdVoltageAverage >= 2.212) && (FwdVoltageAverage < 2.217))
      PWR = 18;
    else if ((FwdVoltageAverage >= 2.217) && (FwdVoltageAverage < 2.22))
      PWR = 19;

    // 20 - 24W
    else if ((FwdVoltageAverage >= 2.220) && (FwdVoltageAverage < 2.246))
      PWR = ((FwdVoltageAverage - 2.22) * 5 / .026) + 20;

    // 25 - 29W
    else if ((FwdVoltageAverage >= 2.246) && (FwdVoltageAverage < 2.266))
      PWR = ((FwdVoltageAverage - 2.246) * 5 / .02) + 25;

    // 30 - 34W
    else if ((FwdVoltageAverage >= 2.266) && (FwdVoltageAverage < 2.280))
      PWR = ((FwdVoltageAverage - 2.266) * 5 / .014) + 30;

    // 35 - 39W
    else if ((FwdVoltageAverage >= 2.280) && (FwdVoltageAverage < 2.300))
      PWR = ((FwdVoltageAverage - 2.280) * 5 / .02) + 35;

    // >= 40W
    else if (FwdVoltage >= 2.3)
      PWR = ((FwdVoltageAverage - 2.3) * 60 / .07) + 40;


    if ((PWR > 0) && (PWR < 3))
      FwdNumberOfLines = 1;
    else
      FwdNumberOfLines = PWR / 3.33;                        // Power bar. 100W / 30 segments = 3.33W per segment

    if (PWR == 0)
      SWR = 0;
    else
    {
      SWR = (1 + sqrt(RevVoltageAverage / FwdVoltageAverage)) / (1 - sqrt(RevVoltageAverage / FwdVoltageAverage));
      SWR = SWR / (SWR_Cal * 5 / 1024);                     // Cal to scope (no between 0 and 5)
    }
    RevNumberOfLines = SWR * 5;                             // One segment per SWR increment

    AvCount = 0;
  }

  if ((PWR != oldPWR) || (SWR != oldSWR))                   // Update display if PWR or SWR has changed
  {
    //SendTelemetryData();
    UpdateDisplay();
    oldPWR = PWR;
    oldSWR = SWR;
  }
}


void SendTelemetryData()
{
  Serial.print("Foward Reading Average: ");
  Serial.println(FwdVoltageAverage, 3);
  Serial.print("Reverse Reading Average: ");
  Serial.println(RevVoltageAverage, 3);
  Serial.print("Power to Load: ");
  Serial.println(PWR);
  Serial.print("SWR: ");
  Serial.println(SWR);
  Serial.println("");
}

void UpdateDisplay()
{
  //Display PWR
  lcd.setCursor(0, 0);
  lcd.print("PWR");
  lcd.setCursor(3, 0);
  lcd.print("     ");
  lcd.setCursor(4, 0);
  lcd.print(PWR, 0);

  //Display SWR
  lcd.setCursor(8, 0);
  lcd.print("SWR");
  lcd.setCursor(11, 0);
  lcd.print("     ");
  lcd.setCursor(12, 0);
  lcd.print(SWR, 1);

  //Draw PWR Bar
  FwdNumberOfLinesToBlank = 29 - FwdNumberOfLines;
  lcd.setCursor(0, 1);
  lcd.print("P");
  while (FwdNumberOfLines >= 5)
  {
    lcd.write(5);
    FwdNumberOfLines = FwdNumberOfLines - 5;
  }

  if (FwdNumberOfLines == 1)
    lcd.write(1);
  if (FwdNumberOfLines == 2)
    lcd.write(2);
  if (FwdNumberOfLines == 3)
    lcd.write(3);
  if (FwdNumberOfLines == 4)
    lcd.write(4);

  while (FwdNumberOfLinesToBlank  >= 5)
  {
    lcd.print(" ");
    FwdNumberOfLinesToBlank = FwdNumberOfLinesToBlank - 5;
  }

  // Blank sedment before 'S'
  lcd.setCursor(7, 1);
  lcd.print(" ");

  //Draw SWR Bar
  RevNumberOfLinesToBlank = 29 - RevNumberOfLines;

  lcd.setCursor(8, 1);
  lcd.print("S");
  while (RevNumberOfLines >= 5)
  {
    lcd.write(5);
    RevNumberOfLines = RevNumberOfLines - 5;
  }

  if (RevNumberOfLines == 1)
    lcd.write(1);
  if (RevNumberOfLines == 2)
    lcd.write(2);
  if (RevNumberOfLines == 3)
    lcd.write(3);
  if (RevNumberOfLines == 4)
    lcd.write(4);

  while (RevNumberOfLinesToBlank >= 5)
  {
    lcd.print(" ");
    RevNumberOfLinesToBlank = RevNumberOfLinesToBlank - 5;
  }
}

Friday, 11 January 2019

Homebrew 2 Tone Audio Oscillator


2 Tone oscillator. Based on two Wein bridge oscillators using LM358 op amps. See YouTube for detaails:

https://youtu.be/H3f-ex2S4Xw