/* MODIFIED FOR USE OF THE AD9851DDS MODULE AND ADDED PULLUP COMMAND FOR A3, A4 FOR STEP ENCODER, 5/7/2020 * SOFTWARE VERSION R2 FOR THE WA3TFS SINGLE BAND HF SSB/CW 40 METER RECEIVER WITH 1.8" LCD DISPLAY * OCTOBER 24, 2019 DISPLAY DATA FORMATTED FOR 1.4" LCD DISPLAY * TUNING RANGE 500 KHZ TO 30 MHZ BUT LIMITED BY HARDWARE TO AROUND 40 METERS BY HARDWARE * COMMENTS OR QUESTIONS SHOULD BE SENT TO WA3TFS@ARRL.NET * ADITIONAL INFORMATION ON THIS AND OTHER PROJECTS AVAILABLE ON HTTP://WA3TFS.COM */ #include // Core graphics library https://github.com/adafruit/Adafruit-GFX-Library #include // Hardware-specific library https://github.com/adafruit/Adafruit-ST7735-Library #include #include // Rotary encoder: https://github.com/brianlow/Rotary int TFT_LED = 8; #define TFT_SCLK 13 // 1.4" TFT Display. #define TFT_MOSI 11 // #define TFT_CS 10 #define TFT_RST A1 #define TFT_DC A0 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); #define AD9850_CLOCK 125000000 // Module crystal frequency. Tweak here for accuracy. //#define AD9851_CLOCK 180.0e6 //9851 clock frequency #define W_CLK 8 // AD9850 Module pins. #define FQ_UD 7 #define DATA 6 #define RESET 5 #define stepPin1 A3 // Set 'Step' rotary encoder pins #define stepPin2 A4 int forceHzStep = A2; // 'Step' rotary encoder's push button - Set 100 Hz steps. int forcekHz = 4; // Interrupt-driven encoder's push button - force 1kHz freq. Rotary i = Rotary(stepPin1, stepPin2); // Rotary encoder for setting increment. Rotary r = Rotary(2, 3); // Rotary encoder for frequency connects to interrupt pins long unsigned int freq = 16150000; // Set initial frequency.LO INJECTION WITH 9 MHZ IF FOR 7.150 MHZ long unsigned int freqOld = freq; long unsigned int freqDold; long unsigned int freqD = (freq - 9000000); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% long int timer; char* stepText[11] = {" 1 Hz", " 10 Hz", "100 Hz", " 1 kHz", "10 kHz", "100 kHz", "500 kHz" }; int stepPointer = 2; //Start in 100 Hz steps unsigned long incr = 0; String units = stepText[stepPointer]; #define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); } // transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line void tfr_byte(byte data) { for (int i = 0; i < 8; i++, data >>= 1) { digitalWrite(DATA, data & 0x01); pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high } } void sendFrequency(double frequency) { int32_t freq1 = frequency * 4294967295 / AD9850_CLOCK; // note 125 MHz clock on 9850 and 180 MHz for 9851 for (int b = 0; b < 4; b++, freq1 >>= 8) { tfr_byte(freq1 & 0xFF); } tfr_byte(0x000); // Final control byte, all 0 for 9850 chip & 1 for 9851 pulseHigh(FQ_UD); // Done! Should see output updateDisplay(); // Update the TFT display. } void setup() { pinMode(2, INPUT_PULLUP); //_PULLUP); // Pins for interrupt-driven rotary encoder pinMode(3, INPUT_PULLUP); //_PULLUP); // Pins for interrupt-driven rotary encoder pinMode(4, INPUT_PULLUP); //_PULLUP); // Pins for interrupt-driven rotary encoder push button pinMode(A3, INPUT_PULLUP); //PULLUP FOR STEP ENCODER pinMode(A4, INPUT_PULLUP); //PULLUP FOR STEP ENCODER pinMode(forceHzStep, INPUT_PULLUP); pinMode(forcekHz, INPUT_PULLUP); pinMode(FQ_UD, OUTPUT); // Configure pins for output to AD9850 module. pinMode(W_CLK, OUTPUT); pinMode(DATA, OUTPUT); pinMode(RESET, OUTPUT); pinMode(TFT_RST, OUTPUT); // Configure pins for output to TFT display. pinMode(TFT_DC, OUTPUT); pinMode(TFT_LED, OUTPUT); analogWrite(TFT_LED, 255); // Adjust backlight brightness. // Configure interrupt and enable for rotary encoder. PCICR |= (1 << PCIE2); PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); sei(); tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab tft.setRotation(3); tft.setTextWrap(false); // Allow text to run off right edge tft.fillScreen(ST7735_BLACK); tft.setCursor(15, tft.height() - 20); //18 tft.setTextSize(1); tft.drawFastHLine(0, tft.height() - 25, tft.width() - 10, ST7735_RED);//23 tft.setTextColor(ST7735_YELLOW); tft.println(" WA3TFS HF 40 MTR"); tft.print(" SSB/CW RECEIVER"); // Initialise the AD9850 module. pulseHigh(RESET); pulseHigh(W_CLK); pulseHigh(FQ_UD); // this pulse enables serial mode - Datasheet page 12 figure 10 updateDisplay(); // Update the TFT display. } void getStep() { switch (stepPointer) { case 0: incr = 1; break; case 1: incr = 10; break; case 2: incr = 100; break; case 3: incr = 1000; break; case 4: incr = 10000; break; case 5: incr = 100000; break; //case 6: incr = 500000; break; } } void updateDisplay() { //long unsigned int freqD = freq; //MODIFIED FOR 9 MHZ IF long unsigned int freqD = (freq - 9000000); //MODIFIED FOR 9 MHZ IF getStep(); // units = stepText[stepPointer]; tft.fillRect(0, 15, 160, 20, ST7735_BLACK); //0, 15, 160, 20 tft.setTextColor(ST7735_RED); tft.setCursor(10, 20); tft.setTextSize(1); tft.print(" Step"); tft.setTextSize(2); tft.setCursor(40, 15);//60 tft.print(units); tft.fillRect(0, 40, 160, 60, ST7735_BLACK); tft.setTextColor(ST7735_GREEN); tft.setTextSize(2); if (freq < 500) { tft.setCursor(50, 50);//78, 50 if (freq < 1000) tft.print(" "); if (freq < 100) tft.print (" "); tft.print(freqD); tft.setCursor(58, 75); if (freq < 500) tft.print(" "); if (freq < 100) tft.print(" "); tft.print(freqD); tft.setCursor(58, 75);//58, 75 // tft.print(" Hz"); } else if (freqD < 30000000) { tft.setCursor(15,50);//40, 50 if (freqD < 1000000)tft.print(" "); tft.print((float)freqD / 1000, 3); tft.setCursor(48, 75);//58, 75 tft.print(" kHz"); } else { format(freqD); tft.setCursor(58, 75); //tft.print(" MHz"); } } void format(long value) { int M = (value / 1000000); int T100 = ((value / 100000) % 10); int T10 = ((value / 10000) % 10); int T1 = ((value / 1000) % 10); int U100 = ((value / 100) % 10); int U10 = ((value / 10) % 10); int U1 = ((value / 1) % 10); tft.setCursor(25, 50);//25, 50 tft.print(M); tft.print("."); tft.print(T100); tft.print(T10); tft.print(T1); tft.print(","); tft.print(U100); tft.print(U10); tft.print(U1); freqDold = freqD; } void loop() { // Check 'Step' rotary encoder. //freq = (9000000 + freqD); unsigned char result = i.process(); if (result) { if (result == DIR_CW) { if (stepPointer < 5) stepPointer++; } if (result == DIR_CCW) { if (stepPointer > 0) stepPointer--; } updateDisplay(); } if (digitalRead(forceHzStep) == LOW) { stepPointer = 2; delay(50); updateDisplay(); } if (digitalRead(forcekHz) == LOW) { freq = 16150000; //SET TO 7150000 ON BUTTON PRESS sendFrequency(freq); delay(350); updateDisplay(); } if(freqOld!=freq){ sendFrequency(freq); updateDisplay(); freqOld=freq; } } ISR(PCINT2_vect) { unsigned char result = r.process(); if (result) { if (result == DIR_CW) { if ((freq + incr) <= 39000000) freq += incr; //SET UPPER LIMIT TO 30 MHZ (TUNE 8 MHZ) } else { if ((freq - incr) >= 10500000) freq -= incr; //SET LOWER LIMIT TO .5 MHZ (TUNE 6.5 MHZ } if (freq <= 500) freq = 500; if (freq >= 39000100) freq = 39000000; updateDisplay(); // Update the TFT display. } }