/* This version of the active bridge measures either the forward ( anttena load ) and the reverse (radio source) impedances. This is achieved by a selection switch on D12, select low for source radio impedance or leave high for the antenna load impedance. An alternative selection for a bar graph of the rx signal and tx power is selected by switching D13 low, or the normal number values with D13 switch high or left high. Both D13 and D12 are programmed with "INPUT_PULLUP" commands, so can be left high or switch low to toggle the mode use. The 20character 4 line display is on a twi link, and in this version of meter, all four analogue ports are used. port 0 = forward vswr voltage port 1 = reflected vswr voltage port 2 = transmitter power port 3 = receiver signal strength A switch on Pin 13 is used to switch between the display Rx/Tx bar graph when grounded low, and antenna analyser mode when pin 13 is held high. Ardunio board used = Ardiuno Uno Written by Alastair GW0AJU date : 21/11/2017 */ #include // (no semicolon) //********** liquid display setup ********* #include #include #include #define I2C_ADDR 0x27 // <<- Add your address here. #define Rs_pin 0 #define Rw_pin 1 #define En_pin 2 #define BACKLIGHT_PIN 3 #define D4_pin 4 #define D5_pin 5 #define D6_pin 6 #define D7_pin 7 LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin); byte a[8] = {B00000, B01110, B10001, B10001, B01010, B01010, B11011,}; // character of the synbol of "ohm" byte b[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00000, B00000}; // character of the symbol of 0.0 s meter byte c[8] = {B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111}; // character of the symbol of 1.0 s meter int x_start_rx = 0; int x_rx = 0; int x_start_tx = 0; int x_tx = 0; int rx_bar_signal_value = 0; int rx_bar_signal = 0; int plot_rx = 0; float tx_bar_signal_value = 0; float tx_bar_signal_level = 0; float tx_bar_power_output = 0; int plot_tx = 0; float ratio = 0; float swr_value = 0; #define radio_antenna 13 // pin 13 used as logic switch between radio and antenna meter #define source_load 12 // the witch to the antenna load or radio source impedance //**************** SWR bridge and antenna load calculations **************** float rx_dbm =0; long swr_forward = 0; long swr_reflected = 0; float swr_match = 0; float vswr_forward = 0; float vswr_reflected = 0; float v_forward = 0; float v_reflected = 0; float v_forward_w = 0; float v_reflected_w = 0; float top = 0; float bot = 0; float swr_impedance = 0; float tswr_impedance = 0; float RL = 0; float Zin = 0; float swr =0; float opp = 0; float ind = 0; float cap = 0; float cap_scale = 0; float ind_scale = 0; float cap_scale_t = 0; float ind_scale_t = 0; float res = 0; float res_load = 0; int run_one = 1; float tx_power_measure = 0; float S_meter = 0; double over_load = 0; double signal_meter = 0; double rx_signal_value = 0; float RST_measure = 0; float load_scale = 0; int16_t adc0; //*********** transmitter power and receive signal power mearsurements ******** float rx_signal_level = 0; float rx_signal_voltage = 0; float tx_signal_level = 0; float tx_power_output = 0; //********** start of arduino DDS VFO control program ********* int clean_analyser = 0; int clean_bar = 0; void setup() { // ********* start up display messages ************ lcd.begin (20,4); // LCD Backlight ON lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE); lcd.setBacklight(HIGH); lcd.home(); lcd.createChar(0,a); // ohm lcd.createChar(1,b); // s meter block lcd.createChar(2,c); // s meter blank lcd.clear(); lcd.home(); lcd.setCursor(0,0); // first line of display lcd.print(" Bitx dual mode"); lcd.setCursor(0,1); lcd.print(" active bridge"); lcd.setCursor(0,2); // second line of display lcd.print(" program code by "); lcd.setCursor(0,3); // second line of display lcd.print(" Alastair GW0AJU"); delay(2500); lcd.clear(); lcd.home(); RL = 50; // start up antenna value pinMode(radio_antenna, INPUT_PULLUP); // pin 13 used as logic switch between radio and antenna meters pinMode(source_load, INPUT_PULLUP); // to select the measurement of the antenna load or radio source impedance } //************* void loop *********************** void loop() { if ( digitalRead(radio_antenna) == HIGH) // select antenna ananlyser meter { if (clean_analyser == 0) { lcd.clear(); lcd.home(); clean_analyser = 1; clean_bar = 0; } radio_monitor(); delay(300); // measurement sampling rate } if ( digitalRead(radio_antenna) == LOW) // select signal and power bar graph meter { if ( clean_bar == 0 ) { lcd.clear(); clean_analyser = 0; clean_bar = 1; lcd.home(); lcd.setCursor(0,1); lcd.print("0 5 9+ Rx 'S'"); lcd.setCursor(0,3); lcd.print("0 5 9 Tx 'W'"); lcd.home(); lcd.setCursor(0,0); lcd.write(byte(2)); lcd.setCursor(0,2); lcd.write(byte(2)); signal_meter = 0; over_load = 0; x_start_rx = 0; x_rx = 0; x_start_tx = 0; x_tx = 0; rx_bar_signal_value = 0; plot_rx = 0; tx_bar_signal_value = 0; plot_tx = 0; } plot_signal_rx(); plot_way_rx(); plot_signal_tx(); plot_way_tx(); } } //*************** start of program code sub-routines **************** //********************* Receiver bar graph plot ******************* void plot_signal_rx() { signal_meter = 0; over_load = 0; x_start_rx = 0; rx_bar_signal_value = 0; plot_rx = 0; rx_bar_signal_value = analogRead(3); if ( rx_bar_signal_value <= 10) // 10bit ADC setting { rx_bar_signal_value = 10.01; // error correction for maths } signal_meter = (rx_bar_signal_value - 10); // the value of 500 indicates an "S 9" signal for a 16bit ADC, RST from "Rx:0.1" up to "Rx:9.0 +42.33dB" // the value of 500 indicates an "S 9" signal for a 10bit ADC, RST from "Rx:1.0" up to "Rx:9.0 +6dB" over_load = 20*(double)log10(signal_meter); // for 10bit ADC for "S" meter rx_bar_signal = (over_load/0.6); plot_rx = rx_bar_signal / 10; // max analogue port value is 1024, thus divide by 100 for ten square plot x_start_rx = plot_rx; // to locate square plot x axis } void plot_way_rx() { if ( x_rx > x_start_rx) { down_rx(); x_rx = x_rx - 1; } if ( x_rx < x_start_rx) { x_rx = x_rx + 1; up_rx(); } } void up_rx() // plot block { lcd.home(); lcd.setCursor(x_rx,0); lcd.write(byte(2)); //delay(1); } void down_rx() // plot blank { lcd.home(); lcd.setCursor(x_rx,0); lcd.write(byte(1)); //delay(1); } //********************** Transmitter bar graph plot measurement ****************** void plot_signal_tx() { tx_bar_power_output = 0; x_start_tx = 0; tx_bar_signal_value = 0; plot_tx = 0; tx_bar_signal_value = analogRead(2); if (tx_bar_signal_value == 0 ) { tx_bar_signal_value = 1; } // the 4.47 is the resistor voltage divider ratio for max pwr = 5volts for 10watt Tx power tx_bar_signal_level = (0.0048 * tx_bar_signal_value) * 4.47; // the "4.47" potential resistor divided multiplier tx_bar_power_output = ((tx_bar_signal_level * tx_bar_signal_level) / 50); // tx power = (v * v) / antenna; 10watts max reading plot_tx = (tx_bar_power_output) / 1; // thus divide by 1 for ten square plot x_start_tx = plot_tx; // to locate square plot x axis } void plot_way_tx() { if ( x_tx > x_start_tx) { down_tx(); x_tx = x_tx - 1; } if ( x_tx < x_start_tx) { x_tx = x_tx + 1; up_tx(); } } void up_tx() // plot block { lcd.home(); lcd.setCursor(x_tx,2); lcd.write(byte(2)); //delay(1); } void down_tx() // plot blank { lcd.home(); lcd.setCursor(x_tx,2); lcd.write(byte(1)); //delay(1); } //************ transmit / receive control subroutine ******** void radio_monitor() { rx_pwr(); // only while the receiver is enabled, the Rx signal strength would be displayed tx_pwr(); // only while the transmitter is enabled, the Tx power output would be displayed active_load(); // only while the Tx is enabled, the antenna loading would be displayed } //**************** processes for receive mode *************** void rx_pwr() { rx_signal_value = analogRead(3); // analog port 3 to measure RX signal input if ( rx_signal_value <= 10) // 10bit ADC setting { rx_signal_value = 10; // error correction for maths } signal_meter = (rx_signal_value - 9); // the value of 500 indicates an "S 9" signal for a 16bit ADC, RST from "Rx:0.1" up to "Rx:9.0 +42.33dB" // the value of 500 indicates an "S 9" signal for a 10bit ADC, RST from "Rx:1.0" up to "Rx:9.0 +6dB" over_load = 20*(double)log10(signal_meter); // for 10bit ADC for "S" meter S_meter = (over_load/0.6); lcd.home(); lcd.setCursor(0,0); lcd.print("Rx = "); lcd.setCursor(5,0); lcd.print(" "); if (over_load <= 54 ) { lcd.home(); RST_measure = (S_meter/10); lcd.setCursor(5,0); lcd.print(RST_measure,1); } else if (over_load > 54 ) { lcd.home(); lcd.setCursor(0,0); lcd.print("Rx = 9.0 +"); load_scale = over_load - 54; lcd.setCursor(11,0); lcd.print(" "); lcd.setCursor(11,0); lcd.print(load_scale,2); lcd.setCursor(16,0); lcd.print("dB"); } } // **************************************************************************************** //********** processes for transmit mode *************** void tx_pwr() { tx_power_measure = analogRead(2); // analog 2 to measure tx power output if ( tx_power_measure == 0 ) { tx_power_measure = 1; } tx_signal_level = (0.0048 * tx_power_measure) * 4.47; // the "4.47" potential resistor divided multiplier tx_power_output = ((tx_signal_level * tx_signal_level) / 50); // tx power = (v * v) / antenna; 10watts max reading lcd.home(); lcd.setCursor(0,1); lcd.print("Tx = "); lcd.setCursor(5,1); lcd.print(" "); lcd.setCursor(5,1); lcd.print(tx_power_output,2); lcd.setCursor(11,1); lcd.print("Watts"); swr_forward = 0; // reset value to zero swr_reflected = 0; // reset value to zero swr_forward = analogRead(0); if ( swr_forward == 0 ) { swr_forward = 1; } swr_reflected = analogRead(1); if ( swr_reflected == 0 ) { swr_reflected = 1; } v_forward = 0.0048 * swr_forward; // forward swr voltage v_reflected = 0.0048 * swr_reflected; // reverse swr voltage if (digitalRead(source_load) == HIGH) // measure radio source impedance { ratio = v_reflected / v_forward; } else if (digitalRead(source_load) == LOW) // measure antenna load impedance { ratio = v_forward / v_reflected; } swr_value = ratio; RL = swr_value * 50; // assume match to a 50ohm co-axial cable lcd.setCursor(0,2); lcd.print("Swr= 1:"); lcd.setCursor(7,2); lcd.print(swr_value,4); lcd.print(" "); } //*************** calculate the active load of the antenna ***************** void active_load() { res_load = RL; //******* capacitive loaded antenna ***** if (res_load < 50) { cap = 300E-9 / ( res_load * res_load); cap_scale = cap * 1E12; if (cap_scale <= 1000) { cap_scale_t = cap_scale; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,1); lcd.write(byte(0)); lcd.print("-j"); lcd.print(cap_scale_t,0); lcd.print("pF"); } else if (cap_scale > 1E3 && cap_scale <= 1E6) { cap_scale_t = cap_scale/1E3; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,1); lcd.write(byte(0)); lcd.print("-j"); lcd.print(cap_scale_t,1); lcd.print("nF"); } else if (cap_scale > 1E6 && cap_scale <= 1E9) { cap_scale_t = cap_scale/1E6; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,2); lcd.write(byte(0)); lcd.print("-j"); lcd.print(cap_scale_t,2); lcd.print("uF"); } else if (cap_scale > 1E9 && cap_scale <= 1E12) { cap_scale_t = cap_scale/1E9; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,1); lcd.write(byte(0)); lcd.print("-j"); lcd.print(cap_scale_t,1); lcd.print("mF"); } else if (cap_scale > 1E12) { cap_scale_t = cap_scale/1E12; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,1); lcd.write(byte(0)); lcd.print("-j"); lcd.print(cap_scale_t,1); lcd.print("F"); } } ///***** inductive loaded antenna ****** if (res_load > 50) { ind = (res_load * res_load) * 120E-12; ind_scale = ind * 1E12; if (ind_scale <= 1000) { ind_scale_t = ind_scale; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,1); lcd.write(byte(0)); lcd.print("+j"); lcd.print(ind_scale_t,0); lcd.print("pH"); } else if (ind_scale > 1E3 && ind_scale <= 1E6) { ind_scale_t = ind_scale/1000; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,1); lcd.write(byte(0)); lcd.print("+j"); lcd.print(ind_scale_t,0); lcd.print("nH"); } else if (ind_scale > 1E6 && ind_scale <= 1E9) { ind_scale_t = ind_scale/1E6; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,0); lcd.write(byte(0)); lcd.print("+j"); lcd.print(ind_scale_t,1); lcd.print("uH"); } else if (ind_scale > 1E9 && ind_scale <= 1E12) { ind_scale_t = ind_scale/1E9; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,0); lcd.write(byte(0)); lcd.print("+j"); lcd.print(ind_scale_t,2); lcd.print("mH"); } else if (ind_scale > 1E12) { ind_scale_t = ind_scale/1E12; lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,0); lcd.write(byte(0)); lcd.print("+j"); lcd.print(ind_scale_t,1); lcd.print("H"); } } if ( res_load == 50) { lcd.setCursor(0,3); // bottom line of the display lcd.print(" "); lcd.setCursor(0,3); lcd.print("Imp= "); lcd.print(res_load,0); lcd.write(byte(0)); lcd.print(" antenna "); } } //**************************** end of program code ****************************