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;
}
}
Saturday, 26 January 2019
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.
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;
}
}
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.
#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