Try to learn something about everything, and everything about somethingThomas Huxley “Darwin's bulldog” (1824-1895)

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
public:radio:topics:arduino:60m_transceiver [11/07/26 10:13 BST] – [60m Transceiver] johnpublic:radio:topics:arduino:60m_transceiver [11/07/26 10:44 BST] (current) – [Further Information] john
Line 3: Line 3:
  
 ====== 60m Transceiver ====== ====== 60m Transceiver ======
 +
 +
 +The 60m transceiver has the following features, which vary according to the loaded firmware
 +
 +  * Channelized operation
 +  * LCD display
 +    * Frequency
 +    * Mode (SSB / CW)
 +    * Modulation Source (Mic/Key/Data)
 +    * RX / TX status
 +  * 9MHz IF with Xtal filter
 +  * SSB & CW set via mode switch
 +  * Approx 3W PEP
 +  * Digital mode input/output and PTT via 9-pin D
 +  * SSB Mic input via 8-pin round "Icom" connector
 +  * Modulation Source (Mic or Data) can chosen via select switch
 +  * Scan start switch - scan a preset group of channels - cycles continuously, no "squelch"
 +    * Use of Jenal SC2 CCIR493 Selcal microphone can be supported - including scanning
 +
 +===== Arduino Versions =====
 +
 +There are several different firmware versions....this is just a sample...
 +
 +==== RX Only, with SSB, CW & scan ====
  
 {{ :public:radio:topics:arduino:gm4slv_60m_channels_cwscan_noptt_new_calibration_130523.ino |}} {{ :public:radio:topics:arduino:gm4slv_60m_channels_cwscan_noptt_new_calibration_130523.ino |}}
  
-<code>+++++ Firmware (Click to view) | 
 +  
 +<code c> 
 + 
 +#include <rgb_lcd.h> 
 +#include <si5351.h> 
 + 
 +char version[] = "v0.1"; 
 + 
 +const long channel_array[] =  
 +
 +5258500,5260000,5261000,5262000,5263000, 5276000, 
 +5278500,5279000,5287200,5290000,5298000, 
 +5301000,5304000,5317000,5320000,5333000, 
 +5334000,5335000,5354000,5355000,5362000, 
 +5363000,5364700,5366500,5371500,5378000, 
 +5379000,5395000,5398500,5403500, 
 +5345000,5245000,5450000,5505000,5680000, 
 +5195000,5616000,5649000 
 +} ; 
 + 
 +const long scan_array[] =  
 +
 + 5260000,5261000, 
 + 5262000,5263000, 
 + 5366500,5354000, 
 + 5355000, 
 +} ; 
 + 
 + 
 +const int mems = sizeof(channel_array)/sizeof(long); 
 + 
 +const int scan_mems = sizeof(scan_array)/sizeof(long); 
 + 
 +// the last "no_scan" number channels of 
 +// channel_array are not to be scanned.  
 +// Put the channels not to be scanned last  
 +// in the array and update no_scan to reflect.  
 + 
 +const int no_scan = 0;  
 + 
 +const long bandStart = 5000000;     
 +const long bandEnd = 6000000; 
 +const long txcio = 9001200; 
 +  
 +const long cwoffset = 600; 
 +const long filteroffset = 500; 
 + 
 +volatile int channel = 01; 
 + 
 +volatile long freq = channel_array[channel];  //       
 +volatile long oldfreq = 0; 
 + 
 + 
 + 
 + 
 + 
 +volatile long currentfreq = 0; 
 +volatile int updatedisplay = 0; 
 + 
 +// Rotary encoder pins and other inputs 
 +static const int rotAPin = 2; 
 +static const int rotBPin = 3; 
 +static const int pushSwPin = 4; 
 +static const int mictxrxPin = 5; 
 +static const int txRLA1Pin = 7; 
 +static const int txRLA2Pin = 6; 
 +static const int datatxrxPin = 8; 
 +static const int modRLAPin = 9; 
 +static const int modeSWPin = 11; 
 +static const int scanSWPin = 10; 
 + 
 +volatile int scanning = 0; 
 +volatile int old_scanning = 0; 
 + 
 +volatile int tx = 0; 
 +volatile int oldtxrx = 0; 
 + 
 +volatile int mod = 0; 
 +volatile int oldmod = 0; 
 + 
 +volatile int channel_freq = 0; // push-button to toggle tune method 
 +volatile int old_channel_freq = 0; 
 + 
 +volatile long scan_freq = scan_array[channel]; 
 +volatile long old_scan_freq = 0; 
 + 
 +volatile int mode = 1; // 1 = USB/LSB, 0 = CW  
 +volatile int oldmode = 0; 
 + 
 +// Rotary encoder variables, used by interrupt routines 
 +volatile int rotState = 0; 
 +volatile int rotAval = 1; 
 +volatile int rotBval = 1; 
 + 
 + 
 +int digit1 = 0; 
 +int digit2 = 0; 
 +int digit3 = 0; 
 +int digit4 = 0;    
 +int digit5 = 0; 
 +int digit6 = 0; 
 +int digit7 = 0; 
 + 
 +// Instantiate the Objects 
 +rgb_lcd lcd; 
 +Si5351 si5351; 
 + 
 + 
 + 
 +byte customChar[8] = { 
 +  0b11111, 
 +  0b11011, 
 +  0b11001, 
 +  0b00000, 
 +  0b11001, 
 +  0b11011, 
 +  0b11111, 
 +  0b11111 
 +}; 
 + 
 + 
 + 
 +void setup() 
 +
 + 
 +  
 +  // Set up frequency and radix switches 
 +  pinMode(rotAPin, INPUT_PULLUP); 
 +  pinMode(rotBPin, INPUT_PULLUP); 
 +  pinMode(pushSwPin, INPUT_PULLUP); 
 +   
 +  pinMode(mictxrxPin, INPUT_PULLUP); 
 +  pinMode(datatxrxPin, INPUT_PULLUP); 
 +   
 +  pinMode(modeSWPin, INPUT_PULLUP); 
 +  pinMode(scanSWPin, INPUT_PULLUP); 
 +  pinMode(txRLA1Pin, OUTPUT); 
 +  pinMode(txRLA2Pin, OUTPUT); 
 +  pinMode(modRLAPin, OUTPUT); 
 +  
 +  digitalWrite(txRLA1Pin, LOW); 
 +  digitalWrite(txRLA2Pin, LOW); 
 +  digitalWrite(modRLAPin, LOW); 
 + 
 +  // Set up interrupt pins 
 +  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE); 
 +  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE); 
 + 
 +  // Initialize the display 
 +  lcd.begin(16, 2); 
 + 
 +lcd.createChar(0, customChar); // create a new custom character 
 + 
 +  lcd.cursor(); 
 + 
 +  // Initialize the Si5351 
 + 
 +  //si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, -31200);         //  
 +  //si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);   // 2 mA for HB mixers 
 +  //si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);   // 2 mA for HB mixers 
 +   
 +  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); 
 +  si5351.set_correction(-34976, SI5351_PLL_INPUT_XO); 
 +  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); 
 +  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 
 +  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA); 
 + 
 +   
 +  // Update display and send start frequency 
 +  UpdateDisplay(); 
 +  SendFrequency(); 
 +
 + 
 + 
 +void loop() 
 +
 + 
 +  CheckScanSwitch(); 
 +   
 +  //CheckTXSwitch(); 
 +   
 +  //CheckModSwitch(); 
 + 
 +  CheckModeSwitch(); 
 +   
 +  // Check to see if the freq has changed 
 +  currentfreq = getfreq();                      // Interrupt safe method to get the current frequency 
 +   
 +  if (currentfreq != oldfreq) 
 +  { 
 +    
 +    oldfreq = currentfreq; 
 +      
 +    UpdateDisplay(); 
 +    SendFrequency(); 
 + 
 +  } 
 + 
 +  // Check the rotary encoder (radix) swith 
 +  if (digitalRead(pushSwPin) == LOW)           // Read the rotary encoder switch 
 +  { 
 +    delay(500); 
 +    if (digitalRead(pushSwPin) == LOW) 
 +    { 
 +     
 +    if (channel_freq == 1) 
 +    { 
 +      channel_freq = 0; 
 +    } 
 +    else if (channel_freq == 0) 
 +    { 
 +      channel_freq = 1; 
 +    } 
 +    //delay(50); 
 +     
 +    UpdateDisplay(); 
 +     
 +    } 
 +  } 
 +   
 +} // end of main loop 
 + 
 + 
 +long getfreq() 
 +
 +  long temp_freq; 
 +  cli(); 
 +  temp_freq = freq; 
 +  sei(); 
 +  return temp_freq; 
 +
 + 
 +void CheckScanSwitch() 
 +
 + if (digitalRead(scanSWPin) == 0) 
 + 
 +    { 
 +     
 +      scanning  = 1; 
 +      scan_freq = 0; 
 +      channel = channel + 1; 
 + 
 +      if (channel > scan_mems - (no_scan + 1)) 
 +            { 
 +              channel = 0; 
 +            } 
 +             
 +      freq = scan_array[channel]; 
 +       
 +      UpdateDisplay(); 
 +      SendFrequency(); 
 +      delay(500); 
 +    } 
 +    else 
 +    { 
 +      
 +       
 +      if (scanning != old_scanning) 
 +      { 
 +        scanning = 0; 
 +        UpdateDisplay(); 
 +      } 
 +      old_scanning = scanning; 
 +    } 
 + 
 +
 + 
 +//void CheckModSwitch() 
 +//{ 
 +//  if (digitalRead(modSWPin) == 0) 
 +//      mod = 0;                             // 0 = Phone 
 +//  else if (digitalRead(modSWPin) == 1) 
 +//      mod = 1;                                 // 1=Data 
 +     
 +     
 +//  if (mod != oldmod) 
 +//  { 
 +//    if ( mod == 0) 
 +//      { 
 +//        digitalWrite(modRLAPin,LOW); 
 +//      } 
 +//    else 
 +//      { 
 +//        digitalWrite(modRLAPin,HIGH); 
 +//      }  
 +//    UpdateDisplay(); 
 +//    SendFrequency(); 
 +//    oldmod = mod; 
 +//  } 
 +//} 
 + 
 + 
 +void CheckModeSwitch() 
 +
 +  if (digitalRead(modeSWPin) == 0) 
 +      mode = 0;                             // 0 = CW 
 +  else if (digitalRead(modeSWPin) == 1) 
 +      mode = 1;                                 // 1=SSB 
 +     
 +     
 +  if (mode != oldmode) 
 +  { 
 +    if ( mode == 0) 
 +      { 
 +         
 +      } 
 +    else 
 +      { 
 +        
 +      }  
 +    UpdateDisplay(); 
 +    SendFrequency(); 
 +    oldmode = mode; 
 +  } 
 +
 + 
 + 
 + 
 +void CheckTXSwitch() 
 +
 +  if (scanning == 0) 
 +  { 
 +  if (digitalRead(mictxrxPin) == 0) 
 + 
 +  { 
 +    tx = 1;                             // 1=TX 
 +    mod = 0; 
 +     
 +    else if (digitalRead(datatxrxPin) == 0) 
 + 
 +  {  tx = 1; 
 +     mod = 1; 
 +      
 +  }  else if (digitalRead(mictxrxPin) == 1) 
 +     
 +  {  tx = 0;                                 // 0=Phone 
 +     
 +  } else if (digitalRead(datatxrxPin) == 1) 
 + 
 +   tx = 0; 
 +     
 + } 
 +    
 +  if (tx != oldtxrx) 
 +  { 
 +    if ( tx == 1) 
 +      { 
 +        if ( mod == 0 ) 
 +        { 
 +          digitalWrite(modRLAPin,LOW); 
 +        } 
 +        else if ( mod == 1 ) 
 +        { 
 +          digitalWrite(modRLAPin,HIGH); 
 +        } 
 +        digitalWrite(txRLA1Pin,HIGH); 
 +        digitalWrite(txRLA2Pin,HIGH); 
 +      } 
 +    else 
 +      { 
 +        digitalWrite(txRLA1Pin,LOW); 
 +        digitalWrite(txRLA2Pin,LOW);    
 +      } 
 +    UpdateDisplay(); 
 +    SendFrequency(); 
 +    oldtxrx = tx; 
 +  } 
 +
 +
 + 
 +// Interrupt routines 
 +void ISRrotAChange() 
 +
 +  if (digitalRead(rotAPin)) 
 +  { 
 +    rotAval = 1; 
 +    UpdateRot(); 
 +  } 
 +  else 
 +  { 
 +    rotAval = 0; 
 +    UpdateRot(); 
 +  } 
 +
 + 
 + 
 +void ISRrotBChange() 
 +
 +  if (digitalRead(rotBPin)) 
 +  { 
 +    rotBval = 1; 
 +    UpdateRot(); 
 +  } 
 +  else 
 +  { 
 +    rotBval = 0; 
 +    UpdateRot(); 
 +  } 
 +
 + 
 + 
 +// Determine which way the rotary encoder is rotating and action as required 
 +void UpdateRot() 
 +
 +  switch (rotState) 
 +  { 
 +    case 0:                                         // Idle state, look for direction 
 +      if (!rotBval) 
 +        rotState = 1;                               // CW 1 
 +      if (!rotAval) 
 +        rotState = 11;                              // CCW 1 
 +      break; 
 + 
 +    case 1:                                         // CW, wait for A low while B is low 
 +      if (!rotBval) 
 +      { 
 +        if (!rotAval) 
 +        { 
 +          // either increment the radix or freq 
 +          if (channel_freq == 1) 
 +          { 
 +            updatedisplay = 1; 
 +            if (mode == 1) 
 +            { 
 +            freq = freq + 500; 
 +            } 
 +            else 
 +            { 
 +              freq = freq + 100; 
 +            } 
 +            if (freq > bandEnd) 
 +            { 
 +              freq = bandEnd; 
 +            } 
 +            
 +          } 
 +          else 
 +          { 
 +            channel = channel + 1; 
 +             
 +            if (channel > mems -1) 
 +            { 
 +              channel = 0; 
 +            } 
 +            freq = channel_array[channel];  
 +          } 
 +          rotState = 2;                             // CW 2 
 +        } 
 +      } 
 +      else if (rotAval) 
 +        rotState = 0;                               // It was just a glitch on B, go back to start 
 +      break; 
 + 
 +    case 2:                                         // CW, wait for B high 
 +      if (rotBval) 
 +        rotState = 3;                               // CW 3 
 +      break; 
 + 
 +    case 3:                                         // CW, wait for A high 
 +      if (rotAval) 
 +        rotState = 0;                               // back to idle (detent) state 
 +      break; 
 + 
 +    case 11:                                        // CCW, wait for B low while A is low 
 +      if (!rotAval) 
 +      { 
 +        if (!rotBval) 
 +        { 
 +          if ( channel_freq == 1 ) 
 +          { 
 +            updatedisplay = 1; 
 + 
 +            if (mode == 1) 
 +            { 
 +            freq = freq - 500; 
 +            } 
 +            else 
 +            { 
 +              freq = freq - 100; 
 +            } 
 +             
 +            if (freq < bandStart) 
 +            { 
 +              freq = bandStart; 
 +            } 
 +          } 
 +          else 
 +          { 
 +            channel = channel - 1; 
 +             
 +            if (channel < 0) 
 +             { 
 +              channel = mems - 1; 
 +             } 
 +            freq = channel_array[channel]; 
 +            
 +          } 
 +          rotState = 12;                            // CCW 2 
 +        } 
 +      } 
 +      else if (rotBval) 
 +        rotState = 0;                               // It was just a glitch on A, go back to start 
 +      break; 
 + 
 +    case 12:                                        // CCW, wait for A high 
 +      if (rotAval) 
 +        rotState = 13;                              // CCW 3 
 +      break; 
 + 
 +    case 13:                                        // CCW, wait for B high 
 +      if (rotBval) 
 +        rotState = 0;                               // back to idle (detent) state 
 +      break; 
 +  } 
 +
 + 
 + 
 +void UpdateDisplay() 
 +
 + 
 + 
 +    digit1 = (freq%10); 
 +    digit2 = ((freq/10)%10); 
 +    digit3 = ((freq/100)%10); 
 +    digit4 = ((freq/1000)%10);    
 +    digit5 = ((freq/10000)%10); 
 +    digit6 = ((freq/100000)%10); 
 +    digit7 = ((freq/1000000)%10); 
 +    
 +     
 +  lcd.setCursor(0,0); 
 +  lcd.print(digit7); 
 +  lcd.setCursor(1,0); 
 +  lcd.print(","); 
 +  lcd.setCursor(2,0); 
 +  lcd.print(digit6); 
 +  lcd.setCursor(3,0); 
 +  lcd.print(digit5); 
 +  lcd.setCursor(4,0); 
 +  lcd.print(digit4); 
 +  lcd.setCursor(5,0); 
 +  lcd.print("."); 
 +  lcd.setCursor(6,0); 
 +  lcd.print(digit3); 
 +  lcd.setCursor(7,0); 
 +  lcd.print(digit2); 
 +   
 +  lcd.setCursor(8,0); 
 +  lcd.print("kHz"); 
 +  
 + 
 +  
 + 
 +  lcd.setCursor(0,1); 
 +  lcd.print("        "); 
 +   
 +   
 +   
 +  lcd.setCursor(channel,1);  
 +   
 + 
 +if (scanning == 1) 
 +
 +   // lcd.print("|"); 
 + 
 +  lcd.write((byte)0);  // print the custom char at (2, 0) 
 +
 +   
 + /* 
 +  //if (channel < 10) 
 +  //{ 
 +  //lcd.print("0"); 
 +  //} 
 +  //lcd.print(channel); 
 + 
 + lcd.setCursor(0,1); 
 + if (freq == 5287200 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("WSPR1"); 
 + } 
 + 
 + if (freq == 5290000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("ORK"); 
 + } 
 + 
 + if (freq == 5364700 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("WSPR2"); 
 + } 
 + 
 + if (freq == 5450000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("RAF"); 
 + } 
 + 
 + if (freq == 5505000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("EIP"); 
 + } 
 + 
 +if (freq == 5317000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("VMARS"); 
 + } 
 + 
 +if (freq == 5366500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FK"); 
 + } 
 + 
 +if (freq == 5258500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FA"); 
 + } 
 + 
 +if (freq == 5278500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FB"); 
 + } 
 + 
 +if (freq == 5288500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FC"); 
 + } 
 + 
 +if (freq == 5371500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FL"); 
 + } 
 +  
 +if (freq == 5398500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FE"); 
 + } 
 + 
 + if (freq == 5403500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FM"); 
 + } 
 + 
 +if (freq == 5195000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("DRA5"); 
 + } 
 + 
 +if (freq == 5262000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("QRP CW"); 
 + } 
 +   
 + 
 +if ((freq >= 5259000) && (freq < 5262000) ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("CW"); 
 + } 
 + 
 + 
 +   
 +*/ 
 + 
 + 
 +  
 +  
 + lcd.setCursor(14,0); 
 + 
 +if (tx == 0) 
 +   { lcd.print("RX"); 
 +   
 +   } else if (tx == 1) 
 +   { 
 +    lcd.print("TX"); 
 +  } 
 +   
 +  lcd.setCursor(8,1); 
 +  if (mode == 1) 
 +  { 
 +    lcd.print("SSB"); 
 +  } 
 +  if (mode == 0) 
 +  { 
 +    lcd.print(" CW"); 
 +  } 
 +     
 +  lcd.setCursor(12,1); 
 +  if ( mode == 0 ) 
 +  { 
 +    lcd.print(" Key"); 
 +    //lcd.print(version); 
 +  } 
 +  else 
 +   
 +  { 
 +    if (mod == 0) 
 +  { 
 +    lcd.print(" Mic"); 
 +    //lcd.print(version); 
 +  } 
 +  else 
 +  { 
 +   lcd.print("Data"); 
 +   //lcd.print(version); 
 +  } 
 +
 +if (channel_freq == 1) 
 +
 +  if (mode == 1) 
 +  { 
 +    lcd.setCursor(6,0); 
 +  } 
 +  else if ( mode == 0 ) 
 +  { 
 +    lcd.setCursor(7,0); 
 +  } 
 +  lcd.blink(); 
 +
 +else 
 +
 +  lcd.noBlink(); 
 +
 +} // end of updatedisplay() 
 + 
 + 
 +void SendFrequency() 
 + 
 + 
 +  
 +  
 +
 + 
 +if (mode == 1 ) // SSB 
 + 
 +  { 
 +    si5351.set_freq(((txcio + freq) * 100ULL), SI5351_CLK0);     // VFO 
 +    si5351.set_freq((txcio * 100ULL), SI5351_CLK2);              // BFO 
 + 
 +  } 
 + 
 +else if (mode == 0) // CW 
 + 
 +  if ( tx == 0 ) 
 + 
 +  { 
 + 
 +    si5351.set_freq(((txcio + freq - cwoffset - filteroffset) * 100ULL), SI5351_CLK0);    // VFO 
 +    si5351.set_freq(((txcio  - filteroffset) * 100ULL), SI5351_CLK2);                     // BFO 
 +   
 +  } 
 + 
 +  else if (tx == 1 ) 
 +  
 +  { 
 +  
 +    si5351.set_freq(((txcio + freq - cwoffset - filteroffset) * 100ULL), SI5351_CLK0);    // VFO 
 +    si5351.set_freq(((txcio - cwoffset - filteroffset) * 100ULL), SI5351_CLK2);           // BFO 
 +  
 +  } 
 + 
 +} // end of sendfrequency() 
 + 
 +</code> 
 + 
 +++++ 
 + 
 +==== Full TX/RX - with SSB, CW & Scan ==== 
 + 
 +{{ :public:radio:topics:arduino:gm4slv_60m_channels_cwscan_ptt_new_calibration_230823.ino |}} 
 + 
 +++++ Firmware (Click to view) | 
 + 
 +<code c> 
 + 
 +#include <rgb_lcd.h> 
 +#include <si5351.h> 
 + 
 +char version[] = "v0.1"; 
 + 
 +const long channel_array[] =  
 +
 +5258500,5260000,5261000,5262000,5263000, 5276000, 
 +5278500,5279000,5287200,5290000,5298000, 
 +5301000,5304000,5317000,5320000,5333000, 
 +5334000,5335000,5354000,5355000,5362000, 
 +5363000,5364700,5366500,5371500,5378000, 
 +5379000,5395000,5398500,5403500, 
 +5345000,5245000,5450000,5505000,5680000, 
 +5195000,5616000,5649000 
 +} ; 
 + 
 +const long scan_array[] =  
 +
 + 5260000,5261000, 
 + 5262000,5263000, 
 + 5366500,5354000, 
 + 5355000, 
 +} ; 
 + 
 + 
 +const int mems = sizeof(channel_array)/sizeof(long); 
 + 
 +const int scan_mems = sizeof(scan_array)/sizeof(long); 
 + 
 +// the last "no_scan" number channels of 
 +// channel_array are not to be scanned.  
 +// Put the channels not to be scanned last  
 +// in the array and update no_scan to reflect.  
 + 
 +const int no_scan = 0;  
 + 
 +const long bandStart = 5000000;     
 +const long bandEnd = 6000000; 
 +const long txcio = 9001200; 
 +  
 +const long cwoffset = 600; 
 +const long filteroffset = 500; 
 + 
 +volatile int channel = 01; 
 + 
 +volatile long freq = channel_array[channel];  //       
 +volatile long oldfreq = 0; 
 + 
 + 
 + 
 + 
 + 
 +volatile long currentfreq = 0; 
 +volatile int updatedisplay = 0; 
 + 
 +// Rotary encoder pins and other inputs 
 +static const int rotAPin = 2; 
 +static const int rotBPin = 3; 
 +static const int pushSwPin = 4; 
 +static const int mictxrxPin = 5; 
 +static const int txRLA1Pin = 7; 
 +static const int txRLA2Pin = 6; 
 +static const int datatxrxPin = 8; 
 +static const int modRLAPin = 9; 
 +static const int modeSWPin = 11; 
 +static const int scanSWPin = 10; 
 + 
 +volatile int scanning = 0; 
 +volatile int old_scanning = 0; 
 + 
 +volatile int tx = 0; 
 +volatile int oldtxrx = 0; 
 + 
 +volatile int mod = 0; 
 +volatile int oldmod = 0; 
 + 
 +volatile int channel_freq = 0; // push-button to toggle tune method 
 +volatile int old_channel_freq = 0; 
 + 
 +volatile long scan_freq = scan_array[channel]; 
 +volatile long old_scan_freq = 0; 
 + 
 +volatile int mode = 1; // 1 = USB/LSB, 0 = CW  
 +volatile int oldmode = 0; 
 + 
 +// Rotary encoder variables, used by interrupt routines 
 +volatile int rotState = 0; 
 +volatile int rotAval = 1; 
 +volatile int rotBval = 1; 
 + 
 + 
 +int digit1 = 0; 
 +int digit2 = 0; 
 +int digit3 = 0; 
 +int digit4 = 0;    
 +int digit5 = 0; 
 +int digit6 = 0; 
 +int digit7 = 0; 
 + 
 +// Instantiate the Objects 
 +rgb_lcd lcd; 
 +Si5351 si5351; 
 + 
 + 
 + 
 +byte customChar[8] = { 
 +  0b11111, 
 +  0b11011, 
 +  0b11001, 
 +  0b00000, 
 +  0b11001, 
 +  0b11011, 
 +  0b11111, 
 +  0b11111 
 +}; 
 + 
 + 
 + 
 +void setup() 
 +
 + 
 +  
 +  // Set up frequency and radix switches 
 +  pinMode(rotAPin, INPUT_PULLUP); 
 +  pinMode(rotBPin, INPUT_PULLUP); 
 +  pinMode(pushSwPin, INPUT_PULLUP); 
 +   
 +  pinMode(mictxrxPin, INPUT_PULLUP); 
 +  pinMode(datatxrxPin, INPUT_PULLUP); 
 +   
 +  pinMode(modeSWPin, INPUT_PULLUP); 
 +  pinMode(scanSWPin, INPUT_PULLUP); 
 +  pinMode(txRLA1Pin, OUTPUT); 
 +  pinMode(txRLA2Pin, OUTPUT); 
 +  pinMode(modRLAPin, OUTPUT); 
 +  
 +  digitalWrite(txRLA1Pin, LOW); 
 +  digitalWrite(txRLA2Pin, LOW); 
 +  digitalWrite(modRLAPin, LOW); 
 + 
 +  // Set up interrupt pins 
 +  attachInterrupt(digitalPinToInterrupt(rotAPin), ISRrotAChange, CHANGE); 
 +  attachInterrupt(digitalPinToInterrupt(rotBPin), ISRrotBChange, CHANGE); 
 + 
 +  // Initialize the display 
 +  lcd.begin(16, 2); 
 + 
 +lcd.createChar(0, customChar); // create a new custom character 
 + 
 +  lcd.cursor(); 
 + 
 +  // Initialize the Si5351 
 + 
 +  //si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, -31200);         //  
 +  //si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);   // 2 mA for HB mixers 
 +  //si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA);   // 2 mA for HB mixers 
 +   
 +  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); 
 +  si5351.set_correction(-34976, SI5351_PLL_INPUT_XO); 
 +  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); 
 +  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 
 +  si5351.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA); 
 + 
 +   
 +  // Update display and send start frequency 
 +  UpdateDisplay(); 
 +  SendFrequency(); 
 +
 + 
 + 
 +void loop() 
 +
 + 
 +  CheckScanSwitch(); 
 +   
 +  CheckTXSwitch(); 
 +   
 +  //CheckModSwitch(); 
 + 
 +  CheckModeSwitch(); 
 +   
 +  // Check to see if the freq has changed 
 +  currentfreq = getfreq();                      // Interrupt safe method to get the current frequency 
 +   
 +  if (currentfreq != oldfreq) 
 +  { 
 +    
 +    oldfreq = currentfreq; 
 +      
 +    UpdateDisplay(); 
 +    SendFrequency(); 
 + 
 +  } 
 + 
 +  // Check the rotary encoder (radix) swith 
 +  if (digitalRead(pushSwPin) == LOW)           // Read the rotary encoder switch 
 +  { 
 +    delay(500); 
 +    if (digitalRead(pushSwPin) == LOW) 
 +    { 
 +     
 +    if (channel_freq == 1) 
 +    { 
 +      channel_freq = 0; 
 +    } 
 +    else if (channel_freq == 0) 
 +    { 
 +      channel_freq = 1; 
 +    } 
 +    //delay(50); 
 +     
 +    UpdateDisplay(); 
 +     
 +    } 
 +  } 
 +   
 +} // end of main loop 
 + 
 + 
 +long getfreq() 
 +
 +  long temp_freq; 
 +  cli(); 
 +  temp_freq = freq; 
 +  sei(); 
 +  return temp_freq; 
 +
 + 
 +void CheckScanSwitch() 
 +
 + if (digitalRead(scanSWPin) == 0) 
 + 
 +    { 
 +     
 +      scanning  = 1; 
 +      scan_freq = 0; 
 +      channel = channel + 1; 
 + 
 +      if (channel > scan_mems - (no_scan + 1)) 
 +            { 
 +              channel = 0; 
 +            } 
 +             
 +      freq = scan_array[channel]; 
 +       
 +      UpdateDisplay(); 
 +      SendFrequency(); 
 +      delay(500); 
 +    } 
 +    else 
 +    { 
 +      
 +       
 +      if (scanning != old_scanning) 
 +      { 
 +        scanning = 0; 
 +        UpdateDisplay(); 
 +      } 
 +      old_scanning = scanning; 
 +    } 
 + 
 +
 + 
 +//void CheckModSwitch() 
 +//{ 
 +//  if (digitalRead(modSWPin) == 0) 
 +//      mod = 0;                             // 0 = Phone 
 +//  else if (digitalRead(modSWPin) == 1) 
 +//      mod = 1;                                 // 1=Data 
 +     
 +     
 +//  if (mod != oldmod) 
 +//  { 
 +//    if ( mod == 0) 
 +//      { 
 +//        digitalWrite(modRLAPin,LOW); 
 +//      } 
 +//    else 
 +//      { 
 +//        digitalWrite(modRLAPin,HIGH); 
 +//      }  
 +//    UpdateDisplay(); 
 +//    SendFrequency(); 
 +//    oldmod = mod; 
 +//  } 
 +//} 
 + 
 + 
 +void CheckModeSwitch() 
 +
 +  if (digitalRead(modeSWPin) == 0) 
 +      mode = 0;                             // 0 = CW 
 +  else if (digitalRead(modeSWPin) == 1) 
 +      mode = 1;                                 // 1=SSB 
 +     
 +     
 +  if (mode != oldmode) 
 +  { 
 +    if ( mode == 0) 
 +      { 
 +         
 +      } 
 +    else 
 +      { 
 +        
 +      }  
 +    UpdateDisplay(); 
 +    SendFrequency(); 
 +    oldmode = mode; 
 +  } 
 +
 + 
 + 
 + 
 +void CheckTXSwitch() 
 +
 +  if (scanning == 0) 
 +  { 
 +  if (digitalRead(mictxrxPin) == 0) 
 + 
 +  { 
 +    tx = 1;                             // 1=TX 
 +    mod = 0; 
 +     
 +    else if (digitalRead(datatxrxPin) == 0) 
 + 
 +  {  tx = 1; 
 +     mod = 1; 
 +      
 +  }  else if (digitalRead(mictxrxPin) == 1) 
 +     
 +  {  tx = 0;                                 // 0=Phone 
 +     
 +  } else if (digitalRead(datatxrxPin) == 1) 
 + 
 +   tx = 0; 
 +     
 + } 
 +    
 +  if (tx != oldtxrx) 
 +  { 
 +    if ( tx == 1) 
 +      { 
 +        if ( mod == 0 ) 
 +        { 
 +          digitalWrite(modRLAPin,LOW); 
 +        } 
 +        else if ( mod == 1 ) 
 +        { 
 +          digitalWrite(modRLAPin,HIGH); 
 +        } 
 +        digitalWrite(txRLA1Pin,HIGH); 
 +        digitalWrite(txRLA2Pin,HIGH); 
 +      } 
 +    else 
 +      { 
 +        digitalWrite(txRLA1Pin,LOW); 
 +        digitalWrite(txRLA2Pin,LOW);    
 +      } 
 +    UpdateDisplay(); 
 +    SendFrequency(); 
 +    oldtxrx = tx; 
 +  } 
 +
 +
 + 
 +// Interrupt routines 
 +void ISRrotAChange() 
 +
 +  if (digitalRead(rotAPin)) 
 +  { 
 +    rotAval = 1; 
 +    UpdateRot(); 
 +  } 
 +  else 
 +  { 
 +    rotAval = 0; 
 +    UpdateRot(); 
 +  } 
 +
 + 
 + 
 +void ISRrotBChange() 
 +
 +  if (digitalRead(rotBPin)) 
 +  { 
 +    rotBval = 1; 
 +    UpdateRot(); 
 +  } 
 +  else 
 +  { 
 +    rotBval = 0; 
 +    UpdateRot(); 
 +  } 
 +
 + 
 + 
 +// Determine which way the rotary encoder is rotating and action as required 
 +void UpdateRot() 
 +
 +  switch (rotState) 
 +  { 
 +    case 0:                                         // Idle state, look for direction 
 +      if (!rotBval) 
 +        rotState = 1;                               // CW 1 
 +      if (!rotAval) 
 +        rotState = 11;                              // CCW 1 
 +      break; 
 + 
 +    case 1:                                         // CW, wait for A low while B is low 
 +      if (!rotBval) 
 +      { 
 +        if (!rotAval) 
 +        { 
 +          // either increment the radix or freq 
 +          if (channel_freq == 1) 
 +          { 
 +            updatedisplay = 1; 
 +            if (mode == 1) 
 +            { 
 +            freq = freq + 500; 
 +            } 
 +            else 
 +            { 
 +              freq = freq + 100; 
 +            } 
 +            if (freq > bandEnd) 
 +            { 
 +              freq = bandEnd; 
 +            } 
 +            
 +          } 
 +          else 
 +          { 
 +            channel = channel + 1; 
 +             
 +            if (channel > mems -1) 
 +            { 
 +              channel = 0; 
 +            } 
 +            freq = channel_array[channel];  
 +          } 
 +          rotState = 2;                             // CW 2 
 +        } 
 +      } 
 +      else if (rotAval) 
 +        rotState = 0;                               // It was just a glitch on B, go back to start 
 +      break; 
 + 
 +    case 2:                                         // CW, wait for B high 
 +      if (rotBval) 
 +        rotState = 3;                               // CW 3 
 +      break; 
 + 
 +    case 3:                                         // CW, wait for A high 
 +      if (rotAval) 
 +        rotState = 0;                               // back to idle (detent) state 
 +      break; 
 + 
 +    case 11:                                        // CCW, wait for B low while A is low 
 +      if (!rotAval) 
 +      { 
 +        if (!rotBval) 
 +        { 
 +          if ( channel_freq == 1 ) 
 +          { 
 +            updatedisplay = 1; 
 + 
 +            if (mode == 1) 
 +            { 
 +            freq = freq - 500; 
 +            } 
 +            else 
 +            { 
 +              freq = freq - 100; 
 +            } 
 +             
 +            if (freq < bandStart) 
 +            { 
 +              freq = bandStart; 
 +            } 
 +          } 
 +          else 
 +          { 
 +            channel = channel - 1; 
 +             
 +            if (channel < 0) 
 +             { 
 +              channel = mems - 1; 
 +             } 
 +            freq = channel_array[channel]; 
 +            
 +          } 
 +          rotState = 12;                            // CCW 2 
 +        } 
 +      } 
 +      else if (rotBval) 
 +        rotState = 0;                               // It was just a glitch on A, go back to start 
 +      break; 
 + 
 +    case 12:                                        // CCW, wait for A high 
 +      if (rotAval) 
 +        rotState = 13;                              // CCW 3 
 +      break; 
 + 
 +    case 13:                                        // CCW, wait for B high 
 +      if (rotBval) 
 +        rotState = 0;                               // back to idle (detent) state 
 +      break; 
 +  } 
 +
 + 
 + 
 +void UpdateDisplay() 
 +
 + 
 + 
 +    digit1 = (freq%10); 
 +    digit2 = ((freq/10)%10); 
 +    digit3 = ((freq/100)%10); 
 +    digit4 = ((freq/1000)%10);    
 +    digit5 = ((freq/10000)%10); 
 +    digit6 = ((freq/100000)%10); 
 +    digit7 = ((freq/1000000)%10); 
 +    
 +     
 +  lcd.setCursor(0,0); 
 +  lcd.print(digit7); 
 +  lcd.setCursor(1,0); 
 +  lcd.print(","); 
 +  lcd.setCursor(2,0); 
 +  lcd.print(digit6); 
 +  lcd.setCursor(3,0); 
 +  lcd.print(digit5); 
 +  lcd.setCursor(4,0); 
 +  lcd.print(digit4); 
 +  lcd.setCursor(5,0); 
 +  lcd.print("."); 
 +  lcd.setCursor(6,0); 
 +  lcd.print(digit3); 
 +  lcd.setCursor(7,0); 
 +  lcd.print(digit2); 
 +   
 +  lcd.setCursor(8,0); 
 +  lcd.print("kHz"); 
 +  
 + 
 +  
 + 
 +  lcd.setCursor(0,1); 
 +  lcd.print("        "); 
 +   
 +   
 +   
 +  lcd.setCursor(channel,1);  
 +   
 + 
 +if (scanning == 1) 
 +
 +   // lcd.print("|"); 
 + 
 +  lcd.write((byte)0);  // print the custom char at (2, 0) 
 +
 +   
 + /* 
 +  //if (channel < 10) 
 +  //{ 
 +  //lcd.print("0"); 
 +  //} 
 +  //lcd.print(channel); 
 + 
 + lcd.setCursor(0,1); 
 + if (freq == 5287200 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("WSPR1"); 
 + } 
 + 
 + if (freq == 5290000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("ORK"); 
 + } 
 + 
 + if (freq == 5364700 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("WSPR2"); 
 + } 
 + 
 + if (freq == 5450000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("RAF"); 
 + } 
 + 
 + if (freq == 5505000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("EIP"); 
 + } 
 + 
 +if (freq == 5317000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("VMARS"); 
 + } 
 + 
 +if (freq == 5366500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FK"); 
 + } 
 + 
 +if (freq == 5258500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FA"); 
 + } 
 + 
 +if (freq == 5278500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FB"); 
 + } 
 + 
 +if (freq == 5288500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FC"); 
 + } 
 + 
 +if (freq == 5371500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FL"); 
 + } 
 +  
 +if (freq == 5398500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FE"); 
 + } 
 + 
 + if (freq == 5403500 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("FM"); 
 + } 
 + 
 +if (freq == 5195000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("DRA5"); 
 + } 
 + 
 +if (freq == 5262000 ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("QRP CW"); 
 + } 
 +   
 + 
 +if ((freq >= 5259000) && (freq < 5262000) ) 
 + { 
 +  //lcd.setCursor(3,1); 
 +  //lcd.print("    "); 
 +  //lcd.setCursor(3,1); 
 +  lcd.print("CW"); 
 + } 
 + 
 + 
 +   
 +*/ 
 + 
 + 
 +  
 +  
 + lcd.setCursor(14,0); 
 + 
 +if (tx == 0) 
 +   { lcd.print("RX"); 
 +   
 +   } else if (tx == 1) 
 +   { 
 +    lcd.print("TX"); 
 +  } 
 +   
 +  lcd.setCursor(8,1); 
 +  if (mode == 1) 
 +  { 
 +    lcd.print("SSB"); 
 +  } 
 +  if (mode == 0) 
 +  { 
 +    lcd.print(" CW"); 
 +  } 
 +     
 +  lcd.setCursor(12,1); 
 +  if ( mode == 0 ) 
 +  { 
 +    lcd.print(" Key"); 
 +    //lcd.print(version); 
 +  } 
 +  else 
 +   
 +  { 
 +    if (mod == 0) 
 +  { 
 +    lcd.print(" Mic"); 
 +    //lcd.print(version); 
 +  } 
 +  else 
 +  { 
 +   lcd.print("Data"); 
 +   //lcd.print(version); 
 +  } 
 +
 +if (channel_freq == 1) 
 +
 +  if (mode == 1) 
 +  { 
 +    lcd.setCursor(6,0); 
 +  } 
 +  else if ( mode == 0 ) 
 +  { 
 +    lcd.setCursor(7,0); 
 +  } 
 +  lcd.blink(); 
 +
 +else 
 +
 +  lcd.noBlink(); 
 +
 +} // end of updatedisplay() 
 + 
 + 
 +void SendFrequency() 
 + 
 + 
 +  
 +  
 +
 + 
 +if (mode == 1 ) // SSB 
 + 
 +  { 
 +    si5351.set_freq(((txcio + freq) * 100ULL), SI5351_CLK0);     // VFO 
 +    si5351.set_freq((txcio * 100ULL), SI5351_CLK2);              // BFO 
 + 
 +  } 
 + 
 +else if (mode == 0) // CW 
 + 
 +  if ( tx == 0 ) 
 + 
 +  { 
 + 
 +    si5351.set_freq(((txcio + freq - cwoffset - filteroffset) * 100ULL), SI5351_CLK0);    // VFO 
 +    si5351.set_freq(((txcio  - filteroffset) * 100ULL), SI5351_CLK2);                     // BFO 
 +   
 +  } 
 + 
 +  else if (tx == 1 ) 
 +  
 +  { 
 +  
 +    si5351.set_freq(((txcio + freq - cwoffset - filteroffset) * 100ULL), SI5351_CLK0);    // VFO 
 +    si5351.set_freq(((txcio - cwoffset - filteroffset) * 100ULL), SI5351_CLK2);           // BFO 
 +  
 +  } 
 + 
 +} // end of sendfrequency() 
 </code> </code>
 +++++
  
  
Line 18: Line 1668:
 Page updated : ~~LASTMOD~~ Page updated : ~~LASTMOD~~
  
-{{tag>}}+{{tag>radio arduino }}