Delete control_lcd_45mhz_if_v4.ino
This commit is contained in:
parent
91f3ecdf22
commit
ae8d03601d
@ -1,901 +0,0 @@
|
|||||||
/**
|
|
||||||
* This is source code for the scratch built ubitx, it is no longer used for the kits.
|
|
||||||
*
|
|
||||||
* This source file is under General Public License version 3.
|
|
||||||
*
|
|
||||||
* Most source code are meant to be understood by the compilers and the computers.
|
|
||||||
* Code that has to be hackable needs to be well understood and properly documented.
|
|
||||||
* Donald Knuth coined the term Literate Programming to indicate code that is written be
|
|
||||||
* easily read and understood.
|
|
||||||
*
|
|
||||||
* The Raduino is a small board that includes the Arduin Nano, a 16x2 LCD display and
|
|
||||||
* an Si5351a frequency synthesizer. This board is manufactured by Paradigm Ecomm Pvt Ltd
|
|
||||||
*
|
|
||||||
* To learn more about Arduino you may visit www.arduino.cc.
|
|
||||||
*
|
|
||||||
* The Arduino works by firt executing the code in a function called setup() and then it
|
|
||||||
* repeatedly keeps calling loop() forever. All the initialization code is kept in setup()
|
|
||||||
* and code to continuously sense the tuning knob, the function button, transmit/receive,
|
|
||||||
* etc is all in the loop() function. If you wish to study the code top down, then scroll
|
|
||||||
* to the bottom of this file and read your way up.
|
|
||||||
*
|
|
||||||
* Below are the libraries to be included for building the Raduino
|
|
||||||
* The EEPROM library is used to store settings like the frequency memory, caliberation data,
|
|
||||||
* callsign etc .
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <EEPROM.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
|
|
||||||
* from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
|
|
||||||
* Instead, you can look up the Si5351 library written by xxx, yyy. You can download and
|
|
||||||
* install it from www.url.com to complile this file.
|
|
||||||
* The Wire.h library is used to talk to the Si5351 and we also declare an instance of
|
|
||||||
* Si5351 object to control the clocks.
|
|
||||||
*/
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <si5351.h>
|
|
||||||
Si5351 si5351;
|
|
||||||
/**
|
|
||||||
* The Radiono 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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory.
|
|
||||||
* We have to be very careful with variables that are declared inside the functions as they are
|
|
||||||
* created in a memory region called the stack. The stack has just a few bytes of space on the Arduino
|
|
||||||
* if you declare large strings inside functions, they can easily exceed the capacity of the stack
|
|
||||||
* and mess up your programs.
|
|
||||||
* We circumvent this by declaring a few global buffers as kitchen counters where we can
|
|
||||||
* slice and dice our strings. These strings are mostly used to control the display or handle
|
|
||||||
* the input and output from the USB port. We must keep a count of the bytes used while reading
|
|
||||||
* the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable.
|
|
||||||
*/
|
|
||||||
char serial_in[32], c[30], b[30], printBuff[32];
|
|
||||||
int count = 0;
|
|
||||||
unsigned char serial_in_count = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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:
|
|
||||||
* A0, A1, A2, A3, +5v, GND, A6, A7
|
|
||||||
* (while holding the board up so that back of the board faces you)
|
|
||||||
*
|
|
||||||
* 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 S_METER (A0)
|
|
||||||
#define PTT (A1)
|
|
||||||
#define FBUTTON (A3)
|
|
||||||
#define ANALOG_KEYER (A7)
|
|
||||||
#define ANALOG_TUNING (A6)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The second set of 16 pins on the 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_SEL (5)
|
|
||||||
#define CW_KEY (4)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The raduino has a number of timing parameters, all specified in milliseconds
|
|
||||||
* CW_TIMEOUT : how many milliseconds between consecutive keyup and keydowns before switching back to receive?
|
|
||||||
* The next set of three parameters determine what is a tap, a double tap and a hold time for the funciton button
|
|
||||||
* TAP_DOWN_MILLIS : upper limit of how long a tap can be to be considered as a button_tap
|
|
||||||
* TAP_UP_MILLIS : upper limit of how long a gap can be between two taps of a button_double_tap
|
|
||||||
* TAP_HOLD_MILIS : many milliseconds of the buttonb being down before considering it to be a button_hold
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define TAP_UP_MILLIS (500)
|
|
||||||
#define TAP_DOWN_MILLIS (600)
|
|
||||||
#define TAP_HOLD_MILLIS (2000)
|
|
||||||
#define CW_TIMEOUT (2000l) // in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Raduino supports two VFOs : A and B and receiver incremental tuning (RIT).
|
|
||||||
* we define a variables to hold the frequency of the two VFOs, RITs
|
|
||||||
* the rit offset as well as status of the RIT
|
|
||||||
*/
|
|
||||||
#define VFO_A 0
|
|
||||||
#define VFO_B 1
|
|
||||||
char ritOn = 0;
|
|
||||||
char vfoActive = VFO_A;
|
|
||||||
unsigned long vfoA=7100000L, vfoB=14200000L, ritA, ritB, sideTone=800, lsbCarrier, usbCarrier;
|
|
||||||
|
|
||||||
#define MASTER_CAL 0
|
|
||||||
#define LSB_CAL 4
|
|
||||||
#define USB_CAL 8
|
|
||||||
#define SIDE_TONE 12
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raduino needs to keep track of current state of the transceiver. These are a few variables that do it
|
|
||||||
*/
|
|
||||||
char inTx = 0;
|
|
||||||
char keyDown = 0;
|
|
||||||
char isUSB = 0;
|
|
||||||
unsigned long cwTimeout = 0;
|
|
||||||
unsigned char txFilter = 0;
|
|
||||||
|
|
||||||
/** Tuning Mechanism of the Raduino
|
|
||||||
* We use a linear pot that has two ends connected to +5 and the ground. the middle wiper
|
|
||||||
* is connected to ANALOG_TUNNING pin. Depending upon the position of the wiper, the
|
|
||||||
* reading can be anywhere from 0 to 1024.
|
|
||||||
* The tuning control works in steps of 50Hz each for every increment between 50 and 950.
|
|
||||||
* Hence the turning the pot fully from one end to the other will cover 50 x 900 = 45 KHz.
|
|
||||||
* At the two ends, that is, the tuning starts slowly stepping up or down in 10 KHz steps
|
|
||||||
* To stop the scanning the pot is moved back from the edge.
|
|
||||||
* To rapidly change from one band to another, you press the function button and then
|
|
||||||
* move the tuning pot. Now, instead of 50 Hz, the tuning is in steps of 50 KHz allowing you
|
|
||||||
* rapidly use it like a 'bandset' control.
|
|
||||||
* To implement this, we fix a 'base frequency' to which we add the offset that the pot
|
|
||||||
* points to. We also store the previous position to know if we need to wake up and change
|
|
||||||
* the frequency.
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned long baseTune = 7100000L;
|
|
||||||
int old_knob = 0;
|
|
||||||
|
|
||||||
#define FIRST_IF (45000000l)
|
|
||||||
#define SECOND_OSC (57000000l)
|
|
||||||
#define INIT_USB_FREQ (11996500l)
|
|
||||||
#define INIT_LSB_FREQ (11998500l)
|
|
||||||
#define LOWEST_FREQ (3000000l)
|
|
||||||
#define HIGHEST_FREQ (30000000l)
|
|
||||||
|
|
||||||
long frequency, stepSize=100000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The raduino can be booted into multiple modes:
|
|
||||||
* MODE_NORMAL : works the radio normally
|
|
||||||
* MODE_CALIBRATION : used to calibrate Raduino.
|
|
||||||
* To enter this mode, hold the function button down and power up. Tune to exactly 10 MHz on clock0 and release the function button
|
|
||||||
*/
|
|
||||||
#define MODE_NORMAL (0)
|
|
||||||
#define MODE_CALIBRATE (1)
|
|
||||||
char mode = MODE_NORMAL;
|
|
||||||
|
|
||||||
char meter[17];
|
|
||||||
byte s_meter[] = {
|
|
||||||
B0,B0,B0,B0,B0,B00000,B0,B10101,
|
|
||||||
B0,B0,B0,B0,B10000,B10000,B0,B10101,
|
|
||||||
B0,B0,B0,B0,B11000,B11000,B0,B10101,
|
|
||||||
B0,B0,B0,B0,B11100,B11100,B0,B10101,
|
|
||||||
B0,B0,B0,B0,B11110,B11110,B0,B10101,
|
|
||||||
B0,B0,B0,B0,B11111,B11111,B0,B10101
|
|
||||||
};
|
|
||||||
|
|
||||||
void setupSmeter(){
|
|
||||||
lcd.createChar(1, s_meter);
|
|
||||||
lcd.createChar(2, s_meter + 8);
|
|
||||||
lcd.createChar(3, s_meter + 16);
|
|
||||||
lcd.createChar(4, s_meter + 24);
|
|
||||||
lcd.createChar(5, s_meter + 32);
|
|
||||||
lcd.createChar(6, s_meter + 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* display routines */
|
|
||||||
void printLine1(char *c){
|
|
||||||
if (strcmp(c, printBuff)){
|
|
||||||
lcd.setCursor(0, 0);
|
|
||||||
lcd.print(c);
|
|
||||||
strcpy(printBuff, c);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void printLine2(char *c){
|
|
||||||
if (strlen(c) > 16)
|
|
||||||
c[16] = 0;
|
|
||||||
lcd.setCursor(0, 1);
|
|
||||||
lcd.print(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void displayFrequency(unsigned long f){
|
|
||||||
int mhz, khz, hz;
|
|
||||||
|
|
||||||
mhz = f / 1000000l;
|
|
||||||
khz = (f % 1000000l)/1000;
|
|
||||||
hz = f % 1000l;
|
|
||||||
sprintf(b, "[%02d.%03d.%03d]", mhz, khz, hz);
|
|
||||||
printLine1(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateMeter(){
|
|
||||||
int16_t best, i, s;
|
|
||||||
|
|
||||||
best = 0;
|
|
||||||
//take 100 readings, take the peaks
|
|
||||||
for (i = 0; i < 100; i++){
|
|
||||||
s = analogRead(S_METER);
|
|
||||||
if (s > best)
|
|
||||||
best = s;
|
|
||||||
}
|
|
||||||
//now, use the s to get the signal
|
|
||||||
s = best *2;
|
|
||||||
sprintf(meter, "%3d", s);
|
|
||||||
for (i = 3; i < 14; i++){
|
|
||||||
if (s >= 5)
|
|
||||||
meter[i] = 6;
|
|
||||||
else if (s > 0)
|
|
||||||
meter[i] = 1 + s;
|
|
||||||
else
|
|
||||||
meter[i] = 1;
|
|
||||||
s = s - 5;
|
|
||||||
}
|
|
||||||
meter[i] = 0;
|
|
||||||
printLine2(meter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines for menus
|
|
||||||
*/
|
|
||||||
byte menuOn = 0;
|
|
||||||
|
|
||||||
int ritToggle(int btn){
|
|
||||||
if (!btn){
|
|
||||||
if (ritOn == 1)
|
|
||||||
printLine2("RIT:On, Off? ");
|
|
||||||
else
|
|
||||||
printLine2("RIT:Off, On? ");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (ritOn == 0){
|
|
||||||
ritOn = 1;
|
|
||||||
printLine2("RIT is On. ");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ritOn = 0;
|
|
||||||
printLine2("RIT Is Off. ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int vfoToggle(int btn){
|
|
||||||
|
|
||||||
if (!btn){
|
|
||||||
if (vfoActive == VFO_A)
|
|
||||||
printLine2("Select VFO B? ");
|
|
||||||
else
|
|
||||||
printLine2("Select VFO A? ");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (vfoActive == VFO_A){
|
|
||||||
vfoActive = VFO_A;
|
|
||||||
printLine1("Selected VFO A ");
|
|
||||||
frequency = vfoA;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vfoActive = VFO_B;
|
|
||||||
printLine1("Selected VFO B ");
|
|
||||||
frequency = vfoB;
|
|
||||||
}
|
|
||||||
setFrequency(frequency);
|
|
||||||
updateDisplay();
|
|
||||||
resetBasefrequency();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the new correction and resets the clock 0 to 10 MHz
|
|
||||||
*/
|
|
||||||
|
|
||||||
void recalibrate(int32_t correction){
|
|
||||||
|
|
||||||
si5351.set_correction(correction);
|
|
||||||
|
|
||||||
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
|
|
||||||
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB);
|
|
||||||
|
|
||||||
si5351.output_enable(SI5351_CLK0, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK1, 0);
|
|
||||||
si5351.output_enable(SI5351_CLK2, 0);
|
|
||||||
|
|
||||||
si5351.set_freq(1000000000ULL, SI5351_CLK0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void calibrateMaster(int btn){
|
|
||||||
int knob = 0;
|
|
||||||
int32_t correction;
|
|
||||||
|
|
||||||
if (!btn){
|
|
||||||
printLine2("Set Calibration?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
printLine1("Set to 10.000.000");
|
|
||||||
printLine2("PTT to confirm. ");
|
|
||||||
delay(2000);
|
|
||||||
|
|
||||||
recalibrate(0);
|
|
||||||
|
|
||||||
//disable all clock 1 and clock 2
|
|
||||||
while(digitalRead(PTT) == HIGH && !btnDown()){
|
|
||||||
knob = analogRead(ANALOG_TUNING);
|
|
||||||
correction = (knob - 500) * 500ULL;
|
|
||||||
recalibrate(correction);
|
|
||||||
//abort if this button is down
|
|
||||||
if (btnDown()){
|
|
||||||
//re-enable the clock1 and clock 2
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sprintf(c, "%3d ", knob);
|
|
||||||
printLine2(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
//save the setting
|
|
||||||
if (digitalRead(PTT) == LOW){
|
|
||||||
printLine2("Calibration set!");
|
|
||||||
EEPROM.put(MASTER_CAL, correction);
|
|
||||||
delay(2000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EEPROM.get(MASTER_CAL, correction);
|
|
||||||
}
|
|
||||||
|
|
||||||
si5351.set_correction(correction);
|
|
||||||
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
|
|
||||||
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB);
|
|
||||||
|
|
||||||
si5351.output_enable(SI5351_CLK0, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK1, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK2, 1);
|
|
||||||
|
|
||||||
resetBasefrequency();
|
|
||||||
setFrequency(frequency);
|
|
||||||
updateDisplay();
|
|
||||||
menuOn = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBFO(int btn, byte isLSB){
|
|
||||||
int knob = 0;
|
|
||||||
int32_t lsb_Freq;
|
|
||||||
|
|
||||||
if (!btn){
|
|
||||||
if (isLSB)
|
|
||||||
printLine2("Set LSB Carrier ");
|
|
||||||
else
|
|
||||||
printLine2("Set USB Carrier ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isLSB)
|
|
||||||
printLine1("Tune to best LSB");
|
|
||||||
else
|
|
||||||
printLine1("Tune to best USB");
|
|
||||||
printLine2("PTT to confirm. ");
|
|
||||||
delay(2000);
|
|
||||||
|
|
||||||
//disable all clock 1 and clock 2
|
|
||||||
while(digitalRead(PTT) == HIGH && !btnDown()){
|
|
||||||
knob = analogRead(ANALOG_TUNING);
|
|
||||||
if (isLSB){
|
|
||||||
lsbCarrier = 12000000l - knob * 10;
|
|
||||||
si5351.set_freq(lsbCarrier * 100ULL, SI5351_CLK0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
usbCarrier = 12000000l - knob * 10;
|
|
||||||
si5351.set_freq(usbCarrier * 100ULL, SI5351_CLK0);
|
|
||||||
}
|
|
||||||
//abort if this button is down
|
|
||||||
if (btnDown()){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sprintf(c, "%3d ", knob);
|
|
||||||
printLine2(c);
|
|
||||||
}
|
|
||||||
//save the setting
|
|
||||||
if (digitalRead(PTT) == LOW){
|
|
||||||
printLine2("Carrier set! ");
|
|
||||||
if (isLSB)
|
|
||||||
EEPROM.put(LSB_CAL, lsbCarrier);
|
|
||||||
else
|
|
||||||
EEPROM.put(USB_CAL, usbCarrier);
|
|
||||||
delay(2000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
EEPROM.get(LSB_CAL, lsbCarrier);
|
|
||||||
EEPROM.get(USB_CAL, usbCarrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
resetBasefrequency();
|
|
||||||
setFrequency(frequency);
|
|
||||||
updateDisplay();
|
|
||||||
menuOn = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetBasefrequency(){
|
|
||||||
int knob = analogRead(ANALOG_TUNING);
|
|
||||||
baseTune = frequency - (50l * knob);
|
|
||||||
}
|
|
||||||
|
|
||||||
int exitMenu(int btn){
|
|
||||||
|
|
||||||
if (!btn){
|
|
||||||
printLine2("Exit Menu? ");
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
menuOn = 0;
|
|
||||||
resetBasefrequency();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void doMenu(){
|
|
||||||
int select, btnState;
|
|
||||||
menuOn = 1;
|
|
||||||
|
|
||||||
while(menuOn){
|
|
||||||
select = analogRead(ANALOG_TUNING);
|
|
||||||
//downscale the selection
|
|
||||||
select = (select-50)/50;
|
|
||||||
btnState = btnDown();
|
|
||||||
delay(200);
|
|
||||||
switch(select){
|
|
||||||
case 0:
|
|
||||||
ritToggle(btnState);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
vfoToggle(btnState);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
calibrateMaster(btnState);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
setBFO(btnState, 1);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
setBFO(btnState, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
exitMenu(btnState);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateDisplay(){
|
|
||||||
sprintf(b, "%8ld", frequency);
|
|
||||||
sprintf(c, "%s:%.2s.%.3s.%1s", vfoActive == VFO_A ? "A" : "B" , b, b+2, b+5);
|
|
||||||
if (isUSB)
|
|
||||||
strcat(c, " USB");
|
|
||||||
else
|
|
||||||
strcat(c, " LSB");
|
|
||||||
|
|
||||||
if (inTx)
|
|
||||||
strcat(c, " TX");
|
|
||||||
else if (ritOn)
|
|
||||||
strcat(c, " +R");
|
|
||||||
else
|
|
||||||
strcat(c, " ");
|
|
||||||
|
|
||||||
|
|
||||||
printLine1(c);
|
|
||||||
/* sprintf(c, "%s %s %d", isLSB ? "LSB" : "USB", inTx ? " TX" : " RX", digitalRead(FBUTTON));
|
|
||||||
printLine2(c); */
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSidebandAndTXFilters(unsigned long freq){
|
|
||||||
|
|
||||||
if (freq > 10000000L){
|
|
||||||
isUSB = 1;
|
|
||||||
si5351.set_freq(usbCarrier * 100ULL, SI5351_CLK0);
|
|
||||||
digitalWrite(TX_LPF_SEL, 1);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
isUSB = 0;
|
|
||||||
digitalWrite(TX_LPF_SEL, 0);
|
|
||||||
si5351.set_freq(lsbCarrier * 100ULL, SI5351_CLK0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFrequency(unsigned long f){
|
|
||||||
uint64_t osc_f;
|
|
||||||
|
|
||||||
setSidebandAndTXFilters(f);
|
|
||||||
|
|
||||||
if (isUSB)
|
|
||||||
si5351.set_freq((SECOND_OSC - usbCarrier + f) * 100ULL, SI5351_CLK2);
|
|
||||||
else
|
|
||||||
si5351.set_freq((SECOND_OSC - lsbCarrier + f) * 100ULL, SI5351_CLK2);
|
|
||||||
|
|
||||||
frequency = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkTX(){
|
|
||||||
|
|
||||||
//we don't check for ptt when transmitting cw
|
|
||||||
if (cwTimeout > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (digitalRead(PTT) == 0 && inTx == 0){
|
|
||||||
inTx = 1;
|
|
||||||
digitalWrite(TX_RX, 1);
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (digitalRead(PTT) == 1 && inTx == 1){
|
|
||||||
inTx = 0;
|
|
||||||
digitalWrite(TX_RX, 0);
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
byte prevWasDot = 0;
|
|
||||||
|
|
||||||
void keyer(){
|
|
||||||
int key = analogRead(ANALOG_KEYER);
|
|
||||||
|
|
||||||
if (key < 50) //straight key
|
|
||||||
keyDown();
|
|
||||||
else if (key < 300) // both
|
|
||||||
if (prevWasDot){
|
|
||||||
keyDown(dotPeriod * 3);
|
|
||||||
prevWasDot = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
keyDown(dotPeriod);
|
|
||||||
prevWasDot = 1;
|
|
||||||
}
|
|
||||||
else if (key < 600){ //dash
|
|
||||||
keyDown(dotPeriod * 3);
|
|
||||||
prevWasDot = 0;
|
|
||||||
}
|
|
||||||
else if (key > 900){ //dot
|
|
||||||
keyUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void checkCW2(){
|
|
||||||
|
|
||||||
if (keyDown == 0 && analogRead(ANALOG_KEYER) < 50){
|
|
||||||
//switch to transmit mode if we are not already in it
|
|
||||||
if (inTx == 0){
|
|
||||||
digitalWrite(TX_RX, 1);
|
|
||||||
// selectTransmitFilter();
|
|
||||||
//give the relays a few ms to settle the T/R relays
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
inTx = 1;
|
|
||||||
keyDown = 1;
|
|
||||||
tone(CW_TONE, (int)sideTone);
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset the timer as long as the key is down
|
|
||||||
if (keyDown == 1){
|
|
||||||
cwTimeout = CW_TIMEOUT + millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we have a keyup
|
|
||||||
if (keyDown == 1 && analogRead(ANALOG_KEYER) > 150){
|
|
||||||
keyDown = 0;
|
|
||||||
noTone(CW_TONE);
|
|
||||||
cwTimeout = millis() + CW_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we are in cw-mode and have a keyuup for a longish time
|
|
||||||
if (cwTimeout > 0 && inTx == 1 && cwTimeout < millis()){
|
|
||||||
//move the radio back to receive
|
|
||||||
digitalWrite(TX_RX, 0);
|
|
||||||
inTx = 0;
|
|
||||||
cwTimeout = 0;
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkCW3(){
|
|
||||||
|
|
||||||
if (keyDown == 0 && analogRead(ANALOG_KEYER) < 50){
|
|
||||||
//switch to transmit mode if we are not already in it
|
|
||||||
if (inTx == 0){
|
|
||||||
|
|
||||||
if (isUSB)
|
|
||||||
si5351.set_freq((frequency + sideTone) * 100ULL, SI5351_CLK2);
|
|
||||||
else
|
|
||||||
si5351.set_freq((frequency - sideTone) * 100ULL, SI5351_CLK2);
|
|
||||||
//switch off the second oscillator and the bfo
|
|
||||||
si5351.output_enable(SI5351_CLK0, 0);
|
|
||||||
si5351.output_enable(SI5351_CLK1, 0);
|
|
||||||
si5351.output_enable(SI5351_CLK2, 1);
|
|
||||||
|
|
||||||
digitalWrite(TX_RX, 1);
|
|
||||||
// selectTransmitFilter();
|
|
||||||
//give the relays a few ms to settle the T/R relays
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
inTx = 1;
|
|
||||||
keyDown = 1;
|
|
||||||
tone(CW_TONE, (int)sideTone);
|
|
||||||
digitalWrite(CW_KEY, 1);
|
|
||||||
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset the timer as long as the key is down
|
|
||||||
if (keyDown == 1){
|
|
||||||
cwTimeout = CW_TIMEOUT + millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we have a keyup
|
|
||||||
if (keyDown == 1 && analogRead(ANALOG_KEYER) > 150){
|
|
||||||
keyDown = 0;
|
|
||||||
noTone(CW_TONE);
|
|
||||||
digitalWrite(CW_KEY, 0);
|
|
||||||
cwTimeout = millis() + CW_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we are in cw-mode and have a keyuup for a longish time
|
|
||||||
if (cwTimeout > 0 && inTx == 1 && cwTimeout < millis()){
|
|
||||||
//move the radio back to receive
|
|
||||||
digitalWrite(TX_RX, 0);
|
|
||||||
inTx = 0;
|
|
||||||
cwTimeout = 0;
|
|
||||||
updateDisplay();
|
|
||||||
|
|
||||||
//switch off the second oscillator and the bfo
|
|
||||||
si5351.output_enable(SI5351_CLK0, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK1, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK2, 1);
|
|
||||||
setFrequency(frequency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void checkCW(){
|
|
||||||
|
|
||||||
if (keyDown == 0 && analogRead(ANALOG_KEYER) < 50){
|
|
||||||
//switch to transmit mode if we are not already in it
|
|
||||||
if (inTx == 0){
|
|
||||||
digitalWrite(TX_RX, 1);
|
|
||||||
delay(50);
|
|
||||||
inTx = 1;
|
|
||||||
keyDown = 1;
|
|
||||||
}
|
|
||||||
if (isUSB)
|
|
||||||
si5351.set_freq((frequency + sideTone) * 100ULL, SI5351_CLK2);
|
|
||||||
else
|
|
||||||
si5351.set_freq((frequency - sideTone) * 100ULL, SI5351_CLK2);
|
|
||||||
//switch off the second oscillator and the bfo
|
|
||||||
si5351.output_enable(SI5351_CLK0, 0);
|
|
||||||
si5351.output_enable(SI5351_CLK1, 0);
|
|
||||||
si5351.output_enable(SI5351_CLK2, 1);
|
|
||||||
|
|
||||||
digitalWrite(CW_KEY, 1);
|
|
||||||
tone(CW_TONE, sideTone);
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset the timer as long as the key is down
|
|
||||||
if (keyDown == 1){
|
|
||||||
cwTimeout = CW_TIMEOUT + millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we have a keyup
|
|
||||||
if (keyDown == 1 && analogRead(ANALOG_KEYER) > 150){
|
|
||||||
keyDown = 0;
|
|
||||||
noTone(CW_TONE);
|
|
||||||
digitalWrite(CW_KEY, 0);
|
|
||||||
cwTimeout = millis() + CW_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if we are in cw-mode and have a keyuup for a longish time
|
|
||||||
if (cwTimeout > 0 && inTx == 1 && cwTimeout < millis()){
|
|
||||||
//move the radio back to receive
|
|
||||||
digitalWrite(TX_RX, 0);
|
|
||||||
inTx = 0;
|
|
||||||
cwTimeout = 0;
|
|
||||||
//switch off the second oscillator and the bfo
|
|
||||||
si5351.output_enable(SI5351_CLK0, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK1, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK2, 1);
|
|
||||||
setFrequency(frequency);
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int btnDown(){
|
|
||||||
if (digitalRead(FBUTTON) == HIGH)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkButton(){
|
|
||||||
int i, t1, t2, knob, new_knob, duration;
|
|
||||||
|
|
||||||
//only if the button is pressed
|
|
||||||
if (!btnDown())
|
|
||||||
return;
|
|
||||||
|
|
||||||
//wait for 50 ms before declaring the button to be really down
|
|
||||||
delay(50);
|
|
||||||
if (!btnDown())
|
|
||||||
return;
|
|
||||||
|
|
||||||
t1 = millis();
|
|
||||||
knob = analogRead(ANALOG_TUNING);
|
|
||||||
duration = 0;
|
|
||||||
|
|
||||||
/* keep measuring how long the duration of btn down has been to a max of 3 seconds */
|
|
||||||
while (btnDown() && duration < 3000){
|
|
||||||
/* if the tuning knob is moved while the btn is down,
|
|
||||||
then track the bandset until the button is up and return
|
|
||||||
*/
|
|
||||||
new_knob = analogRead(ANALOG_TUNING);
|
|
||||||
if (abs(new_knob - knob) > 10){
|
|
||||||
int count = 0;
|
|
||||||
/* track the tuning and return */
|
|
||||||
while (btnDown()){
|
|
||||||
frequency = baseTune = ((analogRead(ANALOG_TUNING) * 30000l) + 1000000l);
|
|
||||||
setFrequency(frequency);
|
|
||||||
updateDisplay();
|
|
||||||
count++;
|
|
||||||
delay(200);
|
|
||||||
}
|
|
||||||
delay(1000);
|
|
||||||
return;
|
|
||||||
} /* end of handling the bandset */
|
|
||||||
|
|
||||||
delay(100);
|
|
||||||
duration += 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duration < 1000) {
|
|
||||||
printLine2("Menu.");
|
|
||||||
doMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void doTuning(){
|
|
||||||
unsigned long newFreq;
|
|
||||||
|
|
||||||
int knob = analogRead(ANALOG_TUNING);
|
|
||||||
unsigned long old_freq = frequency;
|
|
||||||
|
|
||||||
if (knob < 10 && frequency > LOWEST_FREQ) {
|
|
||||||
baseTune = baseTune - 1000l;
|
|
||||||
frequency = baseTune;
|
|
||||||
updateDisplay();
|
|
||||||
setFrequency(frequency);
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
else if (knob > 1010 && frequency < HIGHEST_FREQ) {
|
|
||||||
baseTune = baseTune + 1000l;
|
|
||||||
frequency = baseTune + 50000l;
|
|
||||||
setFrequency(frequency);
|
|
||||||
updateDisplay();
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
// in the middle, it is business as usual
|
|
||||||
else if (knob != old_knob){
|
|
||||||
frequency = baseTune + (50l * knob);
|
|
||||||
old_knob = knob;
|
|
||||||
setFrequency(frequency);
|
|
||||||
updateDisplay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
int32_t cal;
|
|
||||||
|
|
||||||
lcd.begin(16, 2);
|
|
||||||
setupSmeter();
|
|
||||||
printBuff[0] = 0;
|
|
||||||
printLine1("HFuino v0.01 ");
|
|
||||||
printLine2(" ");
|
|
||||||
|
|
||||||
EEPROM.get(MASTER_CAL, cal);
|
|
||||||
EEPROM.get(LSB_CAL, lsbCarrier);
|
|
||||||
EEPROM.get(USB_CAL, usbCarrier);
|
|
||||||
//set the lsb and usb to defaults
|
|
||||||
if (lsbCarrier == 0)
|
|
||||||
lsbCarrier = INIT_LSB_FREQ;
|
|
||||||
if (usbCarrier == 0)
|
|
||||||
usbCarrier = INIT_USB_FREQ;
|
|
||||||
|
|
||||||
// Start serial and initialize the Si5351
|
|
||||||
Serial.begin(9600);
|
|
||||||
analogReference(DEFAULT);
|
|
||||||
Serial.println("*HFuino v0.01\n");
|
|
||||||
Serial.println("*Searching Si5351\n");
|
|
||||||
|
|
||||||
//configure the function button to use the external pull-up
|
|
||||||
pinMode(FBUTTON, INPUT);
|
|
||||||
digitalWrite(FBUTTON, HIGH);
|
|
||||||
|
|
||||||
pinMode(PTT, INPUT);
|
|
||||||
digitalWrite(PTT, HIGH);
|
|
||||||
|
|
||||||
digitalWrite(ANALOG_KEYER, HIGH);
|
|
||||||
|
|
||||||
pinMode(CW_TONE, OUTPUT);
|
|
||||||
digitalWrite(CW_TONE, 0);
|
|
||||||
pinMode(TX_RX,OUTPUT);
|
|
||||||
digitalWrite(TX_RX, 0);
|
|
||||||
pinMode(TX_LPF_SEL, OUTPUT);
|
|
||||||
digitalWrite(TX_LPF_SEL, 0);
|
|
||||||
pinMode(CW_KEY, OUTPUT);
|
|
||||||
digitalWrite(CW_KEY, 0);
|
|
||||||
EEPROM.get(0,cal);
|
|
||||||
|
|
||||||
si5351.init(SI5351_CRYSTAL_LOAD_8PF,25000000l,0);
|
|
||||||
|
|
||||||
si5351.set_correction(cal);
|
|
||||||
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
|
|
||||||
si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB);
|
|
||||||
|
|
||||||
si5351.output_enable(SI5351_CLK0, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK1, 1);
|
|
||||||
si5351.output_enable(SI5351_CLK2, 1);
|
|
||||||
// printLine1("check freq ");
|
|
||||||
// si5351.set_freq(1000000000l, SI5351_CLK2);
|
|
||||||
|
|
||||||
// delay(20000);
|
|
||||||
|
|
||||||
si5351.set_freq(lsbCarrier * 100ULL, SI5351_CLK0);
|
|
||||||
si5351.set_freq(SECOND_OSC * 100ULL, SI5351_CLK1);
|
|
||||||
si5351.set_freq(5900000000l, SI5351_CLK2);
|
|
||||||
printLine2(b);
|
|
||||||
delay(2000);
|
|
||||||
|
|
||||||
// Set CLK0 to output 7 MHz with a fixed PLL frequency
|
|
||||||
|
|
||||||
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
|
|
||||||
si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA);
|
|
||||||
si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);
|
|
||||||
|
|
||||||
|
|
||||||
Serial.println("*Si5350 ON");
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
|
|
||||||
//generateCW(10000);
|
|
||||||
//the order of testing first for cw and then for ptt is important.
|
|
||||||
checkCW3();
|
|
||||||
checkTX();
|
|
||||||
checkButton();
|
|
||||||
//tune only when not tranmsitting
|
|
||||||
if (!inTx)
|
|
||||||
doTuning();
|
|
||||||
updateMeter();
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user