Added bands, band switch, mode switch

Added band switching functionality with memory, ARRL bandplan baked in,
mode switching for test, basic, polyakov, and BFO modes. BFO code not
implemented yet.
This commit is contained in:
JeffersGlass 2015-10-28 01:14:58 -05:00
parent 1356c88589
commit db663140a4

View File

@ -5,23 +5,94 @@
//-----------Variables & Declarations--------------- //-----------Variables & Declarations---------------
/*
* The current and desired LISTENING FREQUENCY, which is not always the frequency being output by the Si5351.
* In 'testing' and 'basic' modes, the output freqeuncy is equal to currFreq
* In 'polyakov' mode, the output frequency is half of curFreq
* In BFO mode, .........
* These adjustments are mode in the setFrequency_5351 function depending on the current mode held in currMode
*/
long currFreq = 1000000; long currFreq = 1800000;
//long steps[] = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000}; //-----Enumerations of frequency steps and their labels for each mode----//
//const int MAX_STEP_INDEX = 15;
//char* stepNames[] = {" 1 hz", " 2 hz", " 5 hz", " 10 hz", " 20 hz", " 50 hz", "100 hz", "200 hz", "500 hz", " 1 Khz", " 2 Khz", " 5 Khz", "10 Khz", "20 Khz", "50 Khz", "100Khz"};
long steps[] = {1, 10, 100, 1000, 10000, 100000, 500000, 1000000, 5000000, 10000000}; enum modes{mode_testing = 0, mode_basic, mode_polyakov, mode_bfo};
const int MAX_STEP_INDEX = 9; const int NUM_MODES = 4;
char* stepNames[] = {" 1 hz", " 10 hz", "100 hz", " 1Khz", " 10KHZ", "100Khz", "500Khz", " 1Mhz", " 5Mhz", " 10Mhz"}; int currMode = mode_basic;
int stepIndex = 0; char* modeNames[NUM_MODES] = {"TEST", "VFO", "POLYA", "BFO"};
long lastButtonPress[] = {0,0,0,0,0}; long steps[][10] = { //don't forget to update the MAX_STEPS_INDEX array below
boolean buttonActive[] = {false, false, false, false, false}; {10000000, 5000000, 1000000, 500000, 100000, 10000, 1000, 10, 1}, //testing
{10000, 1000, 100, 10, 1}, //basic
{1000, 100, 10, 1}, //polyakov
{1000, 100, 10, 1}, //bfo
};
const int NUM_STEP_OPTIONS[NUM_MODES] = {
10, //testing
5, //basic
4, //polyakov
4, //bfo
};
char* stepNames[][10] = {
{" 10MHz", " 5MHz", " 1MHz", "500Khz", "100KHz", " 10KHz", " 1KHz", " 100Hz", " 10Hz", " 1 Hz"}, //basic
{" 10KHz", " 1KHz", " 100 Hz", " 10 Hz", " 1 Hz"}, //basic
{" 1KHz", " 100 Hz", " 10 Hz", " 1 Hz"}, //polyakov
{" 1KHz", " 100 Hz", " 10 Hz", " 1 Hz"} //BFO
};
int stepIndex = 0; // holds the index of the currently selected step value
//-----AMATEUR BAND DEFININTIONS----------------//
//See function "getCurrentBand" below as well
const int NUM_BANDS = 9;
char* bandNames[NUM_BANDS] = {"160m", "80m", "40m", "30m", "20m", "17m", "15m", "12m", "10m"};
char* OUT_OF_BAND_LABEL = "OOB";
long bandEdges[NUM_BANDS][2] = {
{1800000, 2000000}, //160m
{3500000, 4000000}, //80m
{7000000, 7300000}, //40m
{10100000, 10150000}, //30m
{14000000, 14350000}, //20m
{18068000, 18168000}, //17m
{21000000, 21450000}, //15m
{24890000, 24990000}, //12m
{28000000, 29700000} //10m
};
/*
* Holds the last-seen frequency within each band. The list below is also the default location at bootup.
* This array is updated when the BAND button is used to change between bands.
* If the used has scrolled outside of a defined band and then presses the BAND button, they will
* still be advanced to the next band, but the band-return location will not be updated
*/
long lastBandFreq[NUM_BANDS] = {
1800000, //160m
3500000, //80m
7000000, //40m
10100000, //30m
14000000, //20m
18068000, //17m
21000000, //15m
24890000, //12m
28000000 //10m
};
/*Information on bandplan permissions and recommended communication modes is contained in the
* methods getPermission and getBandplanModes below
*/
//---------------------------------------------
long lastButtonPress[] = {0,0,0,0,0,0,0}; //holds the last timestamp, from millis(), that a pin changed state. Directly references the arduino output pin numbers, length may need to be increased
boolean buttonActive[] = {false, false, false, false, false, false, false};
long encoderPosition = 0; long encoderPosition = 0;
boolean displayNeedsUpdate;
const long MIN_FREQ = 8500; const long MIN_FREQ = 8500;
const long MAX_FREQ = 150000000; const long MAX_FREQ = 150000000;
@ -48,9 +119,8 @@ Encoder encoder(2, 3);
const int PIN_BUTTON_ENCODER = 1; const int PIN_BUTTON_ENCODER = 1;
//Button Pins// //Button Pins//
const int PIN_BUTTON_UP = 4; const int PIN_BUTTON_MODE = 4;
const int PIN_BUTTON_DOWN = 5; const int PIN_BUTTON_BAND = 0;
const int PIN_BUTTON_STEP = 6;
const int BUTTON_DEBOUNCE_TIME = 10; //milliseconds const int BUTTON_DEBOUNCE_TIME = 10; //milliseconds
void setup(){ void setup(){
@ -62,45 +132,81 @@ void setup(){
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0);
si5351.set_freq(currFreq * 100ULL, 0ULL, SI5351_CLK0); si5351.set_freq(currFreq * 100ULL, 0ULL, SI5351_CLK0);
si5351.output_enable(SI5351_CLK0, 1);
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
si5351.output_enable(SI5351_CLK1, 0);
si5351.output_enable(SI5351_CLK2, 0);
delay(750); delay(750);
//knob.write(0); //knob.write(0);
pinMode(PIN_BUTTON_UP, INPUT); pinMode(PIN_BUTTON_ENCODER, INPUT);
digitalWrite(PIN_BUTTON_UP, HIGH); digitalWrite(PIN_BUTTON_ENCODER, HIGH);
pinMode(PIN_BUTTON_DOWN, INPUT);
digitalWrite(PIN_BUTTON_DOWN, HIGH); pinMode(PIN_BUTTON_MODE, INPUT);
pinMode(PIN_BUTTON_STEP, INPUT); digitalWrite(PIN_BUTTON_MODE, HIGH);
digitalWrite(PIN_BUTTON_STEP, HIGH); pinMode(PIN_BUTTON_BAND, INPUT);
digitalWrite(PIN_BUTTON_BAND, HIGH);
lcd.clear(); lcd.clear();
lcd.setCursor(2, 7); lcd.setCursor(2, 7);
lcd.print("WELCOME!"); lcd.print("WELCOME!");
delay(500); delay(500);
displayInfo();
} }
void loop(){ void loop(){
displayInfo(); if (displayNeedsUpdate) {displayInfo();}
delay(200); delay(80);
//detect whether encoder has changed position //detect whether encoder has changed position
long reading = encoder.read(); long reading = encoder.read();
long encoderChange = reading - encoderPosition; long encoderChange = reading - encoderPosition;
encoderPosition = reading; encoderPosition = reading;
displayNeedsUpdate = false;
//step up or down or change step size, for either button presses or encoder turns //step up or down or change step size, for either button presses or encoder turns
if (checkButtonPress(PIN_BUTTON_UP) || (encoderChange > 0)){currFreq += steps[stepIndex]; currFreq = min(currFreq, MAX_FREQ); si5351.set_freq(currFreq * 100ULL, 0ULL, SI5351_CLK0);} if ((encoderChange > 0)){currFreq += steps[currMode][stepIndex]; currFreq = min(currFreq, MAX_FREQ); setFrequency_5351(currFreq); displayNeedsUpdate = true;}
if (checkButtonPress(PIN_BUTTON_DOWN) || (encoderChange < 0)){currFreq -= steps[stepIndex]; currFreq = max(currFreq, MIN_FREQ); si5351.set_freq(currFreq * 100ULL, 0ULL, SI5351_CLK0);} if ((encoderChange < 0)){currFreq -= steps[currMode][stepIndex]; currFreq = max(currFreq, MIN_FREQ); setFrequency_5351(currFreq); displayNeedsUpdate = true;}
if (checkButtonPress(PIN_BUTTON_STEP) || checkButtonPress(PIN_BUTTON_ENCODER)){stepIndex = (stepIndex + 1) % (MAX_STEP_INDEX+1);}
//pressing the encoder button increments through the possible step sizes for each mode
if (checkButtonPress(PIN_BUTTON_ENCODER)){stepIndex = (stepIndex + 1) % (NUM_STEP_OPTIONS[currMode]); displayNeedsUpdate = true;}
//pressing the mode button cycles through the available modes
if (checkButtonPress(PIN_BUTTON_MODE)){currMode = (currMode+1) % NUM_MODES; stepIndex = 0; setFrequency_5351(currFreq); displayNeedsUpdate = true;}
/*The mode button: if currFreq is inside an amateur band, save that frequency as the one to return to when
* the user returns to this band, and jump to the return frequency for the next higher band. Otherwise,
* just jump to the next higher band
*/
if (checkButtonPress(PIN_BUTTON_BAND)){
int currBand = getCurrentBand();
if (currBand >= 0){
lastBandFreq[currBand] = currFreq;
currFreq = lastBandFreq[(getCurrentBand() + 1) % NUM_BANDS];
setFrequency_5351(currFreq);
}
else if (currBand == -2 || currBand == -3){
currFreq = lastBandFreq[0];
setFrequency_5351(currFreq);
}
else if (currBand == -1){
for (int i = 0; i < NUM_BANDS; i++){
if (currFreq < lastBandFreq[i]){currFreq = lastBandFreq[i]; setFrequency_5351(currFreq);}
}
}
displayNeedsUpdate = true;
}
} }
void displayInfo(){ void displayInfo(){
lcd.clear(); lcd.clear();
// frequency information should take up the first 11 spaces on the first line: // frequency information be centeredw within 11 spaces on the second line:
if (currFreq >= 100000000) lcd.setCursor(4, 1); if (currFreq >= 100000000) lcd.setCursor(3, 0);
else if (currFreq > 10000000) lcd.setCursor(5, 1); else if (currFreq > 10000000) lcd.setCursor(4, 0);
else lcd.setCursor(6, 1); else lcd.setCursor(5, 0);
int mhz = int(currFreq/ 1000000); int mhz = int(currFreq/ 1000000);
int khz = int((currFreq - (mhz*1000000)) / 1000); int khz = int((currFreq - (mhz*1000000)) / 1000);
int hz = int(currFreq % 1000); int hz = int(currFreq % 1000);
@ -120,12 +226,41 @@ void displayInfo(){
lcd.print("."); lcd.print(".");
for (int i = 0; i < hzPad; i++) lcd.print("0"); for (int i = 0; i < hzPad; i++) lcd.print("0");
lcd.print(hz); lcd.print(hz);
//The current amateur band is printed in the top-right corner
int currBand = getCurrentBand();
if (currBand >= 0){
char* currBandName = bandNames[currBand];
lcd.setCursor(20-strlen(currBandName), 0);
lcd.print(currBandName);
}
else{
lcd.setCursor(20-strlen(OUT_OF_BAND_LABEL), 0);
lcd.print(OUT_OF_BAND_LABEL);
}
//The license needed to operate on this frequency (ARRL, USA ONLY) is printed just below the band label
lcd.setCursor (19, 1);
lcd.print(getPermission());
//Step Information should take the first 11 spaces on the 2nd line //Step Information should take the middle 11 spaces on the 3nd line
//The first 5 symbols are "STEP:", leaving 6 chars for step info. //The first 5 symbols are "STEP:", leaving 6 chars for step info.
lcd.setCursor(4, 3); lcd.setCursor(4, 2);
lcd.print("STEP:"); lcd.print("STEP:");
lcd.print(stepNames[stepIndex]); lcd.print(stepNames[currMode][stepIndex]);
//Callsign is printed at the beginning of the 4th line
lcd.setCursor(0, 3);
lcd.print("KK9JEF");
//The mode is printed on the 4th line with no label
//lcd.setCursor(6, 3);
lcd.setCursor(20-strlen(modeNames[currMode]), 3);
lcd.print(modeNames[currMode]);
//DEBUG
lcd.setCursor(0,0);
lcd.print(getCurrentBand());
} }
boolean checkButtonPress(int pin){ boolean checkButtonPress(int pin){
@ -141,3 +276,79 @@ boolean checkButtonPress(int pin){
} }
return false; return false;
} }
void setFrequency_5351(long newFreq){
switch (currMode){
case mode_testing:
si5351.set_freq(newFreq * 100ULL, 0ULL, SI5351_CLK0);
break;
case mode_basic:
si5351.set_freq(newFreq * 100ULL, 0ULL, SI5351_CLK0);
break;
case mode_polyakov:
si5351.set_freq((newFreq / 2) * 100ULL, 0ULL, SI5351_CLK0);
break;
case mode_bfo:
si5351.set_freq(newFreq * 100ULL, 0ULL, SI5351_CLK0);
break;
}
}
//Returns the index of the current amateur radio band based on currFreq. Does not include the 60m band
//Returns -1 if out of band, but within the HF amateur turning range
//returns -2 if out of band and lower than the lowest defined band
//returns -3 if out of band and higher than the highest defined band
int getCurrentBand(){
if (currFreq < bandEdges[0][0]) return -2; //we are lower than the lower edge of the lowest defined band
if (currFreq > bandEdges[NUM_BANDS-1][1]) return -3; //We are higher than the upper edge of the highest defined band
for (int i = 0; i < NUM_BANDS; i++){
if (currFreq >= bandEdges[i][0] && currFreq <= bandEdges[i][1]){return i;} //We are within a band
}
return -1;
}
char getPermission(){
if (getCurrentBand() < 0) return ' ';
//160m
if (currFreq >= 1800000 && currFreq <= 2000000) return 'G';
//80m
if (currFreq >= 3525000 && currFreq <= 3600000) return 'T';
if ((currFreq >= 3525000 && currFreq <= 3600000) || (currFreq >= 3800000 && currFreq <= 4000000)) return 'G';
if ((currFreq >= 3525000 && currFreq <= 3600000) || (currFreq >= 3700000 && currFreq <= 4000000)) return 'A';
if (currFreq >= 3500000 && currFreq <= 4000000) return 'E';
//40m
if (currFreq >= 7025000 && currFreq <= 7125000) return 'T';
if ((currFreq >= 7025000 && currFreq <= 7125000) || (currFreq >= 7175000 && currFreq <= 7300000)) return 'G';
if (currFreq >= 7025000 && currFreq <= 7300000) return 'A';
if (currFreq >= 7000000 && currFreq <= 7300000) return 'E';
//30m
if (currFreq >= 10100000 && currFreq <= 10150000) return 'G';
//20m
if ((currFreq >= 14025000 && currFreq <= 14150000) || (currFreq >= 14225000 && currFreq <= 14350000)) return 'G';
if ((currFreq >= 14025000 && currFreq <= 14150000) || (currFreq >= 14175000 && currFreq <= 14350000)) return 'A';
if (currFreq >= 14000000 && currFreq <= 14350000) return 'E';
//17m
if (currFreq >= 18068000 && currFreq <= 18168000) return 'G';
//15m
if (currFreq >= 21025000 && currFreq <= 21200000) return 'T';
if ((currFreq >= 21025000 && currFreq <= 21200000) || (currFreq >= 21275000 && currFreq <= 21450000)) return 'G';
if ((currFreq >= 21025000 && currFreq <= 21200000) || (currFreq >= 21225000 && currFreq <= 21450000)) return 'A';
if (currFreq >= 21000000 && currFreq <= 21450000) return 'E';
//12m
if (currFreq >= 24890000 && currFreq <= 24990000) return 'G';
//10m
if (currFreq >= 28000000 && currFreq <= 28500000) return 'T';
if (currFreq >= 28000000 && currFreq <= 29700000) return 'G';
return 'X';
}