Add files via upload
This commit is contained in:
parent
b83b0d24dc
commit
37aaaf4e89
899
control_lcd_45mhz_if_v4.ino
Normal file
899
control_lcd_45mhz_if_v4.ino
Normal file
@ -0,0 +1,899 @@
|
||||
/**
|
||||
* 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