The Bitx40 vfo code that comes with the bitx40, the raduino vfo, has unfortunately developed a fault type in the display. However this turns out to be the data sense lines of the raduino vfo code false triggering an active line input. However to avoid this problem, other hams have tied these lines to a positive supply line rail. The Arduino command used within the raduino code is "pinMode(cw, INPUT);" however otherwise as "pinMode(cw, INPUT_PULLUP);" would corrected the problem. I have found the raduino code on GitHub, this listing however is not complete, that is to say is seems that parts of the code are not present.
However, the original code in my bitx40 developed the same occurance as other hams have found, so I decided to write my own version of the raduino code and attempt to find a solution.
The Arduino code written is only for as now voice only, but a CW/SSB version I have now written, but to put into action with one or two modes to the bitx40 original circuits, such as a 800Hz bandpass CW filter. The display of the alternative version is shown as below is also different, but I hope easier to read as I have found also.
The photo is a bit fuzzy, but the dial reading is now read as KHz, while the radio ham user may wish to replace the lower display with their own name and callsign.
I also found that the raduino vfo code had a 1200Hz reading offset, this I have corrected with my version of the code, thus the display reading is now on the button in accuracy. I have checked the accuracy with my FT450d.
Below is a text window of the alternative bitx40 vfo coding. Keen radio ham software engineers may have noticed the use of the "<EEPROM.h>" inclusion file, this is used to the store the frequency in use so that it may be recalled when the bitx40 is powered up again, there by a last used frequency recall memory system, despite any part rotation of the tuning knob during switch off or power down of the radio.
The new vfo code maybe found on my radio ham website, the url listed opposite. http://radiohamtech.com/page33.html
Enjoy.
Text Box
// 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.
//
// In the "void setup()" section, please add your name and callsign where shown
// on the "lcd.print("name & callsign");" coding line. My own code use would be
// shown here as "lcd.print("Alastair GW0AJU");" on the bottom line of the display.
//
// This version of the has otwo alterations. As with the code of the 12th June 2018,
// the last frequency used before switch off, is recalled back into use when the radio
// is switched back on. The differnce with this code of the 13th June 2018, the recalled
// frequency after switch off to switch back on, is not subject to a change in frequency
// should the tuning knob be moved while the radio is switched off.
//
// The second alteration is the programmed choice between a 50KHz or a 100KHz tuning spread
// from the tuning knob. The choice can be found in the last section of the "void doTuning()" code.
// To make choice for a choosen normal use, just uncomment your choice and recomment the
// choice not required. The code here for example is set to the 50KHz tuning knob tuning spread.
//
// coding put together by Alastair GW0AJU
//
// date: 20th August 2018
//
#include <EEPROM.h>
#include <Wire.h>
#include <si5351.h>
Si5351 si5351;
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
int address = 100;
int address_base = 108;
#define ANALOG_TUNING (A7)
long crystal_drift = 50; // bfo crystal is high by the "+" amount
unsigned long baseTune = 7090000; // first off boot up value
unsigned long bfo_freq = (11998000 - crystal_drift); // drift cancelled by using 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;
long start_freq;
long last_Set;
long IF_LO;
//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);
}
//******************* volume control type tuning knob ************************
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)
{
knob = analogRead(ANALOG_TUNING)-10;
old_knob = knob;
baseTune = baseTune - 10000;
frequency = baseTune;
setFrequency(frequency);
updateDisplay();
EEPROMWritelong(address, frequency);
EEPROMWritelong(address_base, baseTune);
delay(300);
}
// 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)
{
knob = analogRead(ANALOG_TUNING)-10;
old_knob = knob;
baseTune = baseTune + 10000;
frequency = baseTune;
setFrequency(frequency);
updateDisplay();
EEPROMWritelong(address, frequency);
EEPROMWritelong(address_base, baseTune);
delay(300);
}
// 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
// for a 50KHz band spread use 50Hz inc/dec,
baseTune = baseTune + (50 * change_knob);
// for a 100KHz band spread use 100Hz inc/dec
// baseTune = baseTune + (100 * change_knob);
frequency = baseTune;
old_knob = knob;
setFrequency(frequency);
updateDisplay();
EEPROMWritelong(address, frequency);
EEPROMWritelong(address_base, baseTune);
}
}
//******************* programming si5351a as vfo oscillator ********************
void setFrequency(unsigned long f)
{ // for CW mode cw_tone_offset = 800Hz, for LSB mode cw_tone_offset = 0Hz
IF_LO = bfo_freq - frequency;
if (last_Set != IF_LO)
{
si5351.set_freq( IF_LO * 100ULL, SI5351_CLK2); // rx local oscillator vfo
si5351.update_status();
last_Set = IF_LO;
}
}
//****************** radio set display panel ************************************
void updateDisplay()
{
freq_display = frequency;
lcd.home();
lcd.setCursor(5,0);
lcd.print(" ");
lcd.setCursor(5,0);
lcd.print(freq_display/1E3,2);
}
//***************** radio set intialising **************************************
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_2MA);
si5351.output_enable(SI5351_CLK0, 0);
si5351.output_enable(SI5351_CLK1, 0);
si5351.output_enable(SI5351_CLK2, 1);
// calibration of vfo with digital frequency counter to test 25MHz crystal
//si5351.set_freq(50000000, SI5351_CLK2);
si5351.update_status();
delay(10);
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("bixt40 40m radio");
lcd.setCursor(0,1);
lcd.print("setting up radio");
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);
if (start_freq > 7000000 && start_freq < HIGHEST_FREQ ) // uk = 7200KHz max, USA = 7300kHz max
{
frequency = EEPROMReadlong(address);
baseTune = EEPROMReadlong(address_base);
}
else
{
EEPROMWritelong(address, pwr_up_forty_metre);
frequency = EEPROMReadlong(address);
}
delay(3000); // 3 second delay
knob = analogRead(ANALOG_TUNING)-10;
old_knob = knob;
lcd.clear();
lcd.home();
lcd.setCursor(0,0);
lcd.print("vfo:");
lcd.setCursor(13,0);
lcd.print("KHz");
lcd.setCursor(0,1);
lcd.print("alastair GW0AJU");
//lcd.print("name & callsign");
setFrequency(frequency);
updateDisplay();
}
//**************************** main routine to run bitx40 coding ******************
void loop()
{
doTuning();
delay(50);
}