/* This program written by Alastair GW0AJU. This project is version 5 of the "Bitx active bridge version 5" for a DIY Ham Radio Tx/Rx project. date 23rd April 2017 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 */ #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; #define radio_antenna 13 // pin 13 used as logic switch between radio and antenna meter //**************** 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); // pin 13 used as logic switch between radio and antenna meters } //************* 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; 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; 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 float ratio = v_forward / v_reflected; // float ratio = v_reflected / v_forward; float 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 ****************************