terça-feira, 30 de junho de 2026

10kHz 225MHz Júlio Cesar AM, LSB, USB Cobra 148 GTL.

Vocês, que curte e gosta dos projetos do blog, por gentileza olhem às propagandas e click para maiores detalhes no que interessar, desta forma vocês estarão ajudando o blog. Muito obrigado por acessar e ajudar o blog, conto com vocês muito agradecido.
Olá pessoal, Continuando o prometido no vídeo mês passado. Publico aqui e no vídeo YouTube mais algumas implementações, no mesmo sketch do Sr. Júlio Cesar, meus agradecimentos pelo código livre que foi publicado em sua página 10 kHz a 225 MHz versão 2 e diversas páginas sendo o projeto de DDS VFO gerador RF mais copiado e modificado desde 2021. Ás modificações que implementei são para nós PX, Radioamadores montadores de transceptores, técnicos em modificações de equipamentos com PLL ou VFO analógico. O que conseguir: 1- Modo AM, LSB, USB com FI 7.800 kHz Cobra 148 GTL. Adicionei memória total frequência por banda. Ou seja última frequência selecionada em cada banda serão memorizadas mesmo ao mudar de banda ou desligar o rádio, tipo transceptores comerciais. Clarificador Tune Fine VFO 8 kHz direita e 8 kHz esquerda ajustável no sketch. Bem como já estava com mão na massa continuei a fazer modificações para implementar MENU e funções como: Scanner. Ajuste de VFO com STEP. Ajuste de BFO FI CLK1, entre outras atualizações que fiz em todo estes 2 meses. Mas não estou satisfeito com ás novas atualizações do clarificador e MENU. Faltam alguns ajustes. Não é fácil acertar no que não se ver, fiz este mês 30 ou mais gravações no meu Arduino ATmega 328P que ainda está aguentando firme todo este ano de gravações entre erros e acertos. Pessoal vocês que tem interesse em aprender a modificar qualquer projeto, seja um simples receptor, transmissor, transverter, Sketch de DDS VFO, ou seja, quais quer projetos que você pensar em fazer uma modificação para melhorar, você tem que ter na sua mente que vai conseguir fazer, nunca deixe o pensamento negativo tomar conta do seu interesse que está pensando em modificar para melhor. Não sou nenhum cérebro inteligente nem tenho QI superior a ninguém, pelo contrário eu até meus 12 anos de idade pensava que era um menos inteligente "Burro", achava que meu irmão era o inteligente, e tudo que eu queria saber perguntava a ele. Isso porque ele é mais velho que eu um ano. Depois comecei a ver a realidade da vida e do cérebro humano, ai fui me aprimorando no que eu tinha vontade de fazer e modificar. Quando tinha dinheiro comprava uma revista de eletrônica em esquema de amplificador de áudio e adicionava um pré amplificador de outra revista, isso eu desenhava o esquema em um caderno simples de páginas de linhas. Sempre estava desenhando esquemas. A pessoal, queria poder contar o muito que já fiz e o quanto já sofri para ser o que sou, eu fui como um monte de barro que é amassado para depois virar um belo vazo que vai decorar uma linda sala. Mas hoje vocês tem a internet WEB, revistas de graça, pessoas que fazem e dá dicas em blogs, vídeos verdadeiros no YouTube. Na minha época não tinha nada disso, por isso aproveitem o máximo possível pois um dia poderá ser tarde. Bem voltando a atualidade do nosso sketch, eu vou postar o sketch prometido no vídeo com os modos AM, LSB, USB já pronto para ser colocado no Cobra 148 GTL, espero que se algum técnico quiser e tiver interesse em colocar este projeto do Sr. Júlio Cesar e modificado por mim em transceptores Cobra 148 GTL ou outros equipamentos por favor façam um vídeo ou mande um comentário aqui ou no meu canal do YouTube para ver como ficou na prática o DDS VFO atuando no transceptor. Ficarei grato se também dissesse o criador do DDS VFO em funcionamento. Vejam muitas fotos e outras que no começo do mês não tirei, como é fazer: Ajustar ás posições dos caracteres, desenvolver, desenhar o esquema e muito mais. 
Vejam que faltam o 0 zero dos 100Hz, eu já tinha depois de muitos erros e gravações os modos: AM, LSB, USB.
Vejam a frequência de CLK1.
Vejam que mesmo em LSB não tem o 500Hz.
 
Olhem no frequencimetro frequência de CLK1 em LSB.
Mesma coisa faltam os Hz. e frequência de CLK1.
Frequência do modo USB.
Abaixo observem a data na foto, coloquei o clarificador e os Hz de CLK1.
O número 14 de CL tinha que tá na frequência do VFO.
Vejam que na foto abaixo está acontecendo a mesma coisa em CL.
Tela inicial agora com clarificador em RX e TX no VFO.
Conseguir colocar os Hz na tela do display só com um dígito Centézimo.
Agora parece que está ajustado. Vejam em CL: 23 é o mesmo que o Hz da frequência do VFO.
Vejam que aparece IF os Hz 500 de CLK1 LSB.
Vejam a frequência saída de CLK0 com FI do Cobra 148 GTL canal 1 26.965.00MHz LSB.
Também com os 500 Hz de FI CLK1, só com a centena 5.
Vejam a frequência saída de CLK0 com FI do Cobra 148 GTL canal 1 26.965.00MHz USB.
Vejam que CL está bem próximo a IF.
Vejam que agora com sinal de - para quando o clarificador for para sentido negativo esquerdo.
O z está sobrepondo o I, não pode ser assim.
Acho que assim ficou melhor.
Agora com -8kHz Acho que está bom.
 
Vejam a data da foto. Estou tentando adicionar um MENU.
Tentando adicionar um Scanner para correr ás frequências.

Ainda falta muitas funções.
Ficou bom assim mas faltam ajuste e mais tempo.
Vou tentar colocar os Hz tal como no display em CLK1.
Ainda ter erros e muitos.
Vamos adicionar mais alguns recursos no Scanner.
Agora com indicador contador de 4 dígitos, banda, sinal.

Vou tentar colocar um limite para o Scanner parar pelo S/Meter. 
Esquema elétrico DDS VFO AM, LSB, USB Cobra 148 GTL.
Abaixo sketch DDS VFO AM, LSB, USB, memória total ao desligar, botão de bandas + e - ou sobe e desce. O sketch está com todas explicações comentadas em português. Sucesso na montagem. 
Selecione todo sketch, copie e cole. Abra Arduino IDE vá em "Arquivo" depois "Novo", ou ícone ao lado da seta para "Carregar ou Compilar, abra um novo delete todas ás linhas e cole este sketch, renomeei com final .ino se preferir e salve em uma pasta. adicione todas ás bibliotecas. Lembre-se que muitas bibliotecas para o mesmo arquivo pode causar conflitos, observe a porta USB entre outras preferencias poderá provocar erros na compilação. 
 Sketch abaixo. 

/**********************************************************************************************************
  10kHz to 225MHz VFO / RF Generator with Si5351 and Arduino Nano, with Intermediate Frequency (IF) offset
  (+ or -), RX/TX Selector for QRP Transceivers, Band Presets and Bargraph S-Meter. See the schematics for
  wiring and README.txt for details. By J. CesarSound - ver 2.0 - Feb/2021.
***********************************************************************************************************/
// ============================================================================
// TRANSCEPTOR COBRA 148 GTL - CONTROLE DIGITAL COM Si5351
// ============================================================================
// Sketch original: 10kHz a 225MHz
// Autor original: Júlio Cesar  Fevereiro 2021
// Modificado por: Waldir Cardoso   Junho 2026
// Blog: https://projetosetransceptores.blogspot.com/
// ============================================================================
// FUNCIONALIDADES PRINCIPAIS:
// ============================================================================
// - Frequência: 10 kHz até 225 MHz (cobertura HF/VHF/UHF completa)
// - CLK0 (VFO): Oscilador local para recepção
//   Exemplo: CLK0 Canal 1 PX (CB) AM = 34.765 MHz (26.965 + 7.800 MHz)
// - CLK1 (BFO): Oscilador de frequência intermediária (FI)
//   FI padrão: AM (7.8000 Hz) LSB (7.7985 MHz) USB (7.8015 MHz) (ajustável no sketch)
// - Modos de operação: AM, LSB, USB (teclas físicas separadas)
// - Encoder STEP ajustável: 1Hz, 10Hz, 1kHz, 10kHz, 100kHz, 1MHz, 1.5MHz, 2MHz
// - Bandas: 21 bandas pré-programadas (GEN, MW, 160m a 1m)
// - Botões: BAND+ (D10) sobe banda, BAND- (A1) desce banda
// - S-Meter: Escala estilo Cobra 148 GTL (SIG 1-9 +30 dB)
//   Com suavização e peak hold para melhor visualização
// - EEPROM: Memória total - salva frequência, banda, step e BFO ao desligar
//   Ao ligar, retorna exatamente na última configuração usada
// ============================================================================
// PINOS UTILIZADOS:
// ============================================================================
// D2, D3: Encoder rotativo (controle de frequência)
// A0: Botão do encoder (STEP)
// A1: Botão BAND- (desce banda)
// D10: Botão BAND+ (sobe banda)
// A2: Chave RX/TX
// D6, D7, D8: Teclas de seleção de modo (USB, LSB, AM)
// A3: Entrada do S-Meter (sensor de sinal)
// ============================================================================
// BIBLIOTECAS NECESSÁRIAS
// ============================================================================
#include <EEPROM.h>           // Memória EEPROM para salvar configurações
#include <Wire.h>             // Comunicação I2C (display e Si5351)
#include <Rotary.h>           // Controle do encoder rotativo
#include <SPI.h>              // Comunicação SPI
#include "PU2REO_Si5351Lite.h" // Gerador de frequência Si5351
#include <Adafruit_GFX.h>     // Biblioteca gráfica para display
#include <Adafruit_SSD1306.h> // Driver para display OLED SSD1306

// ============================================================================
// ENDEREÇOS DA MEMÓRIA EEPROM (onde os dados são salvos permanentemente)
// ============================================================================
#define EEPROM_FREQ        0    // Endereço 0: Frequência atual
#define EEPROM_BAND        10   // Endereço 10: Banda atual
#define EEPROM_STEP        20   // Endereço 20: Step (passo) atual
#define EEPROM_BAND_FREQ   100  // Endereço 100: Frequências das bandas

// ============================================================================
// FREQUÊNCIAS DO BFO (Beat Frequency Oscillator) para cada modo
// ============================================================================
#define BFO_AM    7800000UL     // BFO para modo AM  (7.800 MHz)
#define BFO_LSB   7798500UL     // BFO para modo LSB (7.7985 MHz)
#define BFO_USB   7801500UL     // BFO para modo USB (7.8015 MHz)

// ============================================================================
// PINOS DE SELEÇÃO DE MODO (AM, LSB, USB)
// ============================================================================
#define USB_PIN   6             // Pino para selecionar modo USB
#define LSB_PIN   7             // Pino para selecionar modo LSB
#define AM_PIN    8             // Pino para selecionar modo AM

// ============================================================================
// CONFIGURAÇÕES GERAIS DO RÁDIO
// ============================================================================
#define BAND_INIT 15            // Banda inicial ao ligar (15 = 11m CB 27MHz)
#define XT_CAL_F  18000         // Fator de calibração do cristal Si5351
#define S_GAIN    303           // Sensibilidade do S-Meter (1.5V máximo)

// ============================================================================
// PINOS DE ENTRADA (BOTÕES E CHAVES)
// ============================================================================
#define tunestep  A0            // Botão do encoder (muda step)
#define band      A1            // Botão BAND+ (sobe banda)
#define rx_tx     A2            // Chave RX/TX (LOW = TX)
#define band_dn   10            // Botão BAND- (desce banda)

// ============================================================================
// CONFIGURAÇÕES DO DISPLAY OLED
// ============================================================================
#define SCREEN_WIDTH 128        // Largura do display em pixels
#define SCREEN_HEIGHT 64        // Altura do display em pixels
#define OLED_RESET     -1       // Pino de reset (não usado)

// ============================================================================
// OBJETOS DAS BIBLIOTECAS
// ============================================================================
Rotary r = Rotary(2, 3);        // Encoder nos pinos 2 e 3
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Display OLED
Si5351 si5351(0x60);            // Si5351 no endereço I2C 0x60

// ============================================================================
// VARIÁVEIS DO S-METER (Medidor de Sinal)
// ============================================================================
const int sMeterPin = A3;       // Pino de entrada do S-Meter
int smoothedSMeter = 0;         // Valor suavizado do S-Meter
int peakHold = 0;               // Valor de pico mantido
unsigned long peakTimer = 0;    // Temporizador do pico

// ============================================================================
// VARIÁVEIS GLOBAIS PRINCIPAIS
// ============================================================================
unsigned long lastSave = 0;     // Último salvamento na EEPROM
unsigned long freq, freqold, fstep; // Frequência atual, anterior e passo
long cal = XT_CAL_F;            // Calibração do Si5351
byte stp, n = 1;                // Step atual e contador do gráfico
byte count;                     // Banda atual (1-21)
bool sts = 0;                   // Status RX/TX (0=RX, 1=TX)
unsigned long bfo = BFO_AM;     // Frequência do BFO atual
byte mode = 0;                  // Modo atual (0=AM, 1=LSB, 2=USB)

// ============================================================================
// INTERRUPÇÃO DO ENCODER (executada quando gira o encoder)
// ============================================================================
ISR(PCINT2_vect) {
  char result = r.process();    // Lê a direção do encoder
  if (result == DIR_CW) set_frequency(1);   // Sentido horário: sobe frequência
  else if (result == DIR_CCW) set_frequency(-1); // Anti-horário: desce
}

// ============================================================================
// FUNÇÃO: Ajusta a frequência conforme direção do encoder
// ============================================================================
void set_frequency(short dir) {
  if (dir == 1) {               // Se girou para cima
    freq = freq + fstep;        // Soma o step à frequência
    if (freq >= 225000000) freq = 225000000; // Limite máximo: 225 MHz
  }
  if (dir == -1) {              // Se girou para baixo
    freq = freq - fstep;        // Subtrai o step da frequência
    if (fstep == 1000000 && freq <= 1000000) freq = 1000000; // Mínimo com step 1MHz
    else if (freq < 10000) freq = 10000; // Limite mínimo: 10 kHz
  }
}

// ============================================================================
// FUNÇÃO: Salva configurações na memória EEPROM
// ============================================================================
void saveMemory() {
  EEPROM.put(EEPROM_FREQ, freq);   // Salva frequência atual
  EEPROM.put(EEPROM_BAND, count);  // Salva banda atual
  EEPROM.put(EEPROM_STEP, stp);    // Salva step atual
}

// ============================================================================
// FUNÇÃO: Carrega configurações da memória EEPROM
// ============================================================================
void loadMemory() {
  EEPROM.get(EEPROM_FREQ, freq);   // Carrega frequência
  EEPROM.get(EEPROM_BAND, count);  // Carrega banda
  EEPROM.get(EEPROM_STEP, stp);    // Carrega step

  // Se frequência inválida, usa banda inicial
  if (freq < 10000 || freq > 225000000) {
    count = BAND_INIT;
    bandpresets();
  }

  // Converte código do step para valor em Hz
  switch (stp) {
    case 1: fstep = 2000000; break;  // 2 MHz
    case 2: fstep = 1; break;        // 1 Hz
    case 3: fstep = 10; break;       // 10 Hz
    case 4: fstep = 1000; break;     // 1 kHz
    case 5: fstep = 10000; break;    // 10 kHz
    case 6: fstep = 100000; break;   // 100 kHz
    case 7: fstep = 1000000; break;  // 1 MHz
    case 8: fstep = 1500000; break;  // 1.5 MHz
    default:
      stp = 5;                       // Padrão: 10 kHz
      fstep = 10000;
      break;
  }
}

// ============================================================================
// FUNÇÃO: Salva frequência da banda atual na EEPROM
// ============================================================================
void saveBandFrequency() {
  int addr = EEPROM_BAND_FREQ + ((count - 1) * sizeof(unsigned long));
  EEPROM.put(addr, freq);
}

// ============================================================================
// FUNÇÃO: Carrega frequência da banda atual da EEPROM
// ============================================================================
bool loadBandFrequency() {
  int addr = EEPROM_BAND_FREQ + ((count - 1) * sizeof(unsigned long));
  unsigned long tempFreq;
  EEPROM.get(addr, tempFreq);
  if (tempFreq >= 10000UL && tempFreq <= 225000000UL) {
    freq = tempFreq;
    return true;
  }
  return false;
}

// ============================================================================
// FUNÇÃO: Lê o modo de operação (AM/LSB/USB) pelos pinos
// ============================================================================
void readMode() {
  if (digitalRead(USB_PIN) == LOW) {
    mode = 2;
    bfo = BFO_USB;
  }
  if (digitalRead(LSB_PIN) == LOW) {
    mode = 1;
    bfo = BFO_LSB;
  }
  if (digitalRead(AM_PIN) == LOW) {
    mode = 0;
    bfo = BFO_AM;
  }
}

// ============================================================================
// FUNÇÃO DE CONFIGURAÇÃO INICIAL (executada uma vez ao ligar)
// ============================================================================
void setup() {
  Wire.begin();                 // Inicia comunicação I2C
  
  // Inicializa display OLED
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.display();

  // Tela inicial de boas-vindas
  display.setTextSize(2); 
  display.setCursor(9, 10);
  display.print(F("Cobra 148"));
  display.setCursor(45, 40);
  display.print(F("GTL"));
  display.display(); 
  delay(2000);

  // Configura pinos dos botões como entrada com pull-up
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(tunestep, INPUT_PULLUP);
  pinMode(band, INPUT_PULLUP);
  pinMode(rx_tx, INPUT_PULLUP);
  pinMode(band_dn, INPUT_PULLUP);
  pinMode(AM_PIN, INPUT_PULLUP);
  pinMode(LSB_PIN, INPUT_PULLUP);
  pinMode(USB_PIN, INPUT_PULLUP);
  
  // Inicializa gerador de frequência Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(cal, SI5351_PLL_INPUT_XO);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);  // CLK0: 8mA (VFO)
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_6MA);  // CLK1: 6mA (BFO)
  si5351.output_enable(SI5351_CLK0, 1);  // Habilita CLK0
  si5351.output_enable(SI5351_CLK1, 1);  // Habilita CLK1
 
  // Configura interrupção do encoder
  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();                      // Habilita interrupções globais
  
  loadMemory();               // Carrega configurações da EEPROM
  
  // Se frequência inválida, usa valores padrão
  if (freq == 0) {
    count = BAND_INIT;
    bandpresets();
    stp = 5;
    setstep();
  }  

// ============================================================================
// FUNÇÃO PRINCIPAL (executada em loop infinito)
// ============================================================================
void loop() {
  readMode();                 // Lê modo de operação (AM/LSB/USB)
  tunegen();                  // Gera frequências no Si5351
   
  // Se frequência mudou, atualiza Si5351
  if (freqold != freq) {
    tunegen();
    freqold = freq;
  }
  
  // Botão STEP do encoder (muda passo de ajuste)
  if (digitalRead(tunestep) == LOW) {
    setstep();
    delay(300);
  }
  
  // Botão BAND+ (sobe banda)
  if (digitalRead(band) == LOW) {
    inc_preset();
    delay(300);
  }
  
  // Botão BAND- (desce banda)
  if (digitalRead(band_dn) == LOW) {
    dec_preset();
    delay(300);
  }
  
  // Lê status RX/TX
  sts = (digitalRead(rx_tx) == LOW) ? 1 : 0;
  
  // Lê valor do S-Meter
  int sMeterVal = analogRead(sMeterPin);

  // Atualiza display completo
  display.clearDisplay();
  displayfreq();              // Mostra frequência
  layout();                   // Mostra layout (STEP, modo, etc)
  updateDisplay(sMeterVal);   // Mostra S-Meter
  display.display();

  // Salva na EEPROM após 5 segundos sem mexer
  if (millis() - lastSave > 5000) {
    saveMemory();
    lastSave = millis();
  }
  delay(50);                  // Delay para estabilidade
}

// ============================================================================
// FUNÇÃO: Gera as frequências no Si5351 (CLK0 = VFO, CLK1 = BFO)
// ============================================================================
void tunegen() {
  long vfoFreq = (long)(freq + bfo);  // VFO = frequência + BFO
  
  si5351.set_freq((uint64_t)vfoFreq * 100ULL, SI5351_CLK0);  // CLK0: VFO
  si5351.set_freq(bfo * 100ULL, SI5351_CLK1);                // CLK1: BFO

  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_6MA);

  si5351.output_enable(SI5351_CLK0, 1);
  si5351.output_enable(SI5351_CLK1, 1);
}

// ============================================================================
// FUNÇÃO: Exibe a frequência no display
// ============================================================================
void displayfreq() {
  unsigned int m = freq / 1000000;           // MHz
  unsigned int k = (freq % 1000000) / 1000;  // kHz
  unsigned int h = (freq % 1000);            // Hz
  
  display.setTextSize(2);
  char buffer[15] = "";
  
  if (m < 1) {
    display.setCursor(41, 1);
    sprintf(buffer, "%003d.%003d", k, h);
  }
  else if (m < 100) {
    display.setCursor(5, 1);
    sprintf(buffer, "%2d.%003d.%003d", m, k, h);
  }
  else if (m >= 100) {
    unsigned int h = (freq % 1000) / 10;
    display.setCursor(5, 1);
    sprintf(buffer, "%2d.%003d.%02d", m, k, h);
  }
  display.print(buffer);
}

// ============================================================================
// FUNÇÃO: Muda o step (passo) de ajuste da frequência
// ============================================================================
void setstep() {
  switch (stp) {
    case 1: stp = 2; fstep = 1; break;        // 2MHz → 1Hz
    case 2: stp = 3; fstep = 10; break;       // 1Hz → 10Hz
    case 3: stp = 4; fstep = 1000; break;     // 10Hz → 1kHz
    case 4: stp = 5; fstep = 10000; break;    // 1kHz → 10kHz
    case 5: stp = 6; fstep = 100000; break;   // 10kHz → 100kHz
    case 6: stp = 7; fstep = 1000000; break;  // 100kHz → 1MHz
    case 7: stp = 8; fstep = 1500000; break;  // 1MHz → 1.5MHz
    case 8: stp = 1; fstep = 2000000; break;  // 1.5MHz → 2MHz
  }
}

// ============================================================================
// FUNÇÃO: Sobe para a próxima banda
// ============================================================================
void inc_preset() {
  saveBandFrequency();        // Salva frequência atual da banda
  count++;
  if (count > 21) count = 1;  // Volta para banda 1 se passou da 21
  if (!loadBandFrequency()) bandpresets();  // Carrega frequência da banda
  saveMemory();
  delay(50);
}

// ============================================================================
// FUNÇÃO: Desce para a banda anterior
// ============================================================================
void dec_preset() {
  saveBandFrequency();        // Salva frequência atual da banda
  if (count <= 1) count = 21; // Volta para banda 21 se estava na 1
  else count--;
  if (!loadBandFrequency()) bandpresets();  // Carrega frequência da banda
  saveMemory();
  delay(50);
}

// ============================================================================
// FUNÇÃO: Define frequências padrão para cada banda
// ============================================================================
void bandpresets() {
  switch (count) {
    case 1: freq = 100000; tunegen(); break;      // 100 kHz (GEN)
    case 2: freq = 800000; break;                 // 800 kHz (MW)
    case 3: freq = 1800000; break;                // 1.800 MHz (160m)
    case 4: freq = 3650000; break;                // 3.650 MHz (80m)
    case 5: freq = 4985000; break;                // 4.985 MHz (60m)
    case 6: freq = 6180000; break;                // 6.180 MHz (49m)
    case 7: freq = 7200000; break;                // 7.200 MHz (40m)
    case 8: freq = 10000000; break;               // 10.000 MHz (31m)
    case 9: freq = 11780000; break;               // 11.780 MHz (25m)
    case 10: freq = 13630000; break;              // 13.630 MHz (22m)
    case 11: freq = 14100000; break;              // 14.100 MHz (20m)
    case 12: freq = 15000000; break;              // 15.000 MHz (19m)
    case 13: freq = 17655000; break;              // 17.655 MHz (16m)
    case 14: freq = 21525000; break;              // 21.525 MHz (13m)
    case 15: freq = 26965000; break;              // 26.965 MHz (11m CB)
    case 16: freq = 28400000; break;              // 28.400 MHz (10m)
    case 17: freq = 50000000; break;              // 50.000 MHz (6m)
    case 18: freq = 100000000; break;             // 100.000 MHz (WFM)
    case 19: freq = 130000000; break;             // 130.000 MHz (AIR)
    case 20: freq = 144000000; break;             // 144.000 MHz (2m)
    case 21: freq = 220000000; break;             // 220.000 MHz (1m)
  }
  si5351.pll_reset(SI5351_PLLA);  // Reset do PLL para estabilidade
  saveMemory();
}

// ============================================================================
// FUNÇÃO: Desenha o layout completo do display (linhas, textos, etc)
// ============================================================================
void layout() {     
  display.setTextColor(WHITE);
  
  // Linhas horizontais e verticais do layout
  display.drawLine(0, 18, 127, 18, WHITE);   // Linha abaixo da frequência
  display.drawLine(0, 42, 127, 42, WHITE);   // Linha abaixo do STEP
  display.drawLine(105, 19, 105, 41, WHITE); // Linha vertical (RX/MHz)
  display.drawLine(87, 19, 87, 41, WHITE);   // Linha vertical (STEP/RX)
  
  display.setTextSize(1);
  
  // STEP
  display.setCursor(57, 22);
  display.print(F("STEP"));
  display.setCursor(48, 32);
  if (stp == 2) display.print(F("   1Hz"));
  if (stp == 3) display.print(F("  10Hz"));
  if (stp == 4) display.print(F("  1kHz"));
  if (stp == 5) display.print(F(" 10kHz"));
  if (stp == 6) display.print(F("100kHz"));
  if (stp == 7) display.print(F("  1MHz"));
  if (stp == 8) display.print(F("1.5MHz"));
  if (stp == 1) display.print(F("  2MHz"));

  // Indicação do BFO/FI (CLK1)
  display.setCursor(0, 45);    // Posição dos nome caracteres IF CLK1
  display.print(F("IF CLK1:"));
  
  // BFO (Frequência Intermediária)
  display.setCursor(55, 45);   // Posição da frequencia IF CLK1
  display.print(bfo / 1000);
  display.print(F("."));
  display.print((bfo % 1000) / 100);
  display.print(F(" kHz"));
  
  // Unidade da frequência (kHz ou MHz)
  display.setTextSize(1);  
  display.setCursor(110, 21);
  if (freq < 1000000) display.print(F("kHz"));
  if (freq >= 1000000) display.print(F("MHz"));
  
  // Modo de operação (AM/LSB/USB)
  display.setCursor(110, 32);
  if (mode == 0) display.print(F("AM"));
  if (mode == 1) display.print(F("LSB"));
  if (mode == 2) display.print(F("USB"));
  
  // Status RX/TX
  display.setCursor(91, 27);
  if (!sts) display.print(F("RX"));
  if (sts) display.print(F("TX"));
  
  bandlist();  // Mostra nome da banda
}

// ============================================================================
// FUNÇÃO: Mostra o nome da banda atual no display
// ============================================================================
void bandlist() { 
  display.setTextSize(2);
  display.setCursor(0, 23);
  if (count == 1) display.print(F("GEN"));
  if (count == 2) display.print(F("MW"));
  if (count == 3) display.print(F("160m"));
  if (count == 4) display.print(F("80m"));
  if (count == 5) display.print(F("60m"));
  if (count == 6) display.print(F("49m"));
  if (count == 7) display.print(F("40m"));
  if (count == 8) display.print(F("31m"));
  if (count == 9) display.print(F("25m"));
  if (count == 10) display.print(F("22m"));
  if (count == 11) display.print(F("20m"));
  if (count == 12) display.print(F("19m"));
  if (count == 13) display.print(F("16m"));
  if (count == 14) display.print(F("13m"));
  if (count == 15) display.print(F("11m"));
  if (count == 16) display.print(F("10m"));
  if (count == 17) display.print(F("6m"));
  if (count == 18) display.print(F("WFM"));
  if (count == 19) display.print(F("AIR"));
  if (count == 20) display.print(F("2m"));
  if (count == 21) display.print(F("1m"));
}

// ============================================================================
// FUNÇÃO: Desenha o S-Meter (medidor de sinal) no rodapé
// ============================================================================
void updateDisplay(int sMeterVal) {
  // Moldura do S-Meter
  display.drawRect(0, 53, 128, 11, WHITE);
  display.fillRect(1, 54, 126, 8, BLACK);

  // Reduz sensibilidade em 50%
  sMeterVal = (sMeterVal * 50) / 100;
  sMeterVal = constrain(sMeterVal, 0, S_GAIN);
  
  // Converte valor para largura da barra
  int barWidth = map(sMeterVal, 0, S_GAIN, 0, 106);
  
  // Suavização do valor (média móvel)
  smoothedSMeter = ((smoothedSMeter * 2) + barWidth) / 3;

  // Peak Hold (mantém valor de pico)
  if (smoothedSMeter > peakHold) {
    peakHold = smoothedSMeter;
    peakTimer = millis();
  }
  
  // Decay do pico (diminui gradualmente)
  if (millis() - peakTimer > 15) {
    if (peakHold > 0) peakHold -= 2;
  }
  peakHold = constrain(peakHold, 0, 125);

  // Desenha barra do S-Meter
  if (smoothedSMeter > 0) {
    display.fillRect(20, 54, smoothedSMeter, 9, WHITE);
  }

  // Desenha linha de pico
  display.drawLine(peakHold + 20, 53, peakHold + 20, 62, WHITE);
  
  // Desenha escala vertical
  for (int i = 0; i < 126; i++) {
    if (i < smoothedSMeter) {
      display.drawFastVLine(i + 20, 54, 9, WHITE);
    }
  }
  
  // Escala numérica do S-Meter
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(2, 55);
  display.print(F("SIG"));
  display.setCursor(24, 55);
  display.print(F("1"));
  display.setCursor(36, 55);
  display.print(F("3"));
  display.setCursor(48, 55);
  display.print(F("5"));
  display.setCursor(60, 55);
  display.print(F("7"));
  display.setCursor(72, 55);
  display.print(F("9"));
  display.setCursor(79, 55);
  display.print(F("..."));
  display.setCursor(96, 55);
  display.print(F("+30"));
  display.setCursor(115, 55);
  display.print(F("dB"));
}

Nenhum comentário:

Postar um comentário

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