// This program is put together with clues from the raduino github listing, // found was missing code and strange coding too, but listed here is my version // for a voice ssb for lsb radio operation of the bitx40 radio. // // This version of the arduino controlled vfo software does not display the // callsign of the operator as a label notice for QSO operation. // // However the lower display now illustrates a signal strength meter for the Rx signal. // The blue wire fron the cable connector leading to the vfo tuning control, the // blue wire is analog port (A6), which is to be now connected to the receivers AGC line. The // maximum AGC voltage of my bitx40 is around 2Volts. Should the AGC voltage on your // AGC line be different, then the variable "int scale_division = 15;" numerical // value may need to be altered to fix in a meter range from "S1" to "9+++" on the // available lower display space area. However do note that if your AGC voltage is greater // than 5Volts, a resistor scale divider will need to be used to reduce the measuring AGC // voltage to a maximum of 5Volts. This regard for a maximum AGC voltage of 5 Volts, the // "int scale_division = 15;" numerical value should be as shown next "int scale_division = 85;". // // coding put together by Alastair GW0AJU // // date: 12th June 2018 // updated 18th January 2019 // updated 20th January 2024 // #include #include #include Si5351 si5351; #include LiquidCrystal lcd(8,9,10,11,12,13); int address = 100; int address_knob = 104; int address_base = 108; #define ANALOG_TUNING (A7) #define signal_measurement (A6) // blue wire //************* signal meter variables ********* int x_start_rx = 0; int x_rx = 0; int rx_bar_signal_value = 0; int plot_rx = 0; int signal_meter = 0; int scale_division = 15; //************ vfo tuning variables ************* long crystal_drift = 50; // bfo crystal is high by the "+" amount unsigned long baseTune = 7100000; // first off boot up value unsigned long bfo_freq = (11998000 - crystal_drift); // drift cancelled by the minus calculation int old_knob = 0; int change_knob = 0; int knob; #define LOWEST_FREQ (7000000) #define HIGHEST_FREQ (7200000) // UK version //#define HIGHEST_FREQ (7300000) // American version long frequency; long freq_display = 0; unsigned long newFreq; unsigned long old_freq = frequency; long start_freq; //This function will write a 4 byte (32bit) long to the eeprom at //the specified address to address + 3. void EEPROMWritelong(int address, long value) { //Decomposition from a long to 4 bytes by using bitshift. //One = Most significant -> Four = Least significant byte byte four = (value & 0xFF); byte three = ((value >> 8) & 0xFF); byte two = ((value >> 16) & 0xFF); byte one = ((value >> 24) & 0xFF); //Write the 4 bytes into the eeprom memory. EEPROM.write(address, four); EEPROM.write(address + 1, three); EEPROM.write(address + 2, two); EEPROM.write(address + 3, one); } //This function will return a 4 byte (32bit) long from the eeprom //at the specified address to address + 3. long EEPROMReadlong(long address) { //Read the 4 bytes from the eeprom memory. long four = EEPROM.read(address); long three = EEPROM.read(address + 1); long two = EEPROM.read(address + 2); long one = EEPROM.read(address + 3); //Return the recomposed long by using bitshift. return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF); } void setup() { // Start serial and initialize the Si5351 analogReference(DEFAULT); si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_6MA); si5351.output_enable(SI5351_CLK0, 0); si5351.output_enable(SI5351_CLK1, 0); si5351.output_enable(SI5351_CLK2, 1); si5351.update_status(); delay(10); address = 100; // 40m in band operation check long pwr_up_forty_metre = 7090000; // 40m band SSB QRP Centre of Activity 7,090 kHz //Starting at the first byte on the eeprom. start_freq = EEPROMReadlong(address); //start_freq = 5000000; if (start_freq > LOWEST_FREQ && start_freq < HIGHEST_FREQ) // uk band plan { frequency = EEPROMReadlong(address); knob = EEPROMReadlong(address_knob); baseTune = EEPROMReadlong(address_base); old_knob = knob; } else if (start_freq < LOWEST_FREQ || start_freq > HIGHEST_FREQ) // uk band plan { EEPROMWritelong(address, pwr_up_forty_metre); knob = analogRead(ANALOG_TUNING)-10; baseTune = baseTune + (10 * change_knob); frequency = baseTune; old_knob = knob; frequency = EEPROMReadlong(address); EEPROMWritelong(address, frequency); EEPROMWritelong(address_knob, knob); EEPROMWritelong(address_base, baseTune); } lcd.begin(16, 2); lcd.setCursor(0,0); lcd.print("bixt40 40m radio"); lcd.setCursor(0,1); lcd.print("alastair GW0AJU"); delay(2000); // 2 second delay lcd.setCursor(0,0); lcd.print("setting up radio"); lcd.setCursor(0,1); lcd.print("please waiting "); delay(3000); // 3 second delay lcd.clear(); lcd.home(); lcd.setCursor(0,0); lcd.print("vfo:"); lcd.setCursor(13,0); lcd.print("KHz"); lcd.setCursor(0,1); lcd.print("Sig:"); setFrequency(frequency); updateDisplay(); } void loop() { delay(50); doTuning(); // tune vfo from variable resistance pot plot_signal_rx(); // plot signal strength meter readings } void doTuning() { knob = analogRead(ANALOG_TUNING)-10; // the knob is fully on the low end, move down by 10 Khz and wait for 200 msec if (knob < 10 && frequency > LOWEST_FREQ) { baseTune = baseTune - 1000; delay(100); frequency = baseTune; setFrequency(frequency); updateDisplay(); EEPROMWritelong(address, frequency); EEPROMWritelong(address_knob, knob); EEPROMWritelong(address_base, baseTune); } // the knob is full on the high end, move up by 10 Khz and wait for 200 msec else if (knob > 1010 && frequency < HIGHEST_FREQ) { baseTune = baseTune + 1000; delay(100); frequency = baseTune; setFrequency(frequency); updateDisplay(); EEPROMWritelong(address, frequency); EEPROMWritelong(address_knob, knob); EEPROMWritelong(address_base, baseTune); } // the tuning knob is at neither extremities, tune the signals as usual else if (knob != old_knob) { change_knob = knob - old_knob; // if change_knob is +, then up band, if -, then down band baseTune = baseTune + (10 * change_knob); // changed from 50Hz steps to 10Hz steps frequency = baseTune; old_knob = knob; setFrequency(frequency); updateDisplay(); EEPROMWritelong(address, frequency); EEPROMWritelong(address_knob, knob); EEPROMWritelong(address_base, baseTune); } } void setFrequency(unsigned long f) { si5351.set_freq((bfo_freq - f) * 100ULL, SI5351_CLK2); frequency = f; si5351.update_status(); } void updateDisplay() { freq_display = frequency; lcd.home(); lcd.setCursor(5,0); lcd.print(" "); lcd.setCursor(5,0); // lcd.print(knob); lcd.print(freq_display/1E3,2); } //********************* Receiver bar graph plot ******************* void plot_signal_rx() { signal_meter = 0; x_start_rx = 0; rx_bar_signal_value = 0; plot_rx = 0; // analog port "0" is used for S meter wire to MC1360 agc lline via resistor voltage step down attenuator rx_bar_signal_value = analogRead(signal_measurement); if ( rx_bar_signal_value <= 10) // 10bit ADC setting { rx_bar_signal_value = 10.01; // error correction for maths and to overcome radio noise floor } signal_meter = (rx_bar_signal_value); // overcome ground signal noise plot_rx = signal_meter / scale_division; // max analogue port value is 1024 x_start_rx = plot_rx; // to locate square plot x axis ( x_start_x is an integer variable ) plot_way_rx(); } 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 { if (x_rx == 1) { lcd.setCursor(x_rx + 3,1); lcd.print("1"); } else if (x_rx == 3) { lcd.setCursor(x_rx + 3,1); lcd.print("3"); } else if (x_rx == 5) { lcd.setCursor(x_rx + 3,1); lcd.print("5"); } else if (x_rx == 7) { lcd.setCursor(x_rx + 3,1); lcd.print("7"); } else if (x_rx == 9) { lcd.setCursor(x_rx + 3,1); lcd.print("9"); } else if (x_rx >= 10 && x_rx <= 12) { lcd.setCursor(x_rx + 3,1); lcd.print("+"); } else if ( (x_rx != 1) && (x_rx != 3) && (x_rx != 5) && (x_rx != 9) | (x_rx > 10) ) { lcd.setCursor(x_rx + 3,1); lcd.print("-"); } } void down_rx() // plot blank { lcd.setCursor(x_rx + 3,1); lcd.print(" "); }