/* based on code developed by Jason NT7S, Premzek, SQ9JNE and Tom AJK2B Keypad code is from Mark Stanley, Pete N6QW and Tom Ak2B This code revision is for the Ten Tec Model 150A Commercial SSB Transceiver to convert it from Crystal Control to VFO control on 6 Bands (160- 20M)using a keypad The Model 150A has separate USB LSB filters so the internal BFO is fixed at 12.7 MHz and we only need one clock on the Si5351. The IF frequency is 12.7 MHz. Keys 8 and 0 enable tuning the radio up and down based on the step rate selected. From network Sciences Daryl Kemper, Trying shifting the BFO to Force the USB to LSB Code added Modified LSB BFO frequency to 12696500 This mod adds actual display for Hz and kHzwhen keys 7 and 9 are depressed --just briefly on start up you see 7200000 Getting better November 2023 this code has been repurposed to operate with the Ten Tec Triton II Key Pad Key Pad / Arduino / wire color 1 / 8 Red 2 / 7 Purple 3 / 10 Black 4 / 6 White 5 / 12 Grey 6 / 9 Magenta 7 / 11 Blue Pins used 2 Encoder 3 Encoder 4 Step Tuning 5 Internal Software 6 Keypad 7 Keypad 8 Keypad 9 Keypad 10 Keypad 11 Keypad 12 Keypad A1 PTT Keyed A2 Internal Software A3 CW Key A4 I2C LCD and Si5351 A5 I2C LCD and Si5351 A6 USE THIS ONE!!!!!!! Code Modified by N6QW 12/2023 */ #include #include "Wire.h"; #include "LiquidCrystal_I2C.h" #include "Rotary.h" #include "Jsi5351.h" #define IF 0L #define F_MIN 1000000L // Lower frequency limit #define F_MAX 150000000L #define ENCODER_B 2 // Encoder pin A #define ENCODER_A 3 // Encoder pin B #define ENCODER_BTN 4 // Special LCD Character byte customChar[] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 }; const int SW4 = 5; //+ RIT Switch const int SW1 = A2; //- RIT Switch const int SW3 = 13; //Keyed PTT char holdKey; unsigned long t_hold; LiquidCrystal_I2C lcd(0x27, 16, 2); Si5351 si5351; Rotary r = Rotary(ENCODER_A, ENCODER_B); volatile uint32_t vfo = 11200000L; // starting on 0000.00 Hz volatile uint32_t RIT = 0L; volatile uint32_t bfo = 9000000L; // or LSB later make it selectable with the SSB Select Switch volatile uint32_t radix = 100; boolean keystate = 0; boolean changed_f = 0; int RunOnce = 1; int old_vfo = 0; int key = 0; int old_f= 0; int CW = A3; int val = 0; // used for dip /**************************************/ /* Interrupt service routine for */ /* encoder frequency change */ /**************************************/ ISR(PCINT2_vect) { unsigned char result = r.process(); if (result == DIR_CW) set_frequency(1); else if (result == DIR_CCW) set_frequency(-1); } /**************************************/ /* Change the frequency */ /* dir = 1 Increment */ /* dir = -1 Decrement */ /**************************************/ void set_frequency(short dir) { // Added as protection against re-entering this function before it has a // chance to complete a previous call. This will become important when you // set a fast repeat value for the keypad keys. static boolean changing_frequency = false; // Initialized to false when you click on 'verify'. if (!changing_frequency) // if I am not changing then you can come in. { changing_frequency = true; // Now I am changing frequency. if (dir == 1) vfo += radix; if (dir == -1) vfo -= radix; if (vfo > F_MAX) vfo = F_MAX; if (vfo < F_MIN) vfo = F_MIN; changed_f = 1; changing_frequency = false; // All done changing freuqency. } } /**************************************/ /* Read the button with debouncing */ /**************************************/ boolean get_button() { if (!digitalRead(ENCODER_BTN)) { delay(50); if (!digitalRead(ENCODER_BTN)) { while (!digitalRead(ENCODER_BTN)); return 1; } } return 0; } /**************************************/ /* Displays the frequency */ /**************************************/ void display_frequency() { uint16_t f, g; lcd.setCursor(3, 0); f = (vfo - bfo + RIT) / 1000000; if (f < 10) lcd.print(' '); lcd.print(f); lcd.print('.'); f = ((vfo - bfo + RIT) % 1000000) / 1000; if (f < 100) lcd.print('0'); if (f < 10) lcd.print('0'); lcd.print(f); lcd.print('.'); f = (vfo - bfo + RIT) % 1000; if (f < 100) lcd.print('0'); if (f < 10) lcd.print('0'); lcd.print(f); lcd.print("Hz"); } /**************************************/ /* Displays the frequency change step */ /**************************************/ void display_radix() { lcd.clear(); lcd.setCursor(10, 1); switch (radix) { case 10: lcd.print(" 10"); break; case 100: lcd.print(" 100"); break; case 1000: lcd.print(" 1k"); break; case 10000: lcd.print(" 10k"); break; case 100000: lcd.print("100k"); break; } lcd.print("Hz"); lcd.display(); } //***********KeyPad************* const byte ROWS = 4; // Four rows const byte COLS = 3; // Three columns // Define the Keymap char keys[ROWS][COLS] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'} }; // Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins. byte rowPins[ROWS] = { 9, 8, 7, 6 }; // Connect keypad COL0, COL1 and COL2 to these Arduino pins. byte colPins[COLS] = { 12, 11, 10 }; // Create the Keypad Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); void setup() { //lcd.init(); delay(25); lcd.begin(); lcd.createChar(0, customChar); lcd.home(); lcd.write(0); Wire.begin(); lcd.backlight(); Serial.begin(9600); pinMode(A3, INPUT); digitalWrite(A3, HIGH); pinMode(A2, INPUT); digitalWrite(A2, HIGH); pinMode(5, INPUT); digitalWrite(5,HIGH); pinMode(A1, OUTPUT);; digitalWrite(A1,LOW); vfo = 0LL; bfo = 0L; RIT = 0L; display_frequency(); lcd.setCursor(2, 1); lcd.print(" "); lcd.setCursor(0, 1); val = 0; Serial.begin(9600); // Start serial and initialize the Si5351 si5351.init(SI5351_CRYSTAL_LOAD_8PF); si5351.set_correction(100); delay(1000); //lcd.clear(); // init done // Set CLK0 to output vfo frequency with a fixed PLL frequency si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); //lcd.clear(); Wire.begin(); pinMode(ENCODER_BTN, INPUT_PULLUP); PCICR |= (1 << PCIE2); // Enable pin change interrupt for the encoder PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); sei(); display_frequency(); // Update the display display_radix(); lcd.setCursor(0, 0); lcd.print("Exciting Stuff"); } void loop() { SplashScreen(); CheckCW(); // CheckSplit(); lcd.setCursor(0, 1); lcd.print(val); lcd.setCursor(2, 1); lcd.print("M"); if (changed_f) { changed_f = 0; display_frequency(); // most critical piece to show frequency si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); // lcd.setCursor(4,1); //For showing the LO Frequency Noit used with RIT //Left in to show how to do something // lcd.print (abs(vfo/1000));//For showing the LO Frequency Noit used with RIT } changed_f = 0; /* if (digitalRead(SW)) { //********If SW is true do the following. bfo = 12700000L; RIT = 3500L; lcd.setCursor(6,1); lcd.print("USB"); si5351.set_freq( bfo, 0, SI5351_CLK2); } else { //**********if not, do this. bfo = 12696500L; RIT = 0L; lcd.setCursor(6,1); lcd.print("LSB"); si5351.set_freq( bfo, 0, SI5351_CLK2); } */ //Serial.print(vfo); //Serial.print(" "); //Serial.print(bfo); // Serial.print(" "); // Serial.print(vfo - bfo + RIT); // Serial.print(" "); if (get_button()) { switch (radix) { case 10: radix = 100; break; case 100: radix = 1000; break; case 1000: radix = 10000; break; case 10000: radix = 100000; break; // case 100000: // radix = 10; // break; radix = 100; // added to make it cycle back to 100 Hz break; } display_radix(); } char key = kpd.getKey(); if (key) // Check for a valid key. holdKey = key; { switch (key) { case '1'://80 vfo = 12798000L; bfo = 8998000L; RIT = 0; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); display_frequency(); lcd.setCursor(2, 1); lcd.print(" "); lcd.setCursor(0, 1); val = 80; delay(50); break; case '2'://40M vfo = 16208000L; bfo = 8998000L; RIT = 0; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); display_frequency(); lcd.setCursor(2, 1); lcd.print(" "); lcd.setCursor(0, 1); val = 40; delay(50); break; case '3'://20 vfo = 5199500L; bfo = -9000500L; RIT = 0; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); display_frequency(); lcd.setCursor(2, 1); lcd.print(" "); lcd.setCursor(0, 1); val = 20; delay(50); break; case '4': // 15 vfo = 12249500L; bfo = -9000500L; RIT = 0; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); display_frequency(); lcd.setCursor(2, 1); lcd.print(" "); lcd.setCursor(0, 1); val = 15; delay(50); break; case '5'://10M vfo = 19299500L; bfo = -9000500L; RIT = 0; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); display_frequency(); lcd.setCursor(2, 1); lcd.print(" "); lcd.setCursor(0, 1); val = 10; delay(50); break; case '6'://20 radix = 100; lcd.setCursor(10, 1); lcd.print(" 100"); break; case '7': radix = 1000; lcd.setCursor(10, 1); lcd.print(" "); lcd.setCursor(10, 1); lcd.print(" 1k"); break; case '9': //resets from CW and RIT RIT=0L; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); lcd.setCursor(4,1); lcd.print(" "); break; case'*': //This case to give split operation up 10 KHz digitalWrite(A1, HIGH); lcd.setCursor(4,1); lcd.print("Tx=+10"); lcd.setCursor(15,0); lcd.write(0); //Special Character to show transmit lcd.setCursor(0,0); lcd.print("Tx"); RIT = 10000L; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); display_frequency(); delay(10); break; case '#': // This is for CW display_radix(); digitalWrite(A1, HIGH); lcd.setCursor(4,1); lcd.print("Tx=-10"); lcd.setCursor(15,0); lcd.write(0); //Special Character to show transmit lcd.setCursor(0,0); lcd.print("Tx"); RIT = -10000L; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); display_frequency(); delay(10); break; /* if (digitalRead(A2)) { //********If SW1 is true do the following. RIT = 0; si5351.set_freq(vfo , SI5351_PLL_FIXED, SI5351_CLK0); // Internally in the Triton I the CW signal is shifted 750Hz lcd.setCursor(4,1); lcd.print("Tx=CW"); display_frequency(); } else { //**********if not, do this. RIT = 0; si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0); lcd.setCursor(15,0); // Blanking for the special Character lcd.print(" "); } break; */ } } if (kpd.getState() == HOLD) { if ((millis() - t_hold) > 100 ) { switch (holdKey) { case '8'://UP ARROW set_frequency(1); delay (200); break; case '0'://DOWN ARROW set_frequency(-1); delay (200); break; } t_hold = millis(); } } } // ******Splash Screen *********************** void SplashScreen() { if (RunOnce == 1) { lcd.setCursor(0, 0); lcd.print(" N6QW SSB XCVR "); lcd.setCursor(0, 1); lcd.print("Triton II Rocks! "); delay(2000); RunOnce = 0; lcd.clear(); display_radix(); } } //*******************Check CW************** void CheckCW(){ digitalWrite(A3, HIGH); if (digitalRead(A3)) { //********If SW is true do the following. lcd.setCursor(0, 0); lcd.print("Rx"); lcd.setCursor(15,0); lcd.print(" "); display_frequency(); } else { //**********if not, do this. si5351.set_freq(vfo , SI5351_PLL_FIXED, SI5351_CLK0); lcd.setCursor(15,0); lcd.write(0); //Special Character to show transmit lcd.setCursor(0,0); lcd.print("Tx"); delay(10); si5351.set_freq(vfo + RIT , SI5351_PLL_FIXED, SI5351_CLK0);// this puts frequency back to before display_frequency(); /* kpd.getKey();{ if((key) = '*'){ lcd.setCursor(8,1); //Left in to show how to do something lcd.print("+"); return; } if((key) = '#');{ lcd.setCursor(8,1); lcd.print("-"); } } */ return; } } //******************Check Split********* /* void CheckSplit(){ if(digitalRead(5) and digitalRead(A3)){ lcd.setCursor(15,0); lcd.write(0); //Special Character to show transmit delay(155); lcd.setCursor(0,0); lcd.print("Tx"); delay(500); } } */