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

10 comments:

  1. Hi Charlie,
    nice job..
    de SV3IRG Dinos..73.

    ReplyDelete
  2. Thanks Kostas. I'm trying to keep it simple for a start and see how it goes.

    ReplyDelete
  3. Hi Charlie,
    I try to copy the software file and upload it in the arduino but it give a fault can you help me.

    Thanks Robert

    ReplyDelete
    Replies
    1. Probably not Robert. Do a compile and read the error messages carefully. I suspect your LCD library is the culprit. Open the example sketch that comes with the library in your IDE and see if the syntax is different. Adjust my code to have the same syntax and recompile.

      Delete
  4. As per the Setup function within the code. I don't have a specific wiring diagram sorry.

    ReplyDelete
  5. How to connect a0 a1 a2 a3 from out directional coupler? A0 frwd A1 ref. A2 pwr cal A3 swr cal.

    ReplyDelete
    Replies
    1. Hi. As per the code:

      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

      Delete
  6. Hi can I ask where is the connection for the LCD . Thank you God bless

    ReplyDelete
  7. Hi. It's a 4 wire connection using I2C: Ground, Vcc, SDA and SCL.

    ReplyDelete

Note: only a member of this blog may post a comment.