MBFrequency_Counter_v_1_3 /************ A Simple Frequency Counter ver 1.2 6 May 2014 D.Kidder W6DQ and J.Purdum, W9NMT. Modified by KG7TR for use in my homebrew 75S-2B receiver. Band and mode switch positions are monitored to offset the raw VFO frequency count by first xtal oscillator frequencies on 40 thru 10 meters, and the BFO frequencies for LSB, USB and AM operation on all bands. No BFO signal is used for AM, so the offset frequency is set to the measured center of the AM filter (453.900 KHz). The radio is single conversion on 80M, so sideband inversion occurs and BFO frequencies must be reversed. This frequency counter is based on the work of: Martin Nawrath KHM LAB3 Kunsthochschule f¸r Medien Kˆln Academy of Media Arts http://www.khm.de http://interface.khm.de/index.php/labor/experimente/ and uses the FreqCounter.h library from the same source. Pulses are counted on Digital Pin 5 during the gate time and then converted into the frequency in Hz, KHz, or MHz, depending on settings in the code used during compile. The counter has a maximum frequency range of a little over 6 MHz without prescaling. As used in this receiver it covers 3.955 to 4.455 MHz. Precision is set to 4 decimal places (100 Hz resolution). An Arduino module using a quartz crystal for the Atmega microcontroller clock is used. Arduino modules using ceramic resonators for the clock drift too much to achieve accurate and stable resolution to 100 Hz or better. * *************/ #include #include #include #define DEFAULTPRECISION 4 // Default decimal places #define VALUEWIDTH 10 // Numeric field width #define LCDNUMCOLS 16 // number of columns on LCD #define LCDNUMROWS 2 // number of rows #define STARTUPDELAY 3000 // Delay used for splash screen at startup #define UPDATEDELAY 100 // Delay for normal reading #define CALIBRATION 0 // Adjusts frequency for variation in Arduino clock rate, // not clear how it works, so not used #define GATETIME 100 // Gate time in milliseconds, affects CALOFFSET value #define MEGAHERTZ 1000000 // Let's define a couple of constants #define MILLISECONDS 1000 // Number of milliseconds in a second //40M thru 10M xtal freqs based on measured values #define XTALOSC80 0.0 // Xtal Oscillator freq for 80m #define XTALOSC40 11.00226 // Xtal Oscillator freq for 40m #define XTALOSC20 18.00407 // Xtal Oscillator freq for 20m #define XTALOSC15 25.00452 // Xtal Oscillator freq for 15m #define XTALOSC10 32.00493 // Xtal Oscillator freq for 10m #define CALOFFSET .000620 // Offset from f_freq count, CALIBRATION method proved too confusing #define BFOAM 0.453900 // IF freq for AM (used for calculation only, BFO is off) #define BFOUSB 0.453647 // BFO freq for USB (LSB for 80M) #define BFOLSB 0.456267 // BFO freq for LSB (USB for 80M) char scale[] = " MHz"; // Scale string for display units float scaleFactor = 1.0; // Scale factor used to adjust units. // Default is 1.0 for Hz, 0.001 for KHz and .000001 for MHz LiquidCrystal lcd(12, 11, 9, 8, 7, 6); // Setup the LCD hardware interface pins //set up variables used to test for band or mode switch changes int preValue10M = HIGH; int preValue15M = HIGH; int preValue20M = HIGH; int preValue40M = HIGH; int preValue80M = HIGH; int preValueBFOUSB = HIGH; int preValueBFOLSB = HIGH; boolean Update = true; //set to true if band or mode switch has been repositioned float XTALOSC = 0.0; //Value to be set in loop below by position of band switch float BFO = .453900; //Value to be set in loop below by position of mode and band switch void setup() { //Assign pins to band and mode functions pinMode(A0, INPUT_PULLUP); //pin A0 also connected to BFO module pin D12 for BFO status pinMode(A1, INPUT_PULLUP); //pin A1 also connected to BFO module pin D11 for BFO status pinMode(0, INPUT_PULLUP); //pin D0 also connected to BFO module pin D2 for 80M status pinMode(1, INPUT_PULLUP); //40M status pinMode(2, INPUT_PULLUP); //20M status pinMode(3, INPUT_PULLUP); //15M status pinMode(4, INPUT_PULLUP); //10M status lcd.begin(LCDNUMCOLS, LCDNUMROWS); // initialize the LCD lcd.print("KG7TR Receiver "); //name, version and date lcd.setCursor(0, 1); lcd.print("Ver 1.3 17Dec17"); delay(STARTUPDELAY); lcd.clear(); } void loop() { //Serial.begin(9600); int Value10M = digitalRead(4); //pin 4 grounded in 10M position int Value15M = digitalRead(3); //pin 3 grounded in 15M position int Value20M = digitalRead(2); //pin 2 grounded in 20M position int Value40M = digitalRead(1); //pin 1 grounded in 40M position int Value80M = digitalRead(0); //pin 0 grounded in 80M position int ValueBFOUSB = digitalRead(A0); //pin A0 grounded in USB position int ValueBFOLSB = digitalRead(A1); //pin A1 grounded in LSB position //Check for changes in band or mode switch positions if (Value10M != preValue10M) { Update = true; preValue10M = Value10M; }; if (Value15M != preValue15M) { Update = true; preValue15M = Value15M; }; if (Value20M != preValue20M) { Update = true; preValue20M = Value20M; }; if (Value40M != preValue40M) { Update = true; preValue40M = Value40M; }; if (Value80M != preValue80M) { Update = true; preValue80M = Value80M; }; if (ValueBFOUSB != preValueBFOUSB) { Update = true; preValueBFOUSB = ValueBFOUSB; }; if (ValueBFOLSB != preValueBFOLSB) { Update = true; preValueBFOLSB = ValueBFOLSB; }; //set XTALOSC offset freqs and LCD band display if (Update == true) if (Value10M == LOW) { XTALOSC = XTALOSC10; lcd.setCursor(2, 1); lcd.print("10M"); }; if (Value15M == LOW) { XTALOSC = XTALOSC15; lcd.setCursor(2, 1); lcd.print("15M"); }; if (Value20M == LOW) { XTALOSC = XTALOSC20; lcd.setCursor(2, 1); lcd.print("20M"); }; if (Value40M == LOW) { XTALOSC = XTALOSC40; lcd.setCursor(2, 1); lcd.print("40M"); }; if (Value80M == LOW) { XTALOSC = XTALOSC80; lcd.setCursor(2, 1); lcd.print("80M"); }; //set BFO offset freqs and LCD mode display for 40M thru 10M if (Update == true && Value80M == HIGH) { if (ValueBFOUSB == LOW) { BFO = BFOUSB; lcd.setCursor(11, 1); lcd.print("USB"); }; if (ValueBFOLSB == LOW) { BFO = BFOLSB; lcd.setCursor(11, 1); lcd.print("LSB"); } if (ValueBFOUSB == HIGH && ValueBFOLSB == HIGH) { BFO = BFOAM; lcd.setCursor(11, 1); lcd.print("AM "); }; }; //On 80M BFO freqs are reversed due to single conversion only if (Update == true && Value80M == LOW) { if (ValueBFOUSB == LOW) { BFO = BFOLSB; lcd.setCursor(11, 1); lcd.print("USB"); }; if (ValueBFOLSB == LOW) { BFO = BFOUSB; lcd.setCursor(11, 1); lcd.print("LSB"); }; if (ValueBFOUSB == HIGH && ValueBFOLSB == HIGH) { BFO = BFOAM; lcd.setCursor(11, 1); lcd.print("AM "); }; }; delay(100); //Serial.println(Update); //delay(1000); char buffer[LCDNUMCOLS + 1]; // Make it big enough for a 2x16 display unsigned long dataIn; float val; int i; FreqCounter::f_comp = CALIBRATION; // Calibrate with known source; not understood, not used FreqCounter::start(GATETIME); // Count pulses for specified gating period while (FreqCounter::f_ready == 0) dataIn = FreqCounter::f_freq;; delay(20); val = (float) dataIn * scaleFactor * ( MILLISECONDS / GATETIME) / MEGAHERTZ ; // Scale the input reading... if (Value80M == LOW) {val = CALOFFSET - BFO + val;} //calc for 80M only, since no xtal osc is used //{val = CALOFFSET + val;} //Routine used to measure and calibrate raw VFO frequency else { val = XTALOSC - CALOFFSET + BFO - val; }; //calc for 40M thru 10M dtostrf(val, VALUEWIDTH, DEFAULTPRECISION, buffer); // Convert and format value strcat(buffer, scale); // Concatenate contents of buffer and the scale units into buffer lcd.setCursor(0, 0); // Set up the display... lcd.print(buffer); Update = false; //set to false after updates are implemented to bypass subsequent trips thru the loop }