kopia lustrzana https://github.com/afarhan/ubitx4
Merge 77af2ec047
into 1ae2af55db
commit
3aae0451ee
10
README.md
10
README.md
|
@ -1 +1,11 @@
|
|||
#ubitx4
|
||||
|
||||
This is adrian's fork of the ubitx v4 firmware.
|
||||
|
||||
It currently is tailored to run on a stock ubitx4 with bugfixes
|
||||
brought in from other branches and derivatives.
|
||||
|
||||
|
||||
Adrian Chadd / KK6VQK / adrian.chadd@gmail.com
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/**
|
||||
* This source file is under General Public License version 3.
|
||||
*
|
||||
* This verision uses a built-in Si5351 library
|
||||
|
@ -33,6 +33,14 @@
|
|||
#include <Wire.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
#include "ubitx4_eeprom_defs.h"
|
||||
#include "ubitx4_pin_config.h"
|
||||
#include "ubitx4_defaults.h"
|
||||
|
||||
#include "ubitx4_txfilt.h"
|
||||
|
||||
#include "ubitx_ui.h"
|
||||
|
||||
/**
|
||||
The main chip which generates upto three oscillators of various frequencies in the
|
||||
Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
|
||||
|
@ -44,57 +52,9 @@
|
|||
code). Here are some defines and declarations used by Jerry's routines:
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* We need to carefully pick assignment of pin for various purposes.
|
||||
* There are two sets of completely programmable pins on the Raduino.
|
||||
* First, on the top of the board, in line with the LCD connector is an 8-pin connector
|
||||
* that is largely meant for analog inputs and front-panel control. It has a regulated 5v output,
|
||||
* ground and six pins. Each of these six pins can be individually programmed
|
||||
* either as an analog input, a digital input or a digital output.
|
||||
* The pins are assigned as follows (left to right, display facing you):
|
||||
* Pin 1 (Violet), A7, SPARE
|
||||
* Pin 2 (Blue), A6, KEYER (DATA)
|
||||
* Pin 3 (Green), +5v
|
||||
* Pin 4 (Yellow), Gnd
|
||||
* Pin 5 (Orange), A3, PTT
|
||||
* Pin 6 (Red), A2, F BUTTON
|
||||
* Pin 7 (Brown), A1, ENC B
|
||||
* Pin 8 (Black), A0, ENC A
|
||||
*Note: A5, A4 are wired to the Si5351 as I2C interface
|
||||
* *
|
||||
* Though, this can be assigned anyway, for this application of the Arduino, we will make the following
|
||||
* assignment
|
||||
* A2 will connect to the PTT line, which is the usually a part of the mic connector
|
||||
* A3 is connected to a push button that can momentarily ground this line. This will be used for RIT/Bandswitching, etc.
|
||||
* A6 is to implement a keyer, it is reserved and not yet implemented
|
||||
* A7 is connected to a center pin of good quality 100K or 10K linear potentiometer with the two other ends connected to
|
||||
* ground and +5v lines available on the connector. This implments the tuning mechanism
|
||||
*/
|
||||
|
||||
#define ENC_A (A0)
|
||||
#define ENC_B (A1)
|
||||
#define FBUTTON (A2)
|
||||
#define PTT (A3)
|
||||
#define ANALOG_KEYER (A6)
|
||||
#define ANALOG_SPARE (A7)
|
||||
|
||||
/**
|
||||
* The Raduino board is the size of a standard 16x2 LCD panel. It has three connectors:
|
||||
*
|
||||
* First, is an 8 pin connector that provides +5v, GND and six analog input pins that can also be
|
||||
* configured to be used as digital input or output pins. These are referred to as A0,A1,A2,
|
||||
* A3,A6 and A7 pins. The A4 and A5 pins are missing from this connector as they are used to
|
||||
* talk to the Si5351 over I2C protocol.
|
||||
*
|
||||
* Second is a 16 pin LCD connector. This connector is meant specifically for the standard 16x2
|
||||
* LCD display in 4 bit mode. The 4 bit mode requires 4 data lines and two control lines to work:
|
||||
* Lines used are : RESET, ENABLE, D4, D5, D6, D7
|
||||
* We include the library and declare the configuration of the LCD panel too
|
||||
*/
|
||||
|
||||
#include <LiquidCrystal.h>
|
||||
LiquidCrystal lcd(8,9,10,11,12,13);
|
||||
LiquidCrystal lcd(LCD_PIN_RESET, LCD_PIN_ENABLE,
|
||||
LCD_PIN_D4, LCD_PIN_D5, LCD_PIN_D6, LCD_PIN_D7);
|
||||
|
||||
/**
|
||||
* The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory.
|
||||
|
@ -111,77 +71,6 @@ char c[30], b[30];
|
|||
char printBuff[2][31]; //mirrors what is showing on the two lines of the display
|
||||
int count = 0; //to generally count ticks, loops, etc
|
||||
|
||||
/**
|
||||
* The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig.
|
||||
* This assignment is as follows :
|
||||
* Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
||||
* GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7
|
||||
* These too are flexible with what you may do with them, for the Raduino, we use them to :
|
||||
* - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer
|
||||
* - CW_KEY line : turns on the carrier for CW
|
||||
*/
|
||||
|
||||
#define TX_RX (7)
|
||||
#define CW_TONE (6)
|
||||
#define TX_LPF_A (5)
|
||||
#define TX_LPF_B (4)
|
||||
#define TX_LPF_C (3)
|
||||
#define CW_KEY (2)
|
||||
|
||||
/**
|
||||
* These are the indices where these user changable settinngs are stored in the EEPROM
|
||||
*/
|
||||
#define MASTER_CAL 0
|
||||
#define LSB_CAL 4
|
||||
#define USB_CAL 8
|
||||
#define SIDE_TONE 12
|
||||
//these are ids of the vfos as well as their offset into the eeprom storage, don't change these 'magic' values
|
||||
#define VFO_A 16
|
||||
#define VFO_B 20
|
||||
#define CW_SIDETONE 24
|
||||
#define CW_SPEED 28
|
||||
|
||||
//These are defines for the new features back-ported from KD8CEC's software
|
||||
//these start from beyond 256 as Ian, KD8CEC has kept the first 256 bytes free for the base version
|
||||
#define VFO_A_MODE 256 // 2: LSB, 3: USB
|
||||
#define VFO_B_MODE 257
|
||||
|
||||
//values that are stroed for the VFO modes
|
||||
#define VFO_MODE_LSB 2
|
||||
#define VFO_MODE_USB 3
|
||||
|
||||
// handkey, iambic a, iambic b : 0,1,2f
|
||||
#define CW_KEY_TYPE 358
|
||||
|
||||
/**
|
||||
* The uBITX is an upconnversion transceiver. The first IF is at 45 MHz.
|
||||
* The first IF frequency is not exactly at 45 Mhz but about 5 khz lower,
|
||||
* this shift is due to the loading on the 45 Mhz crystal filter by the matching
|
||||
* L-network used on it's either sides.
|
||||
* The first oscillator works between 48 Mhz and 75 MHz. The signal is subtracted
|
||||
* from the first oscillator to arriive at 45 Mhz IF. Thus, it is inverted : LSB becomes USB
|
||||
* and USB becomes LSB.
|
||||
* The second IF of 12 Mhz has a ladder crystal filter. If a second oscillator is used at
|
||||
* 57 Mhz, the signal is subtracted FROM the oscillator, inverting a second time, and arrives
|
||||
* at the 12 Mhz ladder filter thus doouble inversion, keeps the sidebands as they originally were.
|
||||
* If the second oscillator is at 33 Mhz, the oscilaltor is subtracated from the signal,
|
||||
* thus keeping the signal's sidebands inverted. The USB will become LSB.
|
||||
* We use this technique to switch sidebands. This is to avoid placing the lsbCarrier close to
|
||||
* 12 MHz where its fifth harmonic beats with the arduino's 16 Mhz oscillator's fourth harmonic
|
||||
*/
|
||||
|
||||
// the second oscillator should ideally be at 57 MHz, however, the crystal filter's center frequency
|
||||
// is shifted down a little due to the loading from the impedance matching L-networks on either sides
|
||||
#define SECOND_OSC_USB (56995000l)
|
||||
#define SECOND_OSC_LSB (32995000l)
|
||||
|
||||
|
||||
//these are the two default USB and LSB frequencies. The best frequencies depend upon your individual taste and filter shape
|
||||
#define INIT_USB_FREQ (11996500l)
|
||||
// limits the tuning and working range of the ubitx between 3 MHz and 30 MHz
|
||||
#define LOWEST_FREQ (100000l)
|
||||
#define HIGHEST_FREQ (30000000l)
|
||||
|
||||
//we directly generate the CW by programmin the Si5351 to the cw tx frequency, hence, both are different modes
|
||||
//these are the parameter passed to startTx
|
||||
#define TX_SSB 0
|
||||
|
@ -193,7 +82,7 @@ int8_t meter_reading = 0; // a -1 on meter makes it invisible
|
|||
unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier;
|
||||
char isUsbVfoA=0, isUsbVfoB=1;
|
||||
unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
|
||||
unsigned long firstIF = 45000000L;
|
||||
unsigned long firstIF = DEFAULT_FIRSTIF;
|
||||
|
||||
//these are variables that control the keyer behaviour
|
||||
int cwSpeed = 100; //this is actuall the dot period in milliseconds
|
||||
|
@ -238,46 +127,6 @@ void active_delay(int delay_by){
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the properly tx harmonic filters
|
||||
* The four harmonic filters use only three relays
|
||||
* the four LPFs cover 30-21 Mhz, 18 - 14 Mhz, 7-10 MHz and 3.5 to 5 Mhz
|
||||
* Briefly, it works like this,
|
||||
* - When KT1 is OFF, the 'off' position routes the PA output through the 30 MHz LPF
|
||||
* - When KT1 is ON, it routes the PA output to KT2. Which is why you will see that
|
||||
* the KT1 is on for the three other cases.
|
||||
* - When the KT1 is ON and KT2 is off, the off position of KT2 routes the PA output
|
||||
* to 18 MHz LPF (That also works for 14 Mhz)
|
||||
* - When KT1 is On, KT2 is On, it routes the PA output to KT3
|
||||
* - KT3, when switched on selects the 7-10 Mhz filter
|
||||
* - KT3 when switched off selects the 3.5-5 Mhz filter
|
||||
* See the circuit to understand this
|
||||
*/
|
||||
|
||||
void setTXFilters(unsigned long freq){
|
||||
|
||||
if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq >= 14000000L){ //thrown the KT1 relay on, the 30 MHz LPF is bypassed and the 14-18 MHz LPF is allowd to go through
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq > 7000000L){
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 1);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else {
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 1);
|
||||
digitalWrite(TX_LPF_C, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the most frequently called function that configures the
|
||||
* radio to a particular frequeny, sideband and sets up the transmit filters
|
||||
|
@ -317,8 +166,19 @@ void setFrequency(unsigned long f){
|
|||
|
||||
void startTx(byte txMode){
|
||||
unsigned long tx_freq = 0;
|
||||
|
||||
|
||||
// Turn off the main mixer oscillator and wait for RX->TX burst before
|
||||
// TX is flipped on. Then we will re-enable the clocks.
|
||||
si5351bx_setfreq(2, 0);
|
||||
|
||||
// Wait so things settle.
|
||||
delay(TX_DELAY_OSC_OFF);
|
||||
|
||||
// Flip to TX.
|
||||
digitalWrite(TX_RX, 1);
|
||||
|
||||
// Wait for relays, etc to settle.
|
||||
delay(TX_DELAY_ENABLE);
|
||||
inTx = 1;
|
||||
|
||||
if (ritOn){
|
||||
|
@ -357,12 +217,19 @@ void startTx(byte txMode){
|
|||
si5351bx_setfreq(2, frequency - sideTone);
|
||||
}
|
||||
updateDisplay();
|
||||
clearMeterDisplay();
|
||||
}
|
||||
|
||||
void stopTx(){
|
||||
inTx = 0;
|
||||
|
||||
// Turn off the main vfo before disabling TX. setFrequency() will fix
|
||||
// it.
|
||||
si5351bx_setfreq(2, 0); // disable the VFO oscillator.
|
||||
delay(TX_DELAY_OSC_OFF);
|
||||
|
||||
digitalWrite(TX_RX, 0); //turn off the tx
|
||||
delay(TX_DELAY_ENABLE); // wait for relays to settle
|
||||
si5351bx_setfreq(0, usbCarrier); //set back the cardrier oscillator anyway, cw tx switches it off
|
||||
|
||||
if (ritOn)
|
||||
|
@ -459,23 +326,49 @@ void checkButton(){
|
|||
void doTuning(){
|
||||
int s;
|
||||
unsigned long prev_freq;
|
||||
int freq_delta = 0;
|
||||
|
||||
s = enc_read();
|
||||
if (s != 0){
|
||||
prev_freq = frequency;
|
||||
|
||||
/*
|
||||
* Ensure that we don't tune below LOWEST_FREQ/HIGHEST_FREQ.
|
||||
* We need to be sure that frequency doesn't underflow!
|
||||
*/
|
||||
|
||||
if (s > 4)
|
||||
frequency += 10000l;
|
||||
freq_delta = 10000;
|
||||
else if (s > 2)
|
||||
frequency += 500;
|
||||
freq_delta = 500;
|
||||
else if (s > 0)
|
||||
frequency += 50l;
|
||||
freq_delta = 50;
|
||||
else if (s > -2)
|
||||
frequency -= 50l;
|
||||
freq_delta = -50;
|
||||
else if (s > -4)
|
||||
frequency -= 500l;
|
||||
freq_delta = -500;
|
||||
else
|
||||
frequency -= 10000l;
|
||||
freq_delta = -10000;
|
||||
|
||||
/* Be super careful we don't underflow! */
|
||||
if (freq_delta < 0) {
|
||||
unsigned long offset;
|
||||
offset = frequency - LOWEST_FREQ;
|
||||
if (offset < (-freq_delta)) {
|
||||
frequency = LOWEST_FREQ;
|
||||
freq_delta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not so likely to overflow here; a straight comparison is fine */
|
||||
if (freq_delta > 0) {
|
||||
if (frequency + freq_delta > HIGHEST_FREQ) {
|
||||
frequency = HIGHEST_FREQ;
|
||||
freq_delta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
frequency += freq_delta;
|
||||
|
||||
if (prev_freq < 10000000l && frequency > 10000000l)
|
||||
isUSB = true;
|
||||
|
@ -483,8 +376,14 @@ void doTuning(){
|
|||
if (prev_freq > 10000000l && frequency < 10000000l)
|
||||
isUSB = false;
|
||||
|
||||
setFrequency(frequency);
|
||||
updateDisplay();
|
||||
/*
|
||||
* Don't hammer on setting frequency / updating display if
|
||||
* we are at the edges already and we're being clamped above.
|
||||
*/
|
||||
// if (prev_freq != frequency) {
|
||||
setFrequency(frequency);
|
||||
updateDisplay();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,10 +422,10 @@ void initSettings(){
|
|||
EEPROM.get(VFO_B, vfoB);
|
||||
EEPROM.get(CW_SIDETONE, sideTone);
|
||||
EEPROM.get(CW_SPEED, cwSpeed);
|
||||
|
||||
EEPROM.get(CAL_FIRST_IF_FREQ, firstIF);
|
||||
|
||||
if (usbCarrier > 12000000l || usbCarrier < 11990000l)
|
||||
usbCarrier = 11997000l;
|
||||
usbCarrier = INIT_USB_FREQ;
|
||||
if (vfoA > 35000000l || 3500000l > vfoA)
|
||||
vfoA = 7150000l;
|
||||
if (vfoB > 35000000l || 3500000l > vfoB)
|
||||
|
@ -535,6 +434,8 @@ void initSettings(){
|
|||
sideTone = 800;
|
||||
if (cwSpeed < 10 || 1000 < cwSpeed)
|
||||
cwSpeed = 100;
|
||||
if (firstIF < 44500000 || firstIF > 45500000)
|
||||
firstIF = DEFAULT_FIRSTIF;
|
||||
|
||||
/*
|
||||
* The VFO modes are read in as either 2 (USB) or 3(LSB), 0, the default
|
||||
|
@ -629,19 +530,24 @@ void initPorts(){
|
|||
void setup()
|
||||
{
|
||||
Serial.begin(38400);
|
||||
Serial.flush();
|
||||
Serial.flush();
|
||||
lcd.begin(16, 2);
|
||||
lcd.clear();
|
||||
initMeter();
|
||||
|
||||
//we print this line so this shows up even if the raduino
|
||||
//crashes later in the code
|
||||
printLine2("uBITX v4.3");
|
||||
printLineF2(F("uBITX v4.3b"));
|
||||
//active_delay(500);
|
||||
|
||||
// initMeter(); //not used in this build
|
||||
initSettings();
|
||||
initPorts();
|
||||
initOscillators();
|
||||
|
||||
si5351bx_set_drive(0, 1); // 4ma
|
||||
si5351bx_set_drive(1, 1); // 4ma
|
||||
si5351bx_set_drive(2, 1); // 4ma
|
||||
|
||||
frequency = vfoA;
|
||||
setFrequency(vfoA);
|
||||
updateDisplay();
|
||||
|
@ -656,21 +562,23 @@ void setup()
|
|||
*/
|
||||
|
||||
byte flasher = 0;
|
||||
void loop(){
|
||||
|
||||
cwKeyer();
|
||||
void loop(){
|
||||
|
||||
cwKeyer();
|
||||
if (!txCAT)
|
||||
checkPTT();
|
||||
checkButton();
|
||||
|
||||
//tune only when not tranmsitting
|
||||
//tune / display s-meter only when not tranmsitting
|
||||
if (!inTx){
|
||||
if (ritOn)
|
||||
doRIT();
|
||||
else
|
||||
doTuning();
|
||||
// TODO: only update this every few milliseconds? Not constantly?
|
||||
updateMeterDisplay();
|
||||
}
|
||||
|
||||
|
||||
//we check CAT after the encoder as it might put the radio into TX
|
||||
checkCAT();
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* This source file is under General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef __UBITX4_EEPROM_DEFAULTS_H__
|
||||
#define __UBITX4_EEPROM_DEFAULTS_H__
|
||||
|
||||
// Delay when switching between TX and RX.
|
||||
// This prevents spurious bursts when switching RX->TX.
|
||||
#define TX_DELAY_OSC_OFF 15 // wait 15ms after turning off si5351 for it to be off off
|
||||
#define TX_DELAY_ENABLE 30 // wait 30ms after enabling PTT to let things settle.
|
||||
|
||||
/**
|
||||
* The uBITX is an upconnversion transceiver. The first IF is at 45 MHz.
|
||||
* The first IF frequency is not exactly at 45 Mhz but about 5 khz lower,
|
||||
* this shift is due to the loading on the 45 Mhz crystal filter by the matching
|
||||
* L-network used on it's either sides.
|
||||
* The first oscillator works between 48 Mhz and 75 MHz. The signal is subtracted
|
||||
* from the first oscillator to arriive at 45 Mhz IF. Thus, it is inverted : LSB becomes USB
|
||||
* and USB becomes LSB.
|
||||
* The second IF of 12 Mhz has a ladder crystal filter. If a second oscillator is used at
|
||||
* 57 Mhz, the signal is subtracted FROM the oscillator, inverting a second time, and arrives
|
||||
* at the 12 Mhz ladder filter thus doouble inversion, keeps the sidebands as they originally were.
|
||||
* If the second oscillator is at 33 Mhz, the oscilaltor is subtracated from the signal,
|
||||
* thus keeping the signal's sidebands inverted. The USB will become LSB.
|
||||
* We use this technique to switch sidebands. This is to avoid placing the lsbCarrier close to
|
||||
* 12 MHz where its fifth harmonic beats with the arduino's 16 Mhz oscillator's fourth harmonic
|
||||
*/
|
||||
|
||||
// the second oscillator should ideally be at 57 MHz, however, the crystal filter's center frequency
|
||||
// is shifted down a little due to the loading from the impedance matching L-networks on either sides
|
||||
#define SECOND_OSC_USB (56995000l)
|
||||
#define SECOND_OSC_LSB (32995000l)
|
||||
|
||||
//these are the two default USB and LSB frequencies. The best frequencies depend upon your individual taste and filter shape
|
||||
#define INIT_USB_FREQ (11996500l)
|
||||
|
||||
// Default first IF frequency (can be tuned via EEPROM)
|
||||
#define DEFAULT_FIRSTIF 45000000L
|
||||
|
||||
// limits the tuning and working range of the ubitx between 3 MHz and 30 MHz
|
||||
#define LOWEST_FREQ (100000l)
|
||||
#define HIGHEST_FREQ (30000000l)
|
||||
#define FAST_TUNE_STEP (200000L)
|
||||
|
||||
#endif /* __UBITX4_EEPROM_DEFAULTS_H__ */
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* This source file is under General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef __UBITX4_EEPROM_DEFS_H__
|
||||
#define __UBITX4_EEPROM_DEFS_H__
|
||||
|
||||
/**
|
||||
* These are the indices where these user changable settinngs are stored in the EEPROM
|
||||
*/
|
||||
#define MASTER_CAL 0
|
||||
#define LSB_CAL 4
|
||||
#define USB_CAL 8
|
||||
#define SIDE_TONE 12
|
||||
//these are ids of the vfos as well as their offset into the eeprom storage, don't change these 'magic' values
|
||||
#define VFO_A 16
|
||||
#define VFO_B 20
|
||||
#define CW_SIDETONE 24
|
||||
#define CW_SPEED 28
|
||||
|
||||
// Adrian's custom values
|
||||
#define CAL_FIRST_IF_FREQ 252 // 252-255 - first IF freq calibrated value
|
||||
|
||||
//These are defines for the new features back-ported from KD8CEC's software
|
||||
//these start from beyond 256 as Ian, KD8CEC has kept the first 256 bytes free for the base version
|
||||
#define VFO_A_MODE 256 // 2: LSB, 3: USB
|
||||
#define VFO_B_MODE 257
|
||||
|
||||
//values that are stored for the VFO modes
|
||||
#define VFO_MODE_LSB 2
|
||||
#define VFO_MODE_USB 3
|
||||
|
||||
// handkey, iambic a, iambic b : 0,1,2f
|
||||
#define CW_KEY_TYPE 358
|
||||
|
||||
#endif /* __UBITX4_EEPROM_DEFS_H__ */
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* This source file is under General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef __UBITX4_PIN_CONFIG_H__
|
||||
#define __UBITX4_PIN_CONFIG_H__
|
||||
|
||||
/**
|
||||
* We need to carefully pick assignment of pin for various purposes.
|
||||
* There are two sets of completely programmable pins on the Raduino.
|
||||
* First, on the top of the board, in line with the LCD connector is an 8-pin connector
|
||||
* that is largely meant for analog inputs and front-panel control. It has a regulated 5v output,
|
||||
* ground and six pins. Each of these six pins can be individually programmed
|
||||
* either as an analog input, a digital input or a digital output.
|
||||
* The pins are assigned as follows (left to right, display facing you):
|
||||
* Pin 1 (Violet), A7, S-METER / SPARE
|
||||
* Pin 2 (Blue), A6, KEYER (DATA)
|
||||
* Pin 3 (Green), +5v
|
||||
* Pin 4 (Yellow), Gnd
|
||||
* Pin 5 (Orange), A3, PTT
|
||||
* Pin 6 (Red), A2, F BUTTON
|
||||
* Pin 7 (Brown), A1, ENC B
|
||||
* Pin 8 (Black), A0, ENC A
|
||||
*Note: A5, A4 are wired to the Si5351 as I2C interface
|
||||
* *
|
||||
* - A0 and A1 are used for the rotary encoder
|
||||
* - A2 is used for the menu push button
|
||||
* - A3 is PTT to the microphone
|
||||
* - A6 is hooked up to the CW key jack via resistors, to implement
|
||||
* either a straight key or paddle support
|
||||
* - A7 is spare, but is currently used to drive an S-meter menu
|
||||
*/
|
||||
|
||||
#define ENC_A (A0)
|
||||
#define ENC_B (A1)
|
||||
#define FBUTTON (A2)
|
||||
#define PTT (A3)
|
||||
#define ANALOG_KEYER (A6)
|
||||
#define ANALOG_SPARE (A7)
|
||||
|
||||
/*
|
||||
* The 16x2 LCD panel is connected to digital pins as:
|
||||
* RESET : 8
|
||||
* ENABLE : 9
|
||||
* D4 : 10
|
||||
* D5 : 11
|
||||
* D6 : 12
|
||||
* D7 : 13
|
||||
*/
|
||||
#define LCD_PIN_RESET 8
|
||||
#define LCD_PIN_ENABLE 9
|
||||
#define LCD_PIN_D4 10
|
||||
#define LCD_PIN_D5 11
|
||||
#define LCD_PIN_D6 12
|
||||
#define LCD_PIN_D7 13
|
||||
/**
|
||||
* The second set of 16 pins on the Raduino's bottom connector are have the
|
||||
* three clock outputs and the digital lines to control the rig.
|
||||
* This assignment is as follows :
|
||||
* Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
||||
* GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7
|
||||
* These too are flexible with what you may do with them, for the Raduino, we use them to :
|
||||
* - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer
|
||||
* - CW_KEY line : turns on the carrier for CW
|
||||
*/
|
||||
|
||||
#define TX_RX (7)
|
||||
#define CW_TONE (6)
|
||||
#define TX_LPF_A (5)
|
||||
#define TX_LPF_B (4)
|
||||
#define TX_LPF_C (3)
|
||||
#define CW_KEY (2)
|
||||
|
||||
#endif /* __UBITX4_PIN_CONFIG_H__ */
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __UBITX4_TXFILT_H__
|
||||
#define __UBITX4_TXFILT_H__
|
||||
|
||||
extern void setTXFilters(unsigned long freq);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* This source file is under General Public License version 3.
|
||||
*/
|
||||
|
||||
#include "ubitx4_eeprom_defs.h"
|
||||
#include "ubitx4_pin_config.h"
|
||||
|
||||
/**
|
||||
* Select the properly tx harmonic filters
|
||||
*
|
||||
* This is valid for the ubitx v4 board; different boards have different TX filter
|
||||
* configurations and thus will need a different filter mapping routine here!
|
||||
*
|
||||
* The four harmonic filters use only three relays
|
||||
* the four LPFs cover 30-21 Mhz, 18 - 14 Mhz, 7-10 MHz and 3.5 to 5 Mhz
|
||||
* Briefly, it works like this,
|
||||
* - When KT1 is OFF, the 'off' position routes the PA output through the 30 MHz LPF
|
||||
* - When KT1 is ON, it routes the PA output to KT2. Which is why you will see that
|
||||
* the KT1 is on for the three other cases.
|
||||
* - When the KT1 is ON and KT2 is off, the off position of KT2 routes the PA output
|
||||
* to 18 MHz LPF (That also works for 14 Mhz)
|
||||
* - When KT1 is On, KT2 is On, it routes the PA output to KT3
|
||||
* - KT3, when switched on selects the 7-10 Mhz filter
|
||||
* - KT3 when switched off selects the 3.5-5 Mhz filter
|
||||
* See the circuit to understand this
|
||||
*/
|
||||
|
||||
void
|
||||
setTXFilters(unsigned long freq)
|
||||
{
|
||||
if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
|
||||
digitalWrite(TX_LPF_A, 0);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq >= 14000000L){
|
||||
/*
|
||||
* throw the KT1 relay on, the 30 MHz LPF is bypassed and
|
||||
* the 14-18 MHz LPF is allowedd to go through
|
||||
*/
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 0);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else if (freq > 7000000L){
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 1);
|
||||
digitalWrite(TX_LPF_C, 0);
|
||||
}
|
||||
else {
|
||||
digitalWrite(TX_LPF_A, 1);
|
||||
digitalWrite(TX_LPF_B, 1);
|
||||
digitalWrite(TX_LPF_C, 1);
|
||||
}
|
||||
}
|
287
ubitx_menu.ino
287
ubitx_menu.ino
|
@ -11,10 +11,11 @@
|
|||
* - If the menu item is NOT clicked on, then the menu's prompt is to be displayed
|
||||
*/
|
||||
|
||||
#include "ubitx4_defaults.h"
|
||||
|
||||
/** A generic control to read variable values
|
||||
*/
|
||||
int getValueByKnob(int minimum, int maximum, int step_size, int initial, char* prefix, char *postfix)
|
||||
int getValueByKnob(int minimum, int maximum, int step_size, int initial, const char* prefix, const char *postfix)
|
||||
{
|
||||
int knob = 0;
|
||||
int knob_value;
|
||||
|
@ -55,20 +56,17 @@ int getValueByKnob(int minimum, int maximum, int step_size, int initial, char*
|
|||
|
||||
//# Menu: 1
|
||||
|
||||
int menuBand(int btn){
|
||||
void menuBand(int btn){
|
||||
int knob = 0;
|
||||
int band;
|
||||
unsigned long offset;
|
||||
|
||||
// band = frequency/1000000l;
|
||||
// offset = frequency % 1000000l;
|
||||
|
||||
if (!btn){
|
||||
printLine2("Band Select \x7E");
|
||||
printLineF2(F("Band Select \x7E"));
|
||||
return;
|
||||
}
|
||||
|
||||
printLine2("Band Select:");
|
||||
printLineF2(F("Band Select:"));
|
||||
//wait for the button menu select button to be lifted)
|
||||
while (btnDown())
|
||||
active_delay(50);
|
||||
|
@ -80,19 +78,27 @@ int menuBand(int btn){
|
|||
knob = enc_read();
|
||||
if (knob != 0){
|
||||
/*
|
||||
if (band > 3 && knob < 0)
|
||||
band--;
|
||||
if (band < 30 && knob > 0)
|
||||
band++;
|
||||
if (band > 10)
|
||||
isUSB = true;
|
||||
else
|
||||
isUSB = false;
|
||||
setFrequency(((unsigned long)band * 1000000l) + offset); */
|
||||
if (knob < 0 && frequency > 3000000l)
|
||||
setFrequency(frequency - 200000l);
|
||||
if (knob > 0 && frequency < 30000000l)
|
||||
setFrequency(frequency + 200000l);
|
||||
* Ensure that we cap the band select between LOWEST_FREQ
|
||||
* and HIGHEST_FREQ.
|
||||
*/
|
||||
if ((knob < 0) && (frequency > LOWEST_FREQ)) {
|
||||
/* Ensure we don't tune below LOWEST_FREQ */
|
||||
if (frequency > (FAST_TUNE_STEP * 2)) {
|
||||
setFrequency(frequency - FAST_TUNE_STEP);
|
||||
} else {
|
||||
setFrequency(LOWEST_FREQ);
|
||||
}
|
||||
}
|
||||
if ((knob > 0) && (frequency < HIGHEST_FREQ)) {
|
||||
/* Ensure we don't tune above HIGHEST_FREQ */
|
||||
if ((frequency + FAST_TUNE_STEP) > HIGHEST_FREQ) {
|
||||
setFrequency(HIGHEST_FREQ);
|
||||
} else {
|
||||
setFrequency(frequency + FAST_TUNE_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust mode to be USB/LSB across 10MHz */
|
||||
if (frequency > 10000000l)
|
||||
isUSB = true;
|
||||
else
|
||||
|
@ -107,7 +113,7 @@ int menuBand(int btn){
|
|||
active_delay(50);
|
||||
active_delay(50);
|
||||
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
}
|
||||
|
@ -116,24 +122,24 @@ int menuBand(int btn){
|
|||
void menuRitToggle(int btn){
|
||||
if (!btn){
|
||||
if (ritOn == 1)
|
||||
printLine2("RIT On \x7E Off");
|
||||
printLineF2(F("RIT On \x7E Off"));
|
||||
else
|
||||
printLine2("RIT Off \x7E On");
|
||||
printLineF2(F("RIT Off \x7E On"));
|
||||
}
|
||||
else {
|
||||
if (ritOn == 0){
|
||||
//enable RIT so the current frequency is used at transmit
|
||||
ritEnable(frequency);
|
||||
printLine2("RIT is On");
|
||||
printLineF2(F("RIT is On"));
|
||||
|
||||
}
|
||||
else{
|
||||
ritDisable();
|
||||
printLine2("RIT is Off");
|
||||
printLineF2(F("RIT is Off"));
|
||||
}
|
||||
menuOn = 0;
|
||||
active_delay(500);
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
@ -144,9 +150,9 @@ void menuVfoToggle(int btn){
|
|||
|
||||
if (!btn){
|
||||
if (vfoActive == VFO_A)
|
||||
printLine2("VFO A \x7E B");
|
||||
printLineF2(F("VFO A \x7E B"));
|
||||
else
|
||||
printLine2("VFO B \x7E A");
|
||||
printLineF2(F("VFO B \x7E A"));
|
||||
}
|
||||
else {
|
||||
if (vfoActive == VFO_B){
|
||||
|
@ -159,7 +165,7 @@ void menuVfoToggle(int btn){
|
|||
EEPROM.put(VFO_B_MODE, VFO_MODE_LSB);
|
||||
|
||||
vfoActive = VFO_A;
|
||||
// printLine2("Selected VFO A ");
|
||||
// printLineF2(F("Selected VFO A "));
|
||||
frequency = vfoA;
|
||||
isUSB = isUsbVfoA;
|
||||
}
|
||||
|
@ -173,7 +179,7 @@ void menuVfoToggle(int btn){
|
|||
EEPROM.put(VFO_A_MODE, VFO_MODE_LSB);
|
||||
|
||||
vfoActive = VFO_B;
|
||||
// printLine2("Selected VFO B ");
|
||||
// printLineF2(F("Selected VFO B "));
|
||||
frequency = vfoB;
|
||||
isUSB = isUsbVfoB;
|
||||
}
|
||||
|
@ -181,7 +187,7 @@ void menuVfoToggle(int btn){
|
|||
ritDisable();
|
||||
setFrequency(frequency);
|
||||
updateDisplay();
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
//exit the menu
|
||||
menuOn = 0;
|
||||
}
|
||||
|
@ -191,31 +197,35 @@ void menuVfoToggle(int btn){
|
|||
void menuSidebandToggle(int btn){
|
||||
if (!btn){
|
||||
if (isUSB == true)
|
||||
printLine2("USB \x7E LSB");
|
||||
printLineF2(F("USB \x7E LSB"));
|
||||
else
|
||||
printLine2("LSB \x7E USB");
|
||||
printLineF2(F("LSB \x7E USB"));
|
||||
}
|
||||
else {
|
||||
if (isUSB == true){
|
||||
isUSB = false;
|
||||
printLine2("LSB Selected");
|
||||
printLineF2(F("LSB Selected"));
|
||||
active_delay(500);
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
}
|
||||
else {
|
||||
isUSB = true;
|
||||
printLine2("USB Selected");
|
||||
printLineF2(F("USB Selected"));
|
||||
active_delay(500);
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
}
|
||||
//Added by KD8CEC
|
||||
if (vfoActive == VFO_B){
|
||||
isUsbVfoB = isUSB;
|
||||
}
|
||||
else {
|
||||
isUsbVfoB = isUSB;
|
||||
isUsbVfoA = isUSB;
|
||||
}
|
||||
updateDisplay();
|
||||
|
||||
// Update the programmed frequency immediately so the band flips.
|
||||
setFrequency(frequency);
|
||||
|
||||
menuOn = 0;
|
||||
}
|
||||
}
|
||||
|
@ -225,29 +235,29 @@ void menuSidebandToggle(int btn){
|
|||
void menuSplitToggle(int btn){
|
||||
if (!btn){
|
||||
if (splitOn == 0)
|
||||
printLine2("Split Off \x7E On");
|
||||
printLineF2(F("Split Off \x7E On"));
|
||||
else
|
||||
printLine2("Split On \x7E Off");
|
||||
printLineF2(F("Split On \x7E Off"));
|
||||
}
|
||||
else {
|
||||
if (splitOn == 1){
|
||||
splitOn = 0;
|
||||
printLine2("Split ON");
|
||||
printLineF2(F("Split ON"));
|
||||
}
|
||||
else {
|
||||
splitOn = 1;
|
||||
if (ritOn == 1)
|
||||
ritOn = 0;
|
||||
printLine2("Split Off");
|
||||
printLineF2(F("Split Off"));
|
||||
}
|
||||
active_delay(500);
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int menuCWSpeed(int btn){
|
||||
void menuCWSpeed(int btn){
|
||||
int knob = 0;
|
||||
int wpm;
|
||||
|
||||
|
@ -295,12 +305,12 @@ int menuCWSpeed(int btn){
|
|||
*/
|
||||
wpm = getValueByKnob(1, 100, 1, wpm, "CW: ", " WPM>");
|
||||
|
||||
printLine2("CW Speed set!");
|
||||
printLineF2(F("CW Speed set!"));
|
||||
cwSpeed = 1200/wpm;
|
||||
EEPROM.put(CW_SPEED, cwSpeed);
|
||||
active_delay(500);
|
||||
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
}
|
||||
|
@ -308,12 +318,12 @@ int menuCWSpeed(int btn){
|
|||
void menuExit(int btn){
|
||||
|
||||
if (!btn){
|
||||
printLine2("Exit Menu \x7E");
|
||||
printLineF2(F("Exit Menu \x7E"));
|
||||
}
|
||||
else{
|
||||
printLine2("Exiting...");
|
||||
printLineF2(F("Exiting..."));
|
||||
active_delay(500);
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
}
|
||||
|
@ -326,29 +336,29 @@ void menuExit(int btn){
|
|||
int menuSetup(int btn){
|
||||
if (!btn){
|
||||
if (!modeCalibrate)
|
||||
printLine2("Settings \x7E");
|
||||
printLineF2(F("Settings \x7E"));
|
||||
else
|
||||
printLine2("Settings \x7E Off");
|
||||
printLineF2(F("Settings \x7E Off"));
|
||||
}else {
|
||||
if (!modeCalibrate){
|
||||
modeCalibrate = true;
|
||||
printLine2("Settings On");
|
||||
printLineF2(F("Settings On"));
|
||||
}
|
||||
else {
|
||||
modeCalibrate = false;
|
||||
printLine2("Settings Off");
|
||||
printLineF2(F("Settings Off"));
|
||||
}
|
||||
|
||||
while(btnDown())
|
||||
active_delay(100);
|
||||
active_delay(500);
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
return 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//this is used by the si5351 routines in the ubitx_5351 file
|
||||
//this is used by the si5351 routines in the ubitx_5351 file
|
||||
extern int32_t calibration;
|
||||
extern uint32_t si5351bx_vcoa;
|
||||
|
||||
|
@ -410,7 +420,7 @@ int calibrateClock(){
|
|||
keyDown = 0;
|
||||
stopTx();
|
||||
|
||||
printLine2("Calibration set!");
|
||||
printLineF2(F("Calibration set!"));
|
||||
EEPROM.put(MASTER_CAL, calibration);
|
||||
initOscillators();
|
||||
setFrequency(frequency);
|
||||
|
@ -426,12 +436,12 @@ int menuSetupCalibration(int btn){
|
|||
int32_t prev_calibration;
|
||||
|
||||
if (!btn){
|
||||
printLine2("Setup:Calibrate\x7E");
|
||||
printLineF2(F("Setup:Calibrate\x7E"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
printLine1("Press PTT & tune");
|
||||
printLine2("to exactly 10 MHz");
|
||||
printLineF1(F("Press PTT & tune"));
|
||||
printLineF2(F("to exactly 10 MHz"));
|
||||
active_delay(2000);
|
||||
calibrateClock();
|
||||
}
|
||||
|
@ -451,21 +461,30 @@ void printCarrierFreq(unsigned long freq){
|
|||
printLine2(c);
|
||||
}
|
||||
|
||||
void
|
||||
printFreq(unsigned long freq)
|
||||
{
|
||||
memset(c, 0, sizeof(c));
|
||||
memset(b, 0, sizeof(b));
|
||||
ultoa(freq, b, DEC);
|
||||
printLine2(b);
|
||||
}
|
||||
|
||||
void menuSetupCarrier(int btn){
|
||||
int knob = 0;
|
||||
unsigned long prevCarrier;
|
||||
|
||||
if (!btn){
|
||||
printLine2("Setup:BFO \x7E");
|
||||
printLineF2(F("Setup:BFO \x7E"));
|
||||
return;
|
||||
}
|
||||
|
||||
prevCarrier = usbCarrier;
|
||||
printLine1("Tune to best Signal");
|
||||
printLine2("Press to confirm. ");
|
||||
printLineF1(F("Tune to best Signal"));
|
||||
printLineF2(F("Press to confirm. "));
|
||||
active_delay(1000);
|
||||
|
||||
usbCarrier = 11995000l;
|
||||
usbCarrier = INIT_USB_FREQ;
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
printCarrierFreq(usbCarrier);
|
||||
|
||||
|
@ -486,14 +505,62 @@ void menuSetupCarrier(int btn){
|
|||
active_delay(100);
|
||||
}
|
||||
|
||||
printLine2("Carrier set! ");
|
||||
printLineF2(F("Carrier set! "));
|
||||
EEPROM.put(USB_CAL, usbCarrier);
|
||||
active_delay(1000);
|
||||
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
setFrequency(frequency);
|
||||
updateDisplay();
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
menuOn = 0;
|
||||
}
|
||||
|
||||
// Calibrate the IF frequency
|
||||
void menuSetupFreqIF(int btn){
|
||||
int knob = 0;
|
||||
unsigned long prevIF;
|
||||
|
||||
if (!btn){
|
||||
printLineF2(F("Setup:IF \x7E"));
|
||||
return;
|
||||
}
|
||||
|
||||
prevIF = firstIF;
|
||||
printLineF1(F("Tune to loudest signal"));
|
||||
printLineF2(F("Press to confirm. "));
|
||||
active_delay(1000);
|
||||
|
||||
setFrequency(frequency);
|
||||
printFreq(firstIF);
|
||||
|
||||
//disable all clock 1 and clock 2
|
||||
while (!btnDown()){
|
||||
knob = enc_read();
|
||||
|
||||
if (knob > 0)
|
||||
firstIF += 50;
|
||||
else if (knob < 0)
|
||||
firstIF -= 50;
|
||||
|
||||
checkPTT();
|
||||
|
||||
if (knob == 0)
|
||||
continue; //don't update the frequency or the display
|
||||
|
||||
setFrequency(frequency);
|
||||
printFreq(firstIF);
|
||||
|
||||
active_delay(100);
|
||||
}
|
||||
|
||||
printLineF2(F("IF set! "));
|
||||
|
||||
EEPROM.put(CAL_FIRST_IF_FREQ, firstIF);
|
||||
active_delay(1000);
|
||||
setFrequency(frequency);
|
||||
updateDisplay();
|
||||
printLineF2(F(""));
|
||||
menuOn = 0;
|
||||
}
|
||||
|
||||
|
@ -502,13 +569,13 @@ void menuSetupCwTone(int btn){
|
|||
int prev_sideTone;
|
||||
|
||||
if (!btn){
|
||||
printLine2("Setup:CW Tone \x7E");
|
||||
printLineF2(F("Setup:CW Tone \x7E"));
|
||||
return;
|
||||
}
|
||||
|
||||
prev_sideTone = sideTone;
|
||||
printLine1("Tune CW tone");
|
||||
printLine2("PTT to confirm. ");
|
||||
printLineF1(F("Tune CW tone"));
|
||||
printLineF2(F("PTT to confirm. "));
|
||||
active_delay(1000);
|
||||
tone(CW_TONE, sideTone);
|
||||
|
||||
|
@ -534,16 +601,16 @@ void menuSetupCwTone(int btn){
|
|||
noTone(CW_TONE);
|
||||
//save the setting
|
||||
if (digitalRead(PTT) == LOW){
|
||||
printLine2("Sidetone set! ");
|
||||
printLineF2(F("Sidetone set! "));
|
||||
EEPROM.put(CW_SIDETONE, sideTone);
|
||||
active_delay(2000);
|
||||
}
|
||||
else
|
||||
sideTone = prev_sideTone;
|
||||
|
||||
printLine2("");
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
printLineF2(F(""));
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
}
|
||||
|
||||
void menuSetupCwDelay(int btn){
|
||||
|
@ -551,7 +618,7 @@ void menuSetupCwDelay(int btn){
|
|||
int prev_cw_delay;
|
||||
|
||||
if (!btn){
|
||||
printLine2("Setup:CW Delay \x7E");
|
||||
printLineF2(F("Setup:CW Delay \x7E"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -559,8 +626,8 @@ void menuSetupCwDelay(int btn){
|
|||
prev_cw_delay = cwDelayTime;
|
||||
cwDelayTime = getValueByKnob(10, 1000, 50, cwDelayTime, "CW Delay>", " msec");
|
||||
|
||||
printLine1("CW Delay Set!");
|
||||
printLine2("");
|
||||
printLineF1(F("CW Delay Set!"));
|
||||
printLineF2(F(""));
|
||||
active_delay(500);
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
|
@ -571,11 +638,11 @@ void menuSetupKeyer(int btn){
|
|||
|
||||
if (!btn){
|
||||
if (!Iambic_Key)
|
||||
printLine2("Setup:CW(Hand)\x7E");
|
||||
printLineF2(F("Setup:CW(Hand)\x7E"));
|
||||
else if (keyerControl & IAMBICB)
|
||||
printLine2("Setup:CW(IambA)\x7E");
|
||||
printLineF2(F("Setup:CW(IambA)\x7E"));
|
||||
else
|
||||
printLine2("Setup:CW(IambB)\x7E");
|
||||
printLineF2(F("Setup:CW(IambB)\x7E"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -600,11 +667,11 @@ void menuSetupKeyer(int btn){
|
|||
tmp_key = 0;
|
||||
|
||||
if (tmp_key == 0)
|
||||
printLine1("Hand Key?");
|
||||
printLineF1(F("Hand Key?"));
|
||||
else if (tmp_key == 1)
|
||||
printLine1("Iambic A?");
|
||||
printLineF1(F("Iambic A?"));
|
||||
else if (tmp_key == 2)
|
||||
printLine1("Iambic B?");
|
||||
printLineF1(F("Iambic B?"));
|
||||
}
|
||||
|
||||
active_delay(500);
|
||||
|
@ -621,32 +688,67 @@ void menuSetupKeyer(int btn){
|
|||
|
||||
EEPROM.put(CW_KEY_TYPE, tmp_key);
|
||||
|
||||
printLine1("Keyer Set!");
|
||||
printLineF1(F("Keyer Set!"));
|
||||
active_delay(600);
|
||||
printLine1("");
|
||||
printLineF1(F(""));
|
||||
|
||||
//Added KD8CEC
|
||||
printLine2("");
|
||||
printLineF2(F(""));
|
||||
updateDisplay();
|
||||
menuOn = 0;
|
||||
menuOn = 0;
|
||||
}
|
||||
|
||||
void menuReadADC(int btn){
|
||||
int adc;
|
||||
|
||||
char a = 0, al; // Go from A0 -> A7
|
||||
int knob;
|
||||
|
||||
if (!btn){
|
||||
printLine2("6:Setup>Read ADC>");
|
||||
printLineF2(F("6:Setup>Read ADC>"));
|
||||
return;
|
||||
}
|
||||
delay(500);
|
||||
|
||||
while (!btnDown()){
|
||||
adc = analogRead(ANALOG_KEYER);
|
||||
// Assemble the display string, showing the A line and value
|
||||
c[0] = 0;
|
||||
strcat(c, "A");
|
||||
itoa(a, b, 10);
|
||||
strcat(c, b);
|
||||
strcat(c, " = ");
|
||||
|
||||
// Map A line to value, yeah, I wish it were easier?
|
||||
switch (a) {
|
||||
case 0: al = A0; break;
|
||||
case 1: al = A1; break;
|
||||
case 2: al = A2; break;
|
||||
case 3: al = A3; break;
|
||||
case 4: al = A4; break;
|
||||
case 5: al = A5; break;
|
||||
case 6: al = A6; break;
|
||||
case 7: al = A7; break;
|
||||
}
|
||||
adc = analogRead(al);
|
||||
itoa(adc, b, 10);
|
||||
printLine1(b);
|
||||
strcat(c, b);
|
||||
printLine1(c);
|
||||
|
||||
// Read the encoder, see if we need to change the ADC
|
||||
knob = enc_read();
|
||||
if ((knob > 4) && (a < 7)) {
|
||||
a++;
|
||||
delay(100);
|
||||
}
|
||||
if ((knob < -4) && (a > 0)) {
|
||||
a--;
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
printLine1("");
|
||||
printLineF1(F(""));
|
||||
|
||||
// Debounce the menu select
|
||||
delay(500);
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
|
@ -665,7 +767,7 @@ void doMenu(){
|
|||
btnState = btnDown();
|
||||
|
||||
if (i > 0){
|
||||
if (modeCalibrate && select + i < 150)
|
||||
if (modeCalibrate && select + i < 160)
|
||||
select += i;
|
||||
if (!modeCalibrate && select + i < 80)
|
||||
select += i;
|
||||
|
@ -701,6 +803,8 @@ void doMenu(){
|
|||
menuReadADC(btnState);
|
||||
else if (select < 140 && modeCalibrate)
|
||||
menuSetupKeyer(btnState);
|
||||
else if (select < 150 && modeCalibrate)
|
||||
menuSetupFreqIF(btnState);
|
||||
else
|
||||
menuExit(btnState);
|
||||
}
|
||||
|
@ -712,4 +816,3 @@ void doMenu(){
|
|||
|
||||
checkCAT();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,12 @@ void i2cWriten(uint8_t reg, uint8_t *vals, uint8_t vcnt) { // write array
|
|||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
// Call to set the drive strength, takes effect next frequency
|
||||
// set.
|
||||
void si5351bx_set_drive(uint8_t clknum, uint8_t drv)
|
||||
{
|
||||
si5351bx_drive[clknum] = drv & 0x3;
|
||||
}
|
||||
|
||||
void si5351bx_init() { // Call once at power-up, start PLLA
|
||||
uint8_t reg; uint32_t msxp1;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef __UBITX_UI_H__
|
||||
#define __UBITX_UI_H__
|
||||
|
||||
extern int btnDown(void);
|
||||
extern void initMeter(void);
|
||||
extern void drawMeter(uint8_t needle);
|
||||
extern void printLine(char linenmbr, const char *c);
|
||||
extern void printLineF(char linenmbr, const __FlashStringHelper *c);
|
||||
|
||||
|
||||
#define printLine1(c) printLine(1, (c))
|
||||
#define printLine2(c) printLine(0, (c))
|
||||
|
||||
#define printLineF1(c) printLineF(1, (c))
|
||||
#define printLineF2(c) printLineF(0, (c))
|
||||
|
||||
extern void updateDisplay(void);
|
||||
extern void updateMeterDisplay(void);
|
||||
extern void clearMeterDisplay(void);
|
||||
extern byte enc_state (void);
|
||||
extern int enc_read(void);
|
||||
|
||||
#endif
|
181
ubitx_ui.ino
181
ubitx_ui.ino
|
@ -6,8 +6,14 @@
|
|||
* quickly cleared up.
|
||||
*/
|
||||
|
||||
#include "ubitx4_eeprom_defs.h"
|
||||
#include "ubitx4_pin_config.h"
|
||||
|
||||
#include "ubitx_ui.h"
|
||||
|
||||
//returns true if the button is pressed
|
||||
int btnDown(){
|
||||
int btnDown(void)
|
||||
{
|
||||
if (digitalRead(FBUTTON) == HIGH)
|
||||
return 0;
|
||||
else
|
||||
|
@ -24,65 +30,59 @@ int btnDown(){
|
|||
*/
|
||||
|
||||
|
||||
char meter[17];
|
||||
char meter[2];
|
||||
|
||||
const byte PROGMEM s_meter_bitmap[] = {
|
||||
B00000,B00000,B00000,B00000,B00000,B00100,B00100,B11011,
|
||||
B10000,B10000,B10000,B10000,B10100,B10100,B10100,B11011,
|
||||
B01000,B01000,B01000,B01000,B01100,B01100,B01100,B11011,
|
||||
B00100,B00100,B00100,B00100,B00100,B00100,B00100,B11011,
|
||||
B00010,B00010,B00010,B00010,B00110,B00110,B00110,B11011,
|
||||
B00001,B00001,B00001,B00001,B00101,B00101,B00101,B11011,
|
||||
B10000,B11000,B11100,B11110,B11100,B11000,B10000,B00000,
|
||||
B00001,B00011,B00111,B01111,B00111,B00011,B00001,B00000
|
||||
const PROGMEM uint8_t s_meter_bitmap[64] = {
|
||||
B00000, B00000, B00000, B00000, B00000, B00000, B00000, B11111, //shortest bar
|
||||
B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111,
|
||||
B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111,
|
||||
B00000, B00000, B00000, B00000, B11111, B11111, B11111, B11111,
|
||||
B00000, B00000, B00000, B11111, B11111, B11111, B11111, B11111,
|
||||
B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111,
|
||||
B00000, B11111, B11111, B11111, B11111, B11111, B11111, B11111,
|
||||
B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111, // tallest bar
|
||||
};
|
||||
|
||||
// Initialise the custom character out of program memory
|
||||
static void
|
||||
initLcdChar(char lcd_char, char s_meter_bitmap_offset)
|
||||
{
|
||||
uint8_t tmp_bytes[8];
|
||||
char i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
tmp_bytes[i] = pgm_read_byte(&s_meter_bitmap[s_meter_bitmap_offset + i]);
|
||||
}
|
||||
lcd.createChar(lcd_char, tmp_bytes);
|
||||
}
|
||||
|
||||
// initializes the custom characters
|
||||
// we start from char 1 as char 0 terminates the string!
|
||||
void initMeter(){
|
||||
lcd.createChar(1, s_meter_bitmap);
|
||||
lcd.createChar(2, s_meter_bitmap + 8);
|
||||
lcd.createChar(3, s_meter_bitmap + 16);
|
||||
lcd.createChar(4, s_meter_bitmap + 24);
|
||||
lcd.createChar(5, s_meter_bitmap + 32);
|
||||
lcd.createChar(6, s_meter_bitmap + 40);
|
||||
lcd.createChar(0, s_meter_bitmap + 48);
|
||||
lcd.createChar(7, s_meter_bitmap + 56);
|
||||
void initMeter(void)
|
||||
{
|
||||
lcd.setCursor(0, 0); // Ensure we've reset to display RAM
|
||||
initLcdChar(0, 0); // First call - points to chargen RAM
|
||||
initLcdChar(1, 8);
|
||||
initLcdChar(2, 16);
|
||||
initLcdChar(3, 24);
|
||||
initLcdChar(4, 32);
|
||||
initLcdChar(5, 40);
|
||||
initLcdChar(6, 48);
|
||||
initLcdChar(7, 56);
|
||||
lcd.setCursor(0, 0); // Finish up - point to display RAM again
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The meter is drawn with special characters.
|
||||
* character 1 is used to simple draw the blocks of the scale of the meter
|
||||
* characters 2 to 6 are used to draw the needle in positions 1 to within the block
|
||||
* This displays a meter from 0 to 100, -1 displays nothing
|
||||
* The meter is drawn with special characters from 0..255
|
||||
*/
|
||||
|
||||
void drawMeter(int8_t needle){
|
||||
int16_t best, i, s;
|
||||
|
||||
if (needle < 0)
|
||||
return;
|
||||
|
||||
s = (needle * 4)/10;
|
||||
for (i = 0; i < 8; i++){
|
||||
if (s >= 5)
|
||||
meter[i] = 1;
|
||||
else if (s >= 0)
|
||||
meter[i] = 2 + s;
|
||||
else
|
||||
meter[i] = 1;
|
||||
s = s - 5;
|
||||
}
|
||||
if (needle >= 40)
|
||||
meter[i-1] = 6;
|
||||
meter[i] = 0;
|
||||
void drawMeter(uint8_t needle)
|
||||
{
|
||||
meter[0] = needle / 32;
|
||||
meter[1] = needle / 32;
|
||||
}
|
||||
|
||||
// The generic routine to display one line on the LCD
|
||||
void printLine(char linenmbr, char *c) {
|
||||
void printLine(char linenmbr, const char *c) {
|
||||
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
|
||||
lcd.setCursor(0, linenmbr); // place the cursor at the beginning of the selected line
|
||||
lcd.print(c);
|
||||
|
@ -94,18 +94,26 @@ void printLine(char linenmbr, char *c) {
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
printLineF(char linenmbr, const __FlashStringHelper *c)
|
||||
{
|
||||
int i;
|
||||
char tmp[17]; // XXX TODO: figure out how to do this inline without the buffer
|
||||
PGM_P p = reinterpret_cast<PGM_P>(c);
|
||||
unsigned char ch;
|
||||
|
||||
// short cut to print to the first line
|
||||
void printLine1(char *c){
|
||||
printLine(1,c);
|
||||
}
|
||||
// short cut to print to the first line
|
||||
void printLine2(char *c){
|
||||
printLine(0,c);
|
||||
for (i = 0; i < 17; i++) {
|
||||
ch = pgm_read_byte(p++);
|
||||
tmp[i] = ch;
|
||||
if (ch == 0)
|
||||
break;
|
||||
}
|
||||
printLine(linenmbr, tmp);
|
||||
}
|
||||
|
||||
// this builds up the top line of the display with frequency and mode
|
||||
void updateDisplay() {
|
||||
void updateDisplay(void)
|
||||
{
|
||||
// tks Jack Purdum W8TEE
|
||||
// replaced fsprint commmands by str commands for code size reduction
|
||||
|
||||
|
@ -134,19 +142,25 @@ void updateDisplay() {
|
|||
else
|
||||
strcat(c, "B:");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//one mhz digit if less than 10 M, two digits if more
|
||||
if (frequency < 10000000l){
|
||||
|
||||
/*
|
||||
* + zero mhz digit/one less dot if less than 1MHz
|
||||
* + one mhz digit if less than 10MHz
|
||||
* + two digits if more
|
||||
*/
|
||||
if (frequency < 1000000L) {
|
||||
c[6] = ' '; c[7] = ' '; c[8] = ' ';
|
||||
strncat(c, &b[0], 3);
|
||||
strcat(c, ".");
|
||||
strncat(c, &b[3], 3);
|
||||
} else if (frequency < 10000000l){
|
||||
c[6] = ' ';
|
||||
c[7] = b[0];
|
||||
strcat(c, ".");
|
||||
strncat(c, &b[1], 3);
|
||||
strcat(c, ".");
|
||||
strncat(c, &b[4], 3);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
strncat(c, b, 2);
|
||||
strcat(c, ".");
|
||||
strncat(c, &b[2], 3);
|
||||
|
@ -157,22 +171,41 @@ void updateDisplay() {
|
|||
if (inTx)
|
||||
strcat(c, " TX");
|
||||
printLine(1, c);
|
||||
}
|
||||
|
||||
/*
|
||||
//now, the second line
|
||||
memset(c, 0, sizeof(c));
|
||||
memset(b, 0, sizeof(b));
|
||||
* Update the meter display!
|
||||
*/
|
||||
void
|
||||
updateMeterDisplay(void)
|
||||
{
|
||||
int meter_reading = 0;
|
||||
|
||||
if (inTx)
|
||||
strcat(c, "TX ");
|
||||
else if (ritOn)
|
||||
strcpy(c, "RIT");
|
||||
// Second line, meter on A7 (ANALOG_SPARE)
|
||||
meter_reading = analogRead(ANALOG_SPARE);
|
||||
|
||||
strcpy(c, " \xff");
|
||||
drawMeter(meter_reading);
|
||||
strcat(c, meter);
|
||||
strcat(c, "\xff");
|
||||
printLine2(c);*/
|
||||
// TODO - there's no mapping table here yet! Just linear it!
|
||||
if (meter_reading > 255) {
|
||||
// Ensure we definitely don't overflow an int here
|
||||
meter_reading = 255;
|
||||
}
|
||||
drawMeter(meter_reading); // this takes uint8_t
|
||||
lcd.setCursor(14, 0);
|
||||
lcd.write(meter[0]);
|
||||
lcd.setCursor(15, 0);
|
||||
lcd.write(meter[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the meter - used during transmit
|
||||
*/
|
||||
void
|
||||
clearMeterDisplay(void)
|
||||
{
|
||||
lcd.setCursor(14, 0);
|
||||
lcd.write(' ');
|
||||
lcd.setCursor(15, 0);
|
||||
lcd.write(' ');
|
||||
}
|
||||
|
||||
int enc_prev_state = 3;
|
||||
|
@ -234,5 +267,3 @@ int enc_read(void) {
|
|||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue