sábado, 25 de abril de 2026

DDS VFO si5351 Oled Cobra 148GTL AM, LSB, USB atualização S/Meter.

Olá a todos que acompanha nosso blog. Como já tinha publicado mês passado e estava com a mão na massa neste sketch, aproveitei e fiz outras atualizações ou modificações. Este esboço simples copiado do vídeo do Sr. CT7API  Manoel Ferreira de Portugal, com modos AM, LSB, USB. Meus agradecimentos ao Sr. Manuel CT7API, e ao Sr. GE75A Júlio. Já fiz outras atualizações neste sketch do Sr. Manuel CT7API do vídeo, hoje publico aqui e em vídeo mais esta atualização coloquei S/Meter, o mesmo S/Meter que adicionei no sketch publicado em Janeiro 2026. O código fonte do programa sketch e suas variáveis estão quase totalmente diferenciado do original do Sr. CT7API e do publicado em Agosto de 2026, se bem que este já está atualizado em inicialização, STEP com caracteres números indicando a frequência do passo por cima dos caracteres números da frequência. Assistam ao vídeo e verás o funcionamento do DDS VFO. Para quem acha que é difícil modificar ou atualizar um esboço Arduino, tem que começar e com o tempo vai-se adquirindo experiência, Vejam que eu sempre estou incentivando a todos vocês que acessam o meu blog ou vídeos a fazerem modificações em transceptores e agora com o DDS VFO, eu ainda estou aprendendo e cada dia vou adquirindo experiência e conteúdos para minhas modificações, é normal errar, mas continuar e persistir é o que move o desejo de conseguir o que você quer. Por isso comece agora, você que da manutenção em transceptores, tem que saber e estar por dentro da eletrônica digital. Quem é montador por hobby de transceptores. Sobre este DDS VFO, o esboço é semelhante ao original do vídeo do Sr. Manuel Ferreira  CT7API, com muito mais atualizações este tem o S/Meter com escala total 30dB, parecida com os transceptores Cobra e outros. Esqueci de falar no vídeo. Á entrada do S/Meter no Arduíno está no pino A0, para atenuar a sensibilidade na entrada A0, ponha ou não depende da sensibilidade do transceptor, um resistor entre 10k a 100k, ligue a uma extremidade do trimpot de 10k, a outra extremidade ligue a negativo (GND), o centro ligado a um resistor entre 1k a 10k ligado ao pino A0 do Arduíno. Observem para a sensibilidade do S/Meter digital e analógico do próprio transceptor em RX e TX, ao ajustar o trimpot do S/Meter digital veja se interfere no sinal do S/Meter analógico. tente ajustar o digital ao mais próximo aos numerais do analógico do transceptor. Vejam alguns projetos de transceptores que poderão receber este DDS VFO para ficar um transceptor completo feito em casa (Homebrew).  NajaArarinhaMinhocaAndiráCurió, LaguneroAlba II etc. Existem outros projetos de transceptores no blog e na WEB que são fáceis de montar e agora ficará mais fácil ainda com este DDS VFO.
Assistam ao vídeo e vejam mais sobre este fabuloso DDS VFO para nossos transceptores em AM, LSB, USB.
Fotos e esboços sketches abaixo.
Bem como adicionei a linha de comando do Oled para o original "Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);"  tive que reposicionar os caracteres nomes de inicialização e demais caracteres. 
Vamos ajustar e colocar os caracteres que estão faltando.
Gravei sem o BFO, depois adicionei. 
O S/Meter está funcionando perfeitamente.
Ok vou adicionar o BFO e centralizar os caracteres certinho.
 Reescrever também os números S/Meter. 
Acho que tenho que posicionar o BFO mais para direita e centralizar.
Acho que um pouco mais acima os caracteres da frequência fica melhor.
O BFO tem que subir mais um pouco e ir mais para direita.
 
Ok pronto acho que assim está bom, mas ainda tem que subir mais o BFO e descer mais os números S/Meter.
Agora eu quero colocar o modo BFO FI depois dos caracteres frequência do BFO.
Vou colocar o STEP no começo lado esquerdo do display.
Observem no segundo e terceiro (zeros) do BFO está o AM por traz, estou posicionando.
Observem que o S/Meter está bem sensível ao chegar perto com a câmera mostra S 9.
Pronto posicionei está bom em AM, LSB, USB.
Os caracteres números S/Meter podem descer mais um pouco.
Ajuste ou calibre o S/Meter pelo original do rádio, ponha ou não o resistor de entrada A0.
Agora acho que está bom, vai ser o segundo sketch.
Pronto está ótimo, vai ser o primeiro sketch.
Esquema ligação elétrica Arduino. 
O circuito si5351 e Oled poderá ser alimentado com 3.3 volts Arduino.
Abra seu Arduino IDE na área de trabalho e delete tudo. Copie todo programa esboço e cole dentro do Arduino IDE. Tenham ás bibliotecas instaladas, e lembre-se que muitas bibliotecas para o mesmo arquivo pode causar conflitos e provocar erros na compilação. 
Primeiro sketch abaixo.
//**********************************************************************************************************/
// Modifications and updates for si5351 Arduino Nano, Pro Mini Atmega 328P. Original by GE75A Julio
// and shared on YouTube by CT7API Manuel Ferreira in the version with 128 x 64 OLED. Original LCD version.
// This entire program is taken from Jason Mildrum, NT7S and Przemek Sadowski, SQ9NJE. There is not enough 
// original code written by me to make it worth mentioning. http://nt7s.com/ http://sq9nje.pl/
// http://ak2b.blogspot.com/ Last update BFO CLK1 by Waldir Cardoso Blog:
// https://projetosetransceptores.blogspot.com/2026/04/dds-vfo-si5351-oled-cobra-148gtl-am-lsb.html
// Updated for S/Meter on 10/04/2026 by Waldir Cardoso. Brasil, Bahia.
//---------------------------------------------------------------------------------
// Function
// 1.VFO CLK0 34 Mhz AM LSB USB MODE Cobra 148 GTL other AM SSB equipment, modify the sketch.
// 2.BFO CLK1 BFO FI 7.800 Khz AM LSB USB MODE Cobra 148 GTL other AM SSB equipment, modify the sketch.
// 3.STEP 1Hz,10Hz,100Hz,1KHz,10KHz,100KHz,1MHz
// 4.CALIBRATION CLK1 BFO,IF TEMPORARY ADJUSTMENT AM,LSB,USB,OFFSET 
// 5.S-METER FULL SCALE +30dB Cobra 148 GTL. 
////////////////////////////////////////////////////////////////////////    
//Libraries. BIBLIOTECAS             Links das Bibliotecas
#include <si5351.h>                //https://github.com/etherkit/Si5351Arduino/releases/tag/v1.1.2
#include <SPI.h>
#include <Wire.h>                  //IDE Standard
#include <Adafruit_SSD1306.h>      //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306
#include <Rotary.h>                //Ben  Buxton https://github.com/brianlow/Rotary
#include <Adafruit_GFX.h>          //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library
//----------------------------------------------------------------------------------------------------
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); //Best resolution for my OLED SSD1306 0.96.
Si5351 si5351;  //Si5351 I2C Address 0x60
Rotary r = Rotary(3, 2);

#define F_MIN       1000000UL
#define F_MAX       16000000000UL 
#define ENCODER_A        2       // Encoder pin A                     
#define ENCODER_B        3       // Encoder pin B
#define ENCODER_BTN      4
#define USB_PIN          6
#define LSB_PIN          7
#define AM_PIN           8
#define PIN_S_METER_IN   A0

int lsbstate = 0;
int amstate = 0;
int usbstate = 0;
const int sampleWindow = 50;          // Sample window width in mS (50 mS = 20Hz)
const int sampleWindowPeak = 200;
int lastPeak;
unsigned int sample;

volatile int32_t AM  = 780000000ULL;
volatile int32_t LSB = 779850000ULL;   //LSB = IF - 1500Hz
volatile int32_t USB = 780150000ULL;   //USB = IF + 1500Hz
volatile int32_t bfo = 780000000ULL;   //Intermediary frequency IF
volatile int32_t vfo = 2696500000ULL    / SI5351_FREQ_MULT; // frequency display initialization
volatile uint32_t radix = 10000;       //start step size - change to suit
boolean changed_f = 0;
String tbfo = "AM";
boolean setbfo = false; // Press the ENCODER for temporary BFO tuning. Pressione sintonizar o BFO temporario.
int enc_cnt = 0;        // Encoder count
int  act_clk = 0, disp_txt = 0;

#define IF_Offset       //Output is the display plus or minus the bfo frequency

/**************************************/
/* Interrupt service routine for      */
/* encoder frequency change           */
/**************************************/
ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result == DIR_CW) 
  enc_cnt = +1;
  else if (result == DIR_CCW)
  enc_cnt = -1;
  if (setbfo)
    set_bfo_freq();
  else
    set_frequency();   
 }

/**************************************/
/* Change the frequencies             */
/**************************************/
void set_frequency()
{
  vfo += enc_cnt * radix;
  enc_cnt =0;
  changed_f = 1;
}
void set_bfo_freq()
{
  bfo += enc_cnt * radix;
  //bfo *= enc_cnt * radix;    //BFO ao girar encoder zera FI 8.000MHz, VFO conversão direta 26.965MHz.
  enc_cnt = 0;
  changed_f = 1;
}   
/**************************************/
/* Read the button with debouncing    */
/**************************************/
boolean get_button()
{
  if (!digitalRead(ENCODER_BTN))
  {
  delay(20);
  if (!digitalRead(ENCODER_BTN))
  {
  long strttime=millis();
  while (!digitalRead(ENCODER_BTN));
  if((millis() - strttime) > 500)    // check if it was a long press
  {                
  setbfo = !setbfo;   // Pressing ENCODER will set the temporary BFO setting.       
  Serial.println(bfo);
  changed_f = 1;
  return 0;        
  }
  else
  return 1;
  }
 }
  return 0;
}

/**************************************/
/* Displays the frequency             */
/**************************************/
void display_frequency()
 //display.setTextSize(2);
 //display.setCursor(2,12);
  char LCDstr[12];
  char Mhz[5], Herz[12];
  int p, q;
  unsigned long freq;
  
  switch (act_clk)
  {
    case 0:                               
      freq = vfo;
      break;
    case 1:                                
      freq = bfo;
      break;
  }
  
  Herz[1] = '\0';                         // empty arry
  sprintf(LCDstr, "%ld", freq);           // convert freq to string
  p = strlen(LCDstr);                     // determine length

  strncpy(Mhz, LCDstr, (p - 6));          // get MHz digits (1-3)
  q = p - 6;
  Mhz[q] = '\0';                          // end with null character
  strcpy(Herz, LCDstr);                   // get Herz digits (6)
  strcpy(LCDstr + q, Herz + (q - 1));     // copy into LCDstr
  LCDstr[q] = '.';                        // decimal point

  // MODE CIMA INICIAL ESQUERDO DISPLAY.
  display.clearDisplay();
  display.setTextSize(1);                  // Fonte tamanho letras caracteres na tela. 
  display.setTextColor(WHITE);  
  display.drawLine(0, 8, 0, 39, WHITE);      // Linha vertical descida     
  display.drawLine(127, 8, 127, 39, WHITE);  // Linha vertical descida.                        
  display.setTextSize(1);                    // Fonte tamanho MODE letras caracteres display. 
  display.setTextColor(WHITE);
  display.setCursor(4,0);                     // Posição MODE na tela.
  display.drawLine(0, 8, 127, 8, WHITE);      // Linha divisória acima frequência.
  display.print("MODE= ");                    // Imprime nome na tela.  
  display.print(tbfo);
  display.setCursor(5,30);                   // Posição inicial BFO na tela.  
  display.drawLine(0, 39, 127, 39, WHITE);   // Linha divisória abaixo frequência.
  display.print("BFO = ");                   //Imprime nome na tela.  
  display.print(bfo);    
  display.setTextSize(2);       // Tamanho da fonte caracteres frequência.
  display.setCursor(5, 12);     // Posição freqência no display
  display.println(LCDstr);
  display_settings();
 }  
/**************************************/
/* Displays step, mode and version    */
/**************************************/
////////////////////////////////////////
//            S/METER                 //
////////////////////////////////////////
void display_settings()
{
  unsigned long startMillis = millis();                  // Start of sample window. Início da janela de amostra
  float peakToPeak =    0;                               // peak-to-peak level. nível pico a pico.
  unsigned int signalMax = 0;                            //minimum value. valor mínimo
  unsigned int signalMin = 1023;                         //maximum value. valor máximo

  // collect data for 3000 mS
  while (millis() - startMillis < sampleWindow)
  {
    sample = analogRead(A0);                            //Get reading from microphone. Obtenha a leitura do microfone
    if (sample < 1023)                                  // Doss out spurious readings. Descartar leituras espúrias.
    {
      if (sample > signalMax)
      {
        signalMax = sample;                           // save just the max levels. Salve apenas os níveis máximos.
      }
      else if (sample < signalMin)
      {
        signalMin = sample;                          // save just the min levels. Salve apenas os níveis mínimos.
      }
    }
  }

  peakToPeak = signalMax - signalMin;      // max - min = peak-peak amplitude. Máximo - mínimo = amplitude pico a pico
  float db = map(peakToPeak, 80 , 1023, 50,  550 ); //calibrate for deciBels. Calibrar para decibéis

  for (int x = 5; x < 114; x = x + 10) {  //draw scale. Desenhar escala
  display.drawLine(x, 55, x, 52, WHITE);
  }
  //display.drawRect(0, 25, 125, 9, WHITE);
  display.drawRect(0, 55, 125, 9, WHITE); //draw outline of bar graph. Desenhe o esboço de um gráfico de barras.
  int r = map(db, 50, 550, 1, 127);       //set bar graph for width of screen. Defina o gráfico de barras para a largura da tela.
  display.fillRect(1, 56, r, 7, WHITE);   //draw bar graph with a width of r. Desenhe um gráfico de barras com largura r

  display.fillRect(lastPeak - 10, 56, 2, 7, WHITE);

  if  (r > lastPeak)
    lastPeak = r;
  else
  lastPeak = lastPeak - 5;

/**************************************/
/* Displays the frequency change step */
/**************************************/    
  //STEP CIMA LADO DIREITO DISPLAY.
  display.setTextSize(1);
  display.setCursor(65,0);
  display.print(F("TS=")); // STEP lado direito cima display.
  switch (radix)
  {
    case 1:
      display.println(F("   1 Hz"));
      break;
    case 10:
      display.println(F("  10 Hz"));
      break;
    case 100:
      display.println(F(" 100 Hz"));
      break;
    case 1000:
      display.println(F("  1 kHz"));
      break;
    case 10000:
      display.println(F(" 10 kHz"));
      break;
    case 100000:
      display.println(F("100 kHz"));
      break;
    case 1000000:
      display.println(F("  1 MHz"));
      break;      
}
  display.setCursor(1, 43);                 // Posição escala S/Meter na tela.
  display.setTextSize(1);                   // Tamanho fonte números caracteres S/Meter na tela.
  display.println("SIG 1.3.5.7.9...+30dB"); // Escala S/Meter Cobra 148 GTL.
  //display.println("S1 3 5 9  20  40  +60");
  display.display();
  display.clearDisplay();   
}
/**************************************/
/*            S E T U P               */
/**************************************/
void setup() 
{   
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.display();

  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(USB_PIN, INPUT_PULLUP);
  pinMode(LSB_PIN, INPUT_PULLUP);
  pinMode(AM_PIN, INPUT_PULLUP);
  
  // Initial text Cobra 148 GTL or other equipment display.
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(9,10);
  display.println("Cobra 148");
  display.setCursor(47,40);
  display.print("GTL");
  display.display();
  delay(2000);
  display.clearDisplay();
   
  //initialize the Si5351  
  si5351.set_correction(18000); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  si5351.init(SI5351_CRYSTAL_LOAD_8PF,0); //If you're using a 27Mhz crystal, put in 27000000 instead of 0 
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  // Set CLK0 to output the starting "vfo" frequency as set above by vfo = ?
    
#ifdef IF_Offset 
  //Serial.println((long)((vfo * SI5351_FREQ_MULT) - bfo) * -1);
  si5351.set_freq(((vfo * SI5351_FREQ_MULT) + bfo), SI5351_PLL_FIXED, SI5351_CLK0);    
  volatile uint32_t vfoT =((vfo * SI5351_FREQ_MULT) - bfo);
  tbfo = "AM";
     
  //Set CLK1 to output bfo frequency
  si5351.set_freq( bfo,0, SI5351_CLK1);  
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_6MA);
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_4MA);  

#endif

  pinMode(ENCODER_BTN, INPUT_PULLUP);
  PCICR |= (1 << PCIE2);           // Enabled pin change interrupt for the encoder
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);                    
  sei();  
  display_frequency();  // Update the display
}
/**************************************/
/*             L O O P                */
/**************************************/
void loop()
{       
  // Update the display if the frequency has been changed
   display_frequency();
    
#ifdef IF_Offset
        
    //you can also subtract the bfo to suit your needs
    //si5351.set_freq(((vfo * SI5351_FREQ_MULT) - bfo), SI5351_PLL_FIXED, SI5351_CLK0); // VFO subtrai á IF
    
    si5351.set_freq(( vfo * SI5351_FREQ_MULT) + bfo, SI5351_PLL_FIXED, SI5351_CLK0);    // VFO soma á IF
    si5351.set_freq( bfo,0, SI5351_CLK1);   // BFO CLK1 
    
    si5351.output_enable(SI5351_CLK0, 1); // Enable CLK0                 //1 - Enable / 0 - Disable CLK
    si5351.output_enable(SI5351_CLK1, 1); // Enable CLK1
#endif   
   {
    usbstate = digitalRead(USB_PIN);
    if (usbstate == LOW) {
      //USB
      bfo = USB;
      tbfo = "USB";
    }
    amstate = digitalRead(AM_PIN);
    if (amstate == LOW) {
      //AM
      bfo = AM;
      tbfo = "AM";
    }
    lsbstate = digitalRead(LSB_PIN);
    if (lsbstate == LOW) {
      // LSB
      bfo = LSB;
      tbfo = "LSB";
    }                 
  } 
  // Button press changes the frequency change step for 1 Hz steps 
  if (get_button()) 
  {  
    switch (radix)
    {
      case 1:
        radix = 10;
        break;
      case 10:
        radix = 100;
        break;
      case 100:
        radix = 1000;
        break;
      case 1000:
        radix = 10000;
        break;
      case 10000:
        radix = 100000;
        break;
      case 100000:
        radix = 1000000;
        break;  
      case 1000000:
        radix = 1;
        break; }
    }     
    display_frequency();   
}   

Abra seu Arduino IDE na área de trabalho e delete tudo. Copie todo programa esboço e cole dentro do Arduino IDE. Tenham ás bibliotecas instaladas, e lembre-se que muitas bibliotecas para o mesmo arquivo pode causar conflitos e provocar erros na compilação. 
Segundo sketch abaixo.
//**********************************************************************************************************/
// Modifications and updates for si5351 Arduino Nano, Pro Mini Atmega 328P. Original by GE75A Julio
// and shared on YouTube by CT7API Manuel Ferreira in the version with 128 x 64 OLED. Original LCD version.
// This entire program is taken from Jason Mildrum, NT7S and Przemek Sadowski, SQ9NJE. There is not enough 
// original code written by me to make it worth mentioning. http://nt7s.com/ http://sq9nje.pl/
// http://ak2b.blogspot.com/ Last update BFO CLK1 by Waldir Cardoso Blog:
// https://projetosetransceptores.blogspot.com/2026/04/dds-vfo-si5351-oled-cobra-148gtl-am-lsb.html
// Updated for S/Meter on 10/04/2026 by Waldir Cardoso. Brasil, Bahia.
//---------------------------------------------------------------------------------
// Function
// 1.VFO CLK0 34 Mhz AM LSB USB MODE Cobra 148 GTL other AM SSB equipment, modify the sketch.
// 2.BFO CLK1 BFO FI 7.800 Khz AM LSB USB MODE Cobra 148 GTL other AM SSB equipment, modify the sketch.
// 3.STEP 1Hz,10Hz,100Hz,1KHz,10KHz,100KHz,1MHz
// 4.CALIBRATION CLK1 BFO,IF TEMPORARY ADJUSTMENT AM,LSB,USB,OFFSET 
// 5.S-METER FULL SCALE +30dB Cobra 148 GTL.
////////////////////////////////////////////////////////////////////////    
//Libraries. Bibliotecas.                Links das Bibliotecas
#include <si5351.h>                //https://github.com/etherkit/Si5351Arduino/releases/tag/v1.1.2
#include <SPI.h>
#include <Wire.h>                  //IDE Standard
#include <Adafruit_SSD1306.h>      //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306
#include <Rotary.h>                //Ben  Buxton https://github.com/brianlow/Rotary
#include <Adafruit_GFX.h>          //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library
//----------------------------------------------------------------------------------------------------
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); //Best resolution for my OLED SSD1306 0.96.
Si5351 si5351;  //Si5351 I2C Address 0x60
Rotary r = Rotary(3, 2);

#define F_MIN       100000000UL
#define F_MAX       16000000000UL
#define ENCODER_A        2       // Encoder pin A                     
#define ENCODER_B        3       // Encoder pin B
#define ENCODER_BTN      4
#define USB_PIN          6       // Mode USB
#define LSB_PIN          7       // Mode LSB
#define AM_PIN           8       // Mode AM
#define PIN_S_METER_IN   A0      // Pino entrada S/Meter

int lsbstate = 0;
int amstate = 0;
int usbstate = 0;
const int sampleWindow = 50;           // Sample window width in mS (50 mS = 20Hz)
const int sampleWindowPeak = 200;
int lastPeak;
unsigned int sample;

volatile int32_t AM  = 780000000ULL;
volatile int32_t LSB = 779850000ULL;   //LSB = IF - 1500Hz
volatile int32_t USB = 780150000ULL;   //USB = IF + 1500Hz
volatile int32_t bfo = 780000000ULL;   //Intermediary frequency IF
volatile int32_t vfo = 2696500000ULL    / SI5351_FREQ_MULT; // frequency display initialization
volatile uint32_t radix = 10000;       //start step size - change to suit
boolean changed_f = 0;
String tbfo = "AM";
boolean setbfo = false;              // Press the ENCODER for temporary BFO tuning. Pressione sintonizar o BFO temporario.
int enc_cnt = 0;                     // Encoder count
int  act_clk = 0, disp_txt = 0;      // 2 byte.

#define IF_Offset       //Output is the display plus or minus the bfo frequency

/**************************************/
/* Interrupt service routine for      */
/* encoder frequency change           */
/**************************************/
ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result == DIR_CW) 
  enc_cnt = +1;
  else if (result == DIR_CCW)
  enc_cnt = -1;
  if (setbfo)
    set_bfo_freq();
  else
  set_frequency();   
}
/**************************************/
/* Change the frequencies             */
/**************************************/
void set_frequency()
{
  vfo += enc_cnt * radix;
  enc_cnt =0;
  changed_f = 1;
}
void set_bfo_freq()
{
  bfo += enc_cnt * radix;
  //bfo *= enc_cnt * radix;    //BFO ao girar encoder zera FI 8.000MHz, VFO conversão direta 26.965MHz.
  enc_cnt = 0;
  changed_f = 1;
/**************************************/
/* Read the button with debouncing    */
/**************************************/
boolean get_button()
{
  if (!digitalRead(ENCODER_BTN))
  {
  delay(20);
  if (!digitalRead(ENCODER_BTN))
  {
  long strttime=millis();
  while (!digitalRead(ENCODER_BTN));
  if((millis() - strttime) > 500)    // check if it was a long press
  {                
  setbfo = !setbfo;   // Pressing ENCODER will set the temporary BFO setting.       
  Serial.println(bfo);
  changed_f = 1;
  return 0;        
  }
  else
  return 1;
  }
 }
  return 0;
}
/**************************************/
/* Displays the frequency             */
/**************************************/
void display_frequency()
{  
  char LCDstr[12];
  char Mhz[5], Herz[12];
  int p, q;
  unsigned long freq;
  switch (act_clk)
  {
    case 0:                               
      freq = vfo;
      break;
    case 1:                                
      freq = bfo;
      break;
  }
  
  Herz[1] = '\0';                         // empty arry

  sprintf(LCDstr, "%ld", freq);           // convert freq to string
  p = strlen(LCDstr);                     // determine length

  strncpy(Mhz, LCDstr, (p - 6));          // get MHz digits (1-3)
  q = p - 6;
  Mhz[q] = '\0';                          // end with null character
  strcpy(Herz, LCDstr);                   // get Herz digits (6)
  strcpy(LCDstr + q, Herz + (q - 1));     // copy into LCDstr
  LCDstr[q] = '.';                        // decimal point

  // AM LSB USB AO LADO BFO DISPLAY.
  display.clearDisplay();
  display.setTextSize(1);                    // Fonte tamanho letras caracteres na tela. 
  display.setTextColor(WHITE);  
  display.drawLine(0, 8, 0, 39, WHITE);      // Linha vertical descida     
  display.drawLine(127, 8, 127, 39, WHITE);  // Linha vertical descida.                        
  display.setTextSize(1);                    // Fonte tamanho MODE letras caracteres display. 
  display.setTextColor(WHITE);
  display.setCursor(105,30);                 // Posição MODE na tela.
  //display.setCursor(4,0);                     // Posição MODE na tela.
  display.drawLine(0, 8, 127, 8, WHITE);     // Linha divisória acima frequência.
  //display.print("MODE= ");                    // Imprime nome na tela.  
  display.print(tbfo);
  display.setCursor(5,30);                   // Posição inicial BFO na tela.    
  display.drawLine(0, 39, 127, 39, WHITE);   // Linha divisória abaixo frequência.
  display.print("BFO = ");                   //Imprime nome na tela.  
  display.print(bfo);    
  display.setTextSize(2);       // Tamanho da fonte caracteres frequência.
  display.setCursor(5, 12);     // Posição caracteres freqência no display. 
  display.println(LCDstr);
  display_settings();
 }   
/**************************************/
/* Displays step, mode and version    */
/**************************************/
/**************************************/
/*            S/METER                 */
/**************************************/
void display_settings()
{
  unsigned long startMillis = millis();                  // Start of sample window. Início da janela de amostra
  float peakToPeak =    0;                               // peak-to-peak level. nível pico a pico.
  unsigned int signalMax = 0;                            //minimum value. valor mínimo
  unsigned int signalMin = 1023;                         //maximum value. valor máximo

  // collect data for 3000 mS
  while (millis() - startMillis < sampleWindow)
  {
    sample = analogRead(A0);                            //Get reading from microphone. Obtenha a leitura do microfone
    if (sample < 1023)                                  // Doss out spurious readings. Descartar leituras espúrias.
    {
      if (sample > signalMax)
      {
        signalMax = sample;                           // save just the max levels. Salve apenas os níveis máximos.
      }
      else if (sample < signalMin)
      {
        signalMin = sample;                          // save just the min levels. Salve apenas os níveis mínimos.
      }
    }
  }
  peakToPeak = signalMax - signalMin;      // max - min = peak-peak amplitude. Máximo - mínimo = amplitude pico a pico
  float db = map(peakToPeak, 80 , 1023, 50,  550 ); //calibrate for deciBels. Calibrar para decibéis

  //for (int x = 5; x < 114; x = x + 8) {
  for (int x = 5; x < 114; x = x + 10) {  //draw scale. Desenhar escala
  display.drawLine(x, 55, x, 52, WHITE);
  }
  //display.drawRect(0, 25, 125, 9, WHITE);
  display.drawRect(0, 55, 125, 9, WHITE); //draw outline of bar graph. Desenhe o esboço de um gráfico de barras.
  int r = map(db, 50, 550, 1, 127);       //set bar graph for width of screen. Defina o gráfico de barras para a largura da tela.
  display.fillRect(1, 56, r, 7, WHITE);   //draw bar graph with a width of r. Desenhe um gráfico de barras com largura r

  display.fillRect(lastPeak - 10, 56, 2, 7, WHITE);

  if  (r > lastPeak)
    lastPeak = r;
  else
  lastPeak = lastPeak - 5;

/**************************************/
/* Displays the frequency change step */
/**************************************/    
  //STEP CIMA LADO ESQUERDO DISPLAY.
  display.setTextSize(1);
  display.setCursor(4,0);
  //display.setCursor(65,0);
  display.print(F("STEP=")); // STEP lado esquerdo cima display.
  //display.print(F("TS=")); // STEP lado direito cima display.
  
  switch (radix)
  {
    case 1:
      display.println(F("   1 Hz"));
      break;
    case 10:
      display.println(F("  10 Hz"));
      break;
    case 100:
      display.println(F(" 100 Hz"));
      break;
    case 1000:
      display.println(F("  1 kHz"));
      break;
    case 10000:
      display.println(F(" 10 kHz"));
      break;
    case 100000:
      display.println(F("100 kHz"));
      break;
    case 1000000:
      display.println(F("  1 MHz"));
      break;      
}  
  display.setCursor(1, 43);    // Posição escala S/Meter na tela.
  display.setTextSize(1);     // Tamanho fonte números caracteres S/Meter na tela.
  display.println  ("SIG 1.3.5.7.9...+30dB"); // Escala S/Meter Cobra 148 GTL.
  //display.println("S1 3 5 9  20  40  +60");
  display.display();
  display.clearDisplay();   
}
/**************************************/
/*            S E T U P               */
/**************************************/
void setup() 
{   
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.display();

  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(USB_PIN, INPUT_PULLUP);
  pinMode(LSB_PIN, INPUT_PULLUP);
  pinMode(AM_PIN, INPUT_PULLUP);
  
  // Initial text Cobra 148 GTL or other equipment display.
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(9,10);
  display.println("Cobra 148");
  display.setCursor(47,40);
  display.print("GTL");
  display.display();
  delay(2000);
  display.clearDisplay();
   
  //initialize the Si5351    
  si5351.set_correction(18000); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  si5351.init(SI5351_CRYSTAL_LOAD_8PF,0); //If you're using a 27Mhz crystal, put in 27000000 instead of 0 
  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  // Set CLK0 to output the starting "vfo" frequency as set above by vfo = ?
    
#ifdef IF_Offset 
  //Serial.println((long)((vfo * SI5351_FREQ_MULT) - bfo) * -1);
  si5351.set_freq(((vfo * SI5351_FREQ_MULT) + bfo), SI5351_PLL_FIXED, SI5351_CLK0);    
  volatile uint32_t vfoT =((vfo * SI5351_FREQ_MULT) - bfo);
  tbfo = "AM";
       
  //Set CLK1 to output bfo frequency
  si5351.set_freq( bfo,0, SI5351_CLK1);  
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_6MA);
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_4MA);  

#endif

  pinMode(ENCODER_BTN, INPUT_PULLUP);
  PCICR |= (1 << PCIE2);           // Enabled pin change interrupt for the encoder
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);                    
  sei();  
  display_frequency();  // Update the display
}
/**************************************/
/*             L O O P                */
/**************************************/
void loop()
{       
  // Update the display if the frequency has been changed
  display_frequency();
 
#ifdef IF_Offset
             
    //you can also subtract the bfo to suit your needs
    //si5351.set_freq(((vfo * SI5351_FREQ_MULT) - bfo), SI5351_PLL_FIXED, SI5351_CLK0); // VFO subtrai á IF
    
    si5351.set_freq(( vfo * SI5351_FREQ_MULT) + bfo, SI5351_PLL_FIXED, SI5351_CLK0);    // VFO soma á IF
    si5351.set_freq( bfo,0, SI5351_CLK1);   // BFO CLK1 
    
    si5351.output_enable(SI5351_CLK0, 1); // Enable CLK0                 //1 - Enable / 0 - Disable CLK
    si5351.output_enable(SI5351_CLK1, 1); // Enable CLK1
#endif   
   {
    usbstate = digitalRead(USB_PIN);
    if (usbstate == LOW) {
      //USB
      bfo = USB;
      tbfo = "USB";
    }
    amstate = digitalRead(AM_PIN);
    if (amstate == LOW) {
      //AM
      bfo = AM;
      tbfo = "AM";
    }
    lsbstate = digitalRead(LSB_PIN);
    if (lsbstate == LOW) {
      // LSB
      bfo = LSB;
      tbfo = "LSB";
    }                 
  } 
  // Button press changes the frequency change step for 1 Hz steps 
  if (get_button()) 
  {  
    switch (radix)
    {
      case 1:
        radix = 10;
        break;
      case 10:
        radix = 100;
        break;
      case 100:
        radix = 1000;
        break;
      case 1000:
        radix = 10000;
        break;
      case 10000:
        radix = 100000;
        break;
      case 100000:
        radix = 1000000;
        break;  
      case 1000000:
        radix = 1;
        break; }
    } 
    display_frequency();   
}  

Nenhum comentário:

Postar um comentário

Façam seus comentários com experiências no projeto. Ou de sua opinião.