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.
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 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.
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"));
}
