#include #include // Note that Ashhar had his encoder on ANALOG pins // #define ENC_A (A2) // #define ENC_B (A1) // I have the direct conversion receiver using DIGITAL pins // In Arduino IDE, the digital pins are simply numbers (e.g. 2 = digital pin 2), // while the analog pins must have a preceding A #define ENC_A 2 #define ENC_B 3 //#define SERIALPRINT // uncomment to get serial monitor output at 9600 #define BB0(x) ((uint8_t)x) // Bust int32 into Bytes #define BB1(x) ((uint8_t)(x>>8)) #define BB2(x) ((uint8_t)(x>>16)) #define SI5351BX_ADDR 0x60 // I2C address of Si5351 (typical) #define SI5351BX_XTALPF 2 // 1:6pf 2:8pf 3:10pf // If using 27mhz crystal, set XTAL=27000000, MSA=33. Then vco=891mhz // #define SI5351BX_XTAL 25000000 // Crystal freq in Hz STOCK #define SI5351BX_XTAL 24999333 // GLG unit measured correction #define SI5351BX_MSA 35 // VCOA is at 25mhz*35 = 875mhz unsigned long frequency; unsigned long usbCarrier; unsigned long frequencystep; // User program may have reason to poke new values into these 3 RAM variables uint32_t si5351bx_vcoa = (SI5351BX_XTAL*SI5351BX_MSA); // 25mhzXtal calibrate uint8_t si5351bx_rdiv = 0; // 0-7, CLK pin sees fout/(2**rdiv) uint8_t si5351bx_drive[3] = {1, 1, 1}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2 uint8_t si5351bx_clken = 0xFF; // Private, all CLK output drivers off int32_t calibration = 0; #include LiquidCrystal lcd(8,9,10,11,12,13); // You can read about LiquidCrystal here: https://www.arduino.cc/en/Reference/LiquidCrystalConstructor // and here: https://www.arduino.cc/en/Reference/LiquidCrystal // It explains how the code to connect to and write to the liquid cyrstal display has already been written for you. char printBuff[2][31]; //mirrors what is showing on the two lines of the display void setup() { // put your setup code here, to run once: pinMode(7,INPUT_PULLUP); pinMode(ENC_A, INPUT_PULLUP); // set the encoder pinA as INPUT, pulled up pinMode(ENC_B, INPUT_PULLUP); // set the encoder pin B as INPUT, pulled up Serial.begin(9600); // This just sets up our serial port monitoring in case we want to print something Serial.flush(); lcd.begin(16, 2); // This initializes the lcd display // Read about it here: https://www.arduino.cc/en/Reference/LiquidCrystalBegin frequency = 7000000UL; // 7 MHz frequencystep=100UL; // Initial frequency step in Herz usbCarrier = frequency; si5351bx_init(); // initialize the si5351; } void loop() { unsigned long kHzfrequency; int littlefrequency; unsigned long localfrequency; unsigned long remainder; char buff0[20], buff2[16], buff3[10]; // buff0 is for top line frequency step // put your main code here, to run repeatedly: // A3 is connected to the outbound switch // D7 is connected to the inboard switch // Read outboard switch to increment frequency step upward strcpy(buff0,"Step: "); analogRead(A3); //returns an int A3 must be valued somewhere? if(analogRead(A3)<200) { frequencystep = frequencystep * 10; // order of magnitude frequency step delay(200); // functions as a debounce } // set a maximum if(frequencystep > 1000000) frequencystep = 1000000; // max 1 MHz steps // Read inboard switch to decrement frequency step downward if(digitalRead(7)==LOW) { frequencystep = frequencystep /10 ; // order less magnitude the frequency step delay(200); // functions as a debounce } // set a minimum if(frequencystep < 10) frequencystep = 10; // minimum 10 Hz ltoa((long)frequencystep,buff3,10); strcat(buff0,buff3); printLine(0,buff0); //printLine(0,"Testing line 0"); localfrequency = frequency; kHzfrequency = frequency/1000; remainder = frequency - (kHzfrequency* 1000UL); ltoa(kHzfrequency,buff2,10); strcat(buff2,"."); ltoa(remainder,buff3,10); strcat(buff2,buff3); //littlefrequency = (int) ( localfrequency / 1000); //localfrequency = frequency; //remainder = (unsigned long) (localfrequency - (( unsigned long) littlefrequency) * 1000UL); //itoa(littlefrequency,buff2,10); //itoa((int) remainder,buff3,10); //strcat(buff2,"."); //strcat(buff2,buff3); printLine(1,buff2); // print out the frequency //printLine(1,"Testing line 1"); //Serial.print("Inputs observed: "); // Serial.print("\n"); doTuning(); si5351bx_setfreq(0, (uint32_t)frequency); localfrequency = frequency; #ifdef SERIALPRINT Serial.print("Frequency = "); Serial.println(localfrequency); #endif // enc_read(); // delay(1000); // printLine(1,frequency); // it died right there!!! Should have passed a STRING //if(digitalRead(7)==LOW)printLine(1,"Button Pushed"); //else printLine(1,"Not Pushed"); #ifdef SERIALPRINT Serial.print(analogRead(A3)); Serial.print("\n"); #endif } // The generic routine to display one line on the LCD void printLine(char linenmbr, char *c) { if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change lcd.setCursor(0, linenmbr); // place the cursor at the beginning of the selected line lcd.print(c); strcpy(printBuff[linenmbr], c); for (byte i = strlen(c); i < 16; i++) { // add white spaces until the end of the 16 characters line is reached lcd.print(' '); } } } // --------------- my version of do_tuning() void doTuning(){ int s; unsigned long prev_freq; unsigned long localfrequency; s = enc_read(); #ifdef SERIALPRINT Serial.print("Encoder returns: "); Serial.println(s); Serial.print("Frequency: "); Serial.print(frequency); #endif if (s != 0){ prev_freq = frequency; // Merely detect direction if (s>0) frequency = frequency + frequencystep; if (s<0) frequency = frequency - frequencystep; /* if (s > 4); // frequency += 1000UL; else if (s > 2) frequency += 100UL; else if (s > 0) frequency += 50UL; else if (s > -2) frequency -= 50UL; else if (s > -4) frequency -= 100UL; //else frequency -= 1000; */ Serial.print(" New Freq: "); Serial.println(frequency); /* if (prev_freq < 10000000l && frequency > 10000000l) isUSB = true; if (prev_freq > 10000000l && frequency < 10000000l) isUSB = false; setFrequency(frequency); updateDisplay(); */ } } int enc_prev_state = 3; /** * The A7 And A6 are purely analog lines on the Arduino Nano * These need to be pulled up externally using two 10 K resistors * * There are excellent pages on the Internet about how these encoders work * and how they should be used. We have elected to use the simplest way * to use these encoders without the complexity of interrupts etc to * keep it understandable. * * The enc_state returns a two-bit number such that each bit reflects the current * value of each of the two phases of the encoder * * The enc_read returns the number of net pulses counted over 50 msecs. * If the puluses are -ve, they were anti-clockwise, if they are +ve, the * were in the clockwise directions. Higher the pulses, greater the speed * at which the enccoder was spun */ byte enc_state (void) { // lets test reading the encoder: // Serial.print("\nEncoder A: "); // Serial.print(digitalRead(ENC_A)); // Serial.print(" Encloder B: "); // Serial.print(digitalRead(ENC_B)); // Serial.print(" Total: "); // Serial.println(digitalRead(ENC_A) + 2*(digitalRead(ENC_B))); return (digitalRead(ENC_A)) + 2*(digitalRead(ENC_B)); } int enc_read(void) { int result = 0; byte newState; int enc_speed = 0; long stop_by = millis() + 100; while (millis() < stop_by) { // check if the previous state was stable newState = enc_state(); // Get current state if (newState != enc_prev_state)delay(1); if (enc_state() != newState || newState == enc_prev_state) continue; //these transitions point to the encoder being rotated anti-clockwise if ((enc_prev_state == 0 && newState == 2) || (enc_prev_state == 2 && newState == 3) || (enc_prev_state == 3 && newState == 1) || (enc_prev_state == 1 && newState == 0)) { result--; } //these transitions point o the enccoder being rotated clockwise if ((enc_prev_state == 0 && newState == 1) || (enc_prev_state == 1 && newState == 3) || (enc_prev_state == 3 && newState == 2) || (enc_prev_state == 2 && newState == 0)) { result++; } enc_prev_state = newState; // Record state for next pulse interpretation enc_speed++; active_delay(1); } return(result); } void active_delay(int delay_by){ unsigned long timeStart = millis(); while (millis() - timeStart <= delay_by) { //Background Work // checkCAT(); } } // ************* SI5315 routines - tks Jerry Gaffke, KE7ER *********************** // An minimalist standalone set of Si5351 routines. // VCOA is fixed at 875mhz, VCOB not used. // The output msynth dividers are used to generate 3 independent clocks // with 1hz resolution to any frequency between 4khz and 109mhz. // Usage: // Call si5351bx_init() once at startup with no args; // Call si5351bx_setfreq(clknum, freq) each time one of the // three output CLK pins is to be updated to a new frequency. // A freq of 0 serves to shut down that output clock. // The global variable si5351bx_vcoa starts out equal to the nominal VCOA // frequency of 25mhz*35 = 875000000 Hz. To correct for 25mhz crystal errors, // the user can adjust this value. The vco frequency will not change but // the number used for the (a+b/c) output msynth calculations is affected. // Example: We call for a 5mhz signal, but it measures to be 5.001mhz. // So the actual vcoa frequency is 875mhz*5.001/5.000 = 875175000 Hz, // To correct for this error: si5351bx_vcoa=875175000; // Most users will never need to generate clocks below 500khz. // But it is possible to do so by loading a value between 0 and 7 into // the global variable si5351bx_rdiv, be sure to return it to a value of 0 // before setting some other CLK output pin. The affected clock will be // divided down by a power of two defined by 2**si5351_rdiv // A value of zero gives a divide factor of 1, a value of 7 divides by 128. // This lightweight method is a reasonable compromise for a seldom used feature. void i2cWrite(uint8_t reg, uint8_t val) { // write reg via i2c Wire.beginTransmission(SI5351BX_ADDR); // Serial.println("Wire.begin"); Wire.write(reg); // Serial.print(Wire.write(reg)); // Serial.println(" bytes written by Wire.write(reg)"); // Serial.print(Wire.write(val)); Wire.write(val); // Serial.println(" bytes written by Wire.write(val)"); Wire.endTransmission(); // Serial.print(Wire.endTransmission(true)); // Serial.println(" returned by Wire.end"); } void i2cWriten(uint8_t reg, uint8_t *vals, uint8_t vcnt) { // write array Wire.beginTransmission(SI5351BX_ADDR); Wire.write(reg); while (vcnt--) Wire.write(*vals++); Wire.endTransmission(); } void si5351bx_init() { // Call once at power-up, start PLLA uint8_t reg; uint32_t msxp1; Wire.begin(); Serial.println("Wire.begin started "); i2cWrite(149, 0); // SpreadSpectrum off Serial.println("Spread spectrum off"); i2cWrite(3, si5351bx_clken); // Disable all CLK output drivers Serial.println("Disabled all CLK output drivers"); i2cWrite(183, SI5351BX_XTALPF << 6); // Set 25mhz crystal load capacitance Serial.println("Set the crystal load capacitance"); msxp1 = 128 * SI5351BX_MSA - 512; // and msxp2=0, msxp3=1, not fractional uint8_t vals[8] = {0, 1, BB2(msxp1), BB1(msxp1), BB0(msxp1), 0, 0, 0}; i2cWriten(26, vals, 8); // Write to 8 PLLA msynth regs Serial.println("wrote to the 8 PLLA msynth regs"); i2cWrite(177, 0x20); // Reset PLLA (0x80 resets PLLB) Serial.println("Reset PLLA"); // for (reg=16; reg<=23; reg++) i2cWrite(reg, 0x80); // Powerdown CLK's // i2cWrite(187, 0); // No fannout of clkin, xtal, ms0, ms4 } void si5351bx_setfreq(uint8_t clknum, uint32_t fout) { // Set a CLK to fout Hz uint32_t msa, msb, msc, msxp1, msxp2, msxp3p2top; if ((fout < 500000) || (fout > 109000000)) // If clock freq out of range si5351bx_clken |= 1 << clknum; // shut down the clock else { msa = si5351bx_vcoa / fout; // Integer part of vco/fout msb = si5351bx_vcoa % fout; // Fractional part of vco/fout msc = fout; // Divide by 2 till fits in reg while (msc & 0xfff00000) { msb = msb >> 1; msc = msc >> 1; } msxp1 = (128 * msa + 128 * msb / msc - 512) | (((uint32_t)si5351bx_rdiv) << 20); msxp2 = 128 * msb - 128 * msb / msc * msc; // msxp3 == msc; msxp3p2top = (((msc & 0x0F0000) << 4) | msxp2); // 2 top nibbles uint8_t vals[8] = { BB1(msc), BB0(msc), BB2(msxp1), BB1(msxp1), BB0(msxp1), BB2(msxp3p2top), BB1(msxp2), BB0(msxp2) }; i2cWriten(42 + (clknum * 8), vals, 8); // Write to 8 msynth regs i2cWrite(16 + clknum, 0x0C | si5351bx_drive[clknum]); // use local msynth si5351bx_clken &= ~(1 << clknum); // Clear bit to enable clock } i2cWrite(3, si5351bx_clken); // Enable/disable clock } void si5351_set_calibration(int32_t cal){ si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + cal; // apply the calibration correction factor si5351bx_setfreq(0, usbCarrier); } void initOscillators(){ //initialize the SI5351 si5351bx_init(); si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + calibration; // apply the calibration correction factor si5351bx_setfreq(0, usbCarrier); }