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:26 BST] johnpublic:radio:topics:arduino:60m_transceiver [11/07/26 10:44 BST] (current) – [Further Information] john
Line 5: Line 5:
  
  
-The 60m transceiver has the following features+The 60m transceiver has the following features, which vary according to the loaded firmware
  
   * Channelized operation   * Channelized operation
Line 18: Line 18:
   * Digital mode input/output and PTT via 9-pin D   * Digital mode input/output and PTT via 9-pin D
   * SSB Mic input via 8-pin round "Icom" connector   * SSB Mic input via 8-pin round "Icom" connector
-  * Modulation Source (Mic or Data) chosen via select switch+  * Modulation Source (Mic or Data) can chosen via select switch
   * Scan start switch - scan a preset group of channels - cycles continuously, no "squelch"   * 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 ===== ===== Arduino Versions =====
  
-There are several different firmware versions....+There are several different firmware versions....this is just a sample...
  
-==== RX Only, with CW / SSB, and scan ====+==== 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 |}}
  
-Firmware (Click to view) ++++ |+++++ Firmware (Click to view) |
    
 <code c> <code c>
Line 841: Line 842:
  
 ++++ ++++
 +
 +==== 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>
 +++++
 +
 +
  
 ===== Further Information ===== ===== Further Information =====
Line 849: Line 1668:
 Page updated : ~~LASTMOD~~ Page updated : ~~LASTMOD~~
  
-{{tag>}}+{{tag>radio arduino }}