segunda-feira, 29 de setembro de 2025

DDS VFO si5351 Arduino canais PX CB Oled display.

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á, publico mais dois esboços ou programas modificados em vídeo, desta vez é do site Circuit Secrets  em vídeos no YouTube sobre este simples DDS VFO para transceptores PX CB, AM, FM. Para quem tem um velho Walkie Talkie com cristaiso TX sempre é na frequência do canal, o RX a maioria sempre está - 455 Khz abaixo, para os transceptores com PLL ou montado por você, corrija ás linhas de comando do programa para - e + ou + e - FI em CLK0 e CLK1. Vocês vão definir no programa como será o DDS VFO para o transceptor, tem também a chave de RX e TX, que vocês poderão montar uma chave eletrônica com transistor e colocar no próprio PTT do transceptor. Este simples DDS VFO vai de 24.205 Mhz a 29.705 Mhz, com os dígitos e canais RC controle remoto ou telecomandos, no display T1, T2, T3, T4, T5, segue em sequência sempre de 10 em 10 Khz para cada canal de PX CB, porem os dígitos canal 23 mostra frequência de 27.235 Mhz quando o correto pelo código internacional FCC e adotado aqui no Brasil é canal 23 frequência 27.255 Mhz. Ou seja a frequência do canal 25, 27.255 Mhz seria no canal 23 = 27.255 Mhz, essa divergência chegou ao Brasil nos anos 80, com o CCE 500/60 tenho um até hoje, este  transceptor não tem esta modificação entre os canais 23 e 25, ou seja ele vai do canal 1 ao 60, só saltando os canais RC, telecomandos, sempre de 10 em 10 Khz até o canal 60. Por isso eu coloquei o DDS VFO até o canal 85 = 27.855 Mhz, sem entrar nas discursões dos canais, vocês vão ter ás referências que estão nas frequências liberadas pela ANATEL. Este simples DDS VFO não tem os modos LSB, USB, só podemos usar modos AM ou FM, isso porque não tem os steps de 1Hz, 10Hz, 100Hz, 10Khz, 100Khz, não podemos clarificar a voz ou variar a frequência em Hz, não tem o deslocamento LSB - 1.500Hz, e USB +1.500Hz em VFO CLK0  Por estes motivos não podemos instalar em transceptores SSB.   
Vejam nos comentários deste vídeo que eu solicitei os modos AM, SSB, também o display só mostrava até o canal 39. Vejam a resposta do autor no mesmo vídeo. Então partir para mais uma simples modificação no esboço que ficasse como eu queria.  
Bem realmente não está como queria, pois eu tentei colocar os modos LSB, USB, mas não tive êxito, perdi muito tempo e só dava erros, como sempre digo, não sou um programador, e sim um aprendiz em modificações. Faltou-me sabedoria do código C++ que é muito complicado, não é o inglês, mas sim ás linhas de comandos das variáveis, void setup e void loop.
Vejam ás fotos com os programas abaixo, para nossos projetos de Walkie Talkie, transceptores AM, FM etc.
Em círculos vermelhos são ás bibliotecas usadas nos programas, a biblioteca Wire.h já está no Arduino IDE. Não instale muitas bibliotecas pois poderá acontecer conflitos entre elas e isso dará erros no esboço. Não deixe o Arduino IDE atualizar bibliotecas, ou remova para outra pasta ás que forem instaladas pelo próprio Arduino IDE. Para reinstalar coloque elas em .ZIP e instale em arquivo .ZIP. 
Inicialização sem o Circuit Secret digitei este, ocupa menos espaço no programa.
Suporta os dois display 128 x 32 e 128 x 64 Oled 1306. 
Coloquei até canal 85 frequencia 27.855 Mhz.
Este é o primeiro canal telecomando RC.
Frequência que mostra no display canal 23 também está no Frequencímetro. 
Deveria ser 27.255 Mhz.
Frequência CLK0 RX. Canal 1 = 26.965 Mhz.
Frequência CLK0 TX. Canal 1 26.965 Mhz - 455Khz = 26.510 Mhz.
Coloquei a chave TX no Encoder mas está errado.
Vejam que em CLK1 RX temos a mesma frequência de CLK0 porem TX temos + 455Khz.
Frequência RX CLK1.
CLK1 TX 26.965 + 455 Khz = 27.420 Mhz.
Frequência TX CLK1.
Pessoal façam alterações nas linhas se desejar Offset outras FIs, + ou - TX, + ou - RX, em CLK0 ou CLK1.

Estas linhas 51 a 55, vocês poderão alterar para ter Offset IF em RX ou TX e calibrar frequência do si5351.

//Some radios use a local 10.240mhz oscilator and the offset if it is simply mixed with the other local oscilator
//would be -10240000 
unsigned long long txOffset=45500; //Enter your IF frequency, ex: 45500 = 455kHz, 1070000 = 10.7MHz, 0 = to direct convert receiver or RF generator, + will add and - will subtract IF offfset.
unsigned long long rxOffset=0;     //Enter your IF frequency
long int calibration=18000;        //This is used to callibrate the si5351.

Estas linhas 265 a 269, vocês poderão alterar para frequência inicialização BFO FI CLK1.

 //VFO and BFO frequency initialization 
  unsigned long long tempchannelho=i;
  vfofrequency=26955000+(tempchannelho*10000ULL); // VFO CLK0 initialization frequency  
  //bfofrequency=34755000+(tempchannelho*10000ULL); // BFO CLK1 initialization frequency
  //bfofrequency=34300000+(tempchannelho*10000ULL);
    
Estas linhas de 291 a 294 vocês poderão definir TX Offset + ou - para VFO ou BFO.

si5351.set_freq((vfofrequency-txOffset*10ull)*100ull, SI5351_CLK0); // VFO RX frequency initialization, TX frequency - FI
  si5351.set_freq((vfofrequency+txOffset*10ull)*100ull, SI5351_CLK1); // VFO RX frequency initialization, TX frequency + FI 
  //si5351.set_freq((bfofrequency-txOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((bfofrequency+txOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency + FI
}

Estas linhas de 303 a 306 vocês poderão definir RX Offset + ou - para VFO ou BFO.

si5351.set_freq((vfofrequency+rxOffset*10ull)*100ull, SI5351_CLK0); // VFO RX frequency initialization, TX frequency - FI
  si5351.set_freq((vfofrequency-rxOffset*10ull)*100ull, SI5351_CLK1); // VFO RX frequency initialization, TX frequency + FI
  //si5351.set_freq((bfofrequency+rxOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((bfofrequency-rxOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency + FI
}

Abaixo o programa algoritmo que fiz ás simples modificações para nossos projetos RTX em AM ou FM.
Selecione e copie todo programa esboço, abra o seu Arduino IDE na área de trabalho, limpe tudo e cole, vá em Arquivo depois Salvar como, renomeei o esboço e escolha a pasta a ser salvo.
Copie abaixo.
/* //Arduino pro mini based export VFO designed for repairing and upgrading old AM/FM C.B. radios.
//It is also a great visual upgrade with the modern styling of a multi colored Oled display.
//This sketch brought to you free of charge by circuit secrets
//           #####   ###  ######    #####   #     #  ###  ####### 
//          #     #   #   #     #  #     #  #     #   #      #    
//          #         #   #     #  #        #     #   #      #    
//          #         #   ######   #        #     #   #      #    
//          #         #   #   #    #        #     #   #      #    
//          #     #   #   #    #   #     #  #     #   #      #    
//           #####   ###  #     #   #####    #####   ###     #    
                                              
//       #####   #######   #####   ######   #######  #######   #####  
//      #     #  #        #     #  #     #  #           #     #     # 
//      #        #        #        #     #  #           #     #       
//       #####   #####    #        ######   #####       #      #####  
//            #  #        #        #   #    #           #           # 
//      #     #  #        #     #  #    #   #           #     #     # 
//       #####   #######   #####   #     #  #######     #      #####  
//If you find this useful please visit our youtube and subscribe for more youtube/circuitsecrets
//You may use this sketch at your own risk, we are not responsible for damages from use of this sketch.
//We make no claims to the quality of this sketch and it is intended to be for educational use only.
//You may distribute and modify this in any way you wish for free or comercially.
//We only ask that you reference the original producer and distributor circuit secrets.
//visit our website for more sketches, designs, schematics and diagrams..circuitsecrets.com//
*/
//----------------------------------------------------------------------------------------------------------------
// Modified sketch for home-made or commercial transceivers, 
// Walkie Talkies, direct conversion superheterodyne or double conversion   
// by Waldir Cardoso. Blog: https://projetosetransceptores.blogspot.com/ 2025/09/25.                        
//--------------------------------------------------------------------
//  Function.
//  1.RX TX Key
//  2.VFO (CLK0) 85 Channel CB. + 5 channels RC display
//  3.VFO (CLK0) Frequency 24.205 Mhz to 29.705 Mhz  
//  4.STEP(10khz) Channel CB
//  5.BFO (CLK1) RX = 26.965 Mhz initialization, TX 26.965 Mhz + (IF)
//  6 VFO (CLK0) RX = 26.965 Mhz initialization, TX 26.965 Mhz - (IF)
//  7.IF with Intermediate Frequency (IF) offset 

//wire library for i2c  
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include "si5351.h"

#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display1(128, 64, &Wire, -1);
//variable to hold the desired frequency information for the si5351
unsigned long long vfofrequency=2696500000; // frequency display initialization
//unsigned long long bfofrequency=0;

//Some radios use a local 10.240mhz oscilator and the offset if it is simply mixed with the other local oscilator
//would be -10240000 
unsigned long long txOffset=45500; //Enter your IF frequency, ex: 45500 = 455kHz, 1070000 = 10.7MHz, 0 = to direct convert receiver or RF generator, + will add and - will subtract IF offfset.
unsigned long long rxOffset=0;     //Enter your IF frequency
long int calibration=18000;        //This is used to callibrate the si5351.

//this holds the transmit and recieve state for switching the offset for the VFO
bool transmit=false;
//This is simple latching so when a channel button is pressed it only changes one channel before being released.
// bool channelLatch1=false;
// bool channelLatch2=false;
//bool menuLatch=false;
//variables used for menu control
//int menuItem=1;
//int modeSelector=0;
bool selectItem=false;
int grey=0;
int greyold=0;
int temp1=0;
int temp2=0;

//create instance of si5351
Si5351 si5351;
//variable to keep track of what channel we are on
int channel=1;
/*
//the dimensions of the splash screen bmp
#define LOGO_HEIGHT   64
#define LOGO_WIDTH    88

the splash screen bmp
static const unsigned char PROGMEM logo_bmp[] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xe0, 0x7f, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xea, 0xff, 0x0f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0x1d, 0xac, 0x7f, 0xc3, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x79, 0xae, 0x7f, 0xf8, 0xc4, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x88, 0xb7, 0xff, 0xfc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xe7, 0xae, 0xff, 0xff, 0xfe, 0x3e, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x8f, 0x00, 0x07, 0xf8, 
0xe3, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x38, 0x78, 0x3f, 0x20, 0xf3, 0xed, 0xbf, 0xff, 0xff, 0xff, 
0xfe, 0x6c, 0x63, 0xfe, 0xfc, 0x07, 0x07, 0x9f, 0xff, 0xff, 0xff, 0xfc, 0xc4, 0x8f, 0xfb, 0xff, 
0x1c, 0x01, 0xcf, 0xff, 0xff, 0xff, 0xf9, 0x37, 0x3f, 0xf7, 0xfe, 0x38, 0x30, 0x6f, 0xff, 0xff, 
0xff, 0xfb, 0xf4, 0x7f, 0xdf, 0xfc, 0xe0, 0x18, 0x27, 0xff, 0xff, 0xff, 0xf3, 0x79, 0xff, 0xbf, 
0xf1, 0xc4, 0x9e, 0x33, 0xff, 0xff, 0xff, 0xe5, 0x13, 0xd6, 0xff, 0xe7, 0xe7, 0xcf, 0x9b, 0xff, 
0xff, 0xff, 0xc8, 0xe7, 0xfd, 0xff, 0x8e, 0x32, 0xc6, 0xd9, 0xff, 0xff, 0xff, 0xdc, 0x4f, 0xbf, 
0xfe, 0x38, 0x10, 0xe6, 0x19, 0xff, 0xff, 0xff, 0x9e, 0x9f, 0xfd, 0xfc, 0x74, 0x18, 0x73, 0x71, 
0xff, 0xff, 0xff, 0xa7, 0xbf, 0xbf, 0xf1, 0xe2, 0x4c, 0xf1, 0xc7, 0xff, 0xff, 0xff, 0x31, 0x3f, 
0x6b, 0xe7, 0xcd, 0x0c, 0x5b, 0x8f, 0xff, 0xff, 0xff, 0x5e, 0x7d, 0xff, 0x8e, 0x2f, 0x06, 0x0e, 
0x1f, 0xff, 0xff, 0xfe, 0x4a, 0x7b, 0xfe, 0x3c, 0xa7, 0x93, 0x1c, 0xdf, 0xff, 0xff, 0xfe, 0x44, 
0xef, 0xfc, 0x74, 0x63, 0xc8, 0x31, 0xcf, 0xff, 0xff, 0xfe, 0xf4, 0xdf, 0xf9, 0xe2, 0x73, 0xc1, 
0xe7, 0xcf, 0xff, 0xff, 0xfe, 0xfc, 0x7f, 0xe3, 0xcb, 0x19, 0xe3, 0x87, 0xcf, 0xff, 0xff, 0xfc, 
0xf8, 0xff, 0xcf, 0xef, 0x08, 0xa7, 0x27, 0xcf, 0xff, 0xff, 0xfc, 0xf9, 0xff, 0x1c, 0xe1, 0x9c, 
0x3c, 0x67, 0xef, 0xff, 0xff, 0xfd, 0xfb, 0xfc, 0x70, 0x70, 0xcb, 0x39, 0xe7, 0xef, 0xff, 0xff, 
0xfd, 0xfb, 0xf9, 0xe0, 0xf8, 0x49, 0xe3, 0xf7, 0xef, 0xff, 0xff, 0xfd, 0xfb, 0xe3, 0xc8, 0x7c, 
0x21, 0xcf, 0xe7, 0xef, 0xff, 0xff, 0xfd, 0xfb, 0xc7, 0x4a, 0x7f, 0xa7, 0x1f, 0xe7, 0xcf, 0xff, 
0xff, 0xf9, 0xfb, 0x1f, 0x67, 0x3d, 0xbc, 0x7f, 0xe7, 0xcf, 0xff, 0xff, 0xf9, 0xfa, 0x39, 0xa3, 
0x3e, 0x38, 0xff, 0xe7, 0xcf, 0xff, 0xff, 0xfd, 0xf8, 0xe0, 0xf3, 0x9f, 0xe3, 0xff, 0xef, 0xcf, 
0xff, 0xff, 0xfd, 0xf3, 0xc4, 0xf9, 0xcf, 0xcf, 0xff, 0xef, 0xdf, 0xff, 0xff, 0xfd, 0xc7, 0xda, 
0x68, 0xc7, 0x1f, 0xff, 0xcf, 0xdf, 0xff, 0xff, 0xfd, 0x1c, 0xce, 0x3c, 0xce, 0x7f, 0xff, 0xcf, 
0x9f, 0xff, 0xff, 0xfc, 0x38, 0x4f, 0x36, 0x78, 0xff, 0x9f, 0x97, 0x9f, 0xff, 0xff, 0xfc, 0xf0, 
0x27, 0x9e, 0x73, 0xff, 0xbf, 0x9d, 0xbf, 0xff, 0xff, 0xf1, 0xc9, 0x23, 0x8b, 0xc7, 0xfc, 0xff, 
0x31, 0x3f, 0xff, 0xff, 0xe7, 0x8c, 0x33, 0xc3, 0x9f, 0xdd, 0xff, 0x3b, 0x7f, 0xff, 0xff, 0x8e, 
0x24, 0x19, 0xfe, 0x3f, 0xcf, 0xfe, 0x46, 0x7f, 0xff, 0xff, 0xdc, 0xa6, 0x09, 0xbc, 0xfe, 0x8b, 
0xfe, 0xc2, 0xff, 0xff, 0xff, 0xcc, 0xd3, 0x26, 0x71, 0xfd, 0xbf, 0xfc, 0xbc, 0xff, 0xff, 0xff, 
0xe6, 0x79, 0x03, 0xc7, 0xfd, 0x9f, 0xf9, 0x99, 0xff, 0xff, 0xff, 0xf6, 0x79, 0x83, 0x9f, 0xfc, 
0xbf, 0xf2, 0x49, 0xff, 0xff, 0xff, 0xf3, 0x3c, 0xce, 0x3f, 0xfe, 0xff, 0xe6, 0x73, 0xff, 0xff, 
0xff, 0xf9, 0x1c, 0x5c, 0xff, 0xff, 0xff, 0x8c, 0x27, 0xff, 0xff, 0xff, 0xf9, 0x9a, 0x71, 0xff, 
0xff, 0xff, 0x3e, 0x4f, 0xff, 0xff, 0xff, 0xfc, 0xcb, 0xe0, 0x7d, 0xf7, 0xfc, 0x73, 0x9f, 0xff, 
0xff, 0xff, 0xfe, 0xe3, 0x8e, 0x1f, 0xff, 0xf1, 0xb1, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x3f, 
0x83, 0xff, 0x86, 0x16, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x3c, 0x7f, 0xf0, 0x00, 0x3f, 0x0c, 0xff, 
0xff, 0xff, 0xff, 0xff, 0x90, 0x3f, 0xff, 0xc7, 0xd3, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 
0x1f, 0xff, 0xd8, 0x80, 0xa3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xc7, 0xff, 0xc0, 0xa0, 0x8f, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xc8, 0x0e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xf8, 0x7f, 0x98, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
*/
//--------------void setup --------------------------------------------------------------------------------
void setup() { 
  
  //encoder pin function
  pinMode(13,INPUT_PULLUP);
  pinMode(A0,INPUT_PULLUP);
  pinMode(A1,INPUT_PULLUP);    
   
  // Enable interupts on port C
  PCICR |= B00000010;
  // Select PCINT pins 0 and 1 of port C a0 and a1
  PCMSK1 |= B00000011;
  delay(200);
  // put your setup code here, to run once:
  if(!display1.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
  //if it cannot start stop the program
    for(;;);
  }
  
  //clear the display buffer
  //display1.clearDisplay();
  //call the drawlogo function
  //drawlogo();
  //delay to show off the logo before starting the main program
  //delay(3000);
  display1.clearDisplay();
  //set the text size
  display1.setTextSize(2);
  // Set the text color, the 1306 only supports white
  display1.setTextColor(WHITE);        
  // Set the curser at the top left position
  display1.println("");
  display1.print("   Walkie    ");
  display1.print("Talkie");
  display1.display();
  delay(3000);
  //PrintTextToDisplay();
  //initialize the si5351, setting the oscilator load to the default, no refference frequency, no frequency correction
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, calibration); 
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);  //Output current 2MA, 4MA, 6MA or 8MA
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA);  //Output current 2MA, 4MA, 6MA or 8MA
}
//-------------  void loop-------------------------------------------------------------------------------------------------
void loop(){     
  //call the display and frequency calculation function
  displayChannelAndFrequency(channel);
 
 //read pin 13 to check for tx pin to be grounded
  if(digitalRead(13)==LOW){
    //set the transmit state to true
    tx();
    //set the transmit state to false when the pin is high
  }else rx();

//buttonState=encoderlogic();
  //Limit the channel range to typical export range
if(channel>275){
  channel=-275;
 }
  //Limit the channel range to typical export range
 if(channel<-275){
  channel=275;
 }
}
/*
//function to draw the logo to the screen
void drawlogo(void) {
  clear the display buffer
  display1.clearDisplay();
drawBitmap method is called with the desired center position of the image
the name of the image and the image size
this draws the bitmap to the buffer
  display1.drawBitmap(
    (display1.width()  - LOGO_WIDTH ) / 2,
    (display1.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
the contents of the buffer are displayed.
  display1.display();
}
*/
//function to display the vfo text takes the channel number as an argument
void displayChannelAndFrequency(int i){
  //we create a string and initialize it to the frequency for channel 1
  String frequency="26.965";
int tempchannel=0;
  //we create a switch to set the string to the corrosponding frequency of the selected channel
//organize frequency to channel display
tempchannel=i;
if(i>3){
  tempchannel--;
}
if(i>8){
  tempchannel--;
}
if(i>13){
  tempchannel--;
}
if(i>18){
  tempchannel--;
}
if(i>23){
  tempchannel--;
}
  //This code does all of the formating of the text
  //clear the buffer
  display1.clearDisplay();
  //set the text size
  display1.setTextSize(2);
  // Set the text color, the 1306 only supports white
  display1.setTextColor(WHITE);        
  // Set the curser at the top left position
  display1.println("         "); 
  if (i>0&i<91){
  display1.setCursor(0,0);             
  // Print CH to the display
  display1.println("CANAL");
  //set the cursor next to the CH text at the top
  display1.setCursor(70,0);             
  // print the channel number
  display1.println(tempchannel);
  display1.setCursor(95,0);             
  // print the channel number
  if(i==4){  
  display1.println("T1");}

  if(i==9){
  display1.println("T2");}

  if(i==14){
  display1.println("T3");}

  if(i==19){
  display1.println("T4");}

  if(i==24){
  display1.println("T5");}
 }   
  //VFO and BFO frequency initialization 
  unsigned long long tempchannelho=i;
  vfofrequency=26955000+(tempchannelho*10000ULL); // VFO CLK0 initialization frequency  
  //bfofrequency=34755000+(tempchannelho*10000ULL); // BFO CLK1 initialization frequency
  //bfofrequency=34300000+(tempchannelho*10000ULL);
    
  //display1.clearDisplay();
  display1.setTextColor(WHITE);
  //set the text size
  display1.setTextSize(2);
  display1.setCursor(0,25);
  // Set the text color, the 1306 only supports white
  float tempvfoval=vfofrequency;
  float displayvalue=tempvfoval/1000000;           
  // print the frequency to the display
  //display1.println("test");  
  display1.print(displayvalue, 3);
  display1.println(".Mhz");
  display1.display();
 }
//function to handle the TX state
void tx(void){

  // Set CLK0 to output frequency. We multiply our frequenzy by 100 unsigned unsigned long because the frequency is set in
  //100ths of hertz not hertz. We set the clock 0
  //we subtract the tx local oscilator value for the mixer
  si5351.set_freq((vfofrequency-txOffset*10ull)*100ull, SI5351_CLK0); // VFO RX frequency initialization, TX frequency - FI
  si5351.set_freq((vfofrequency+txOffset*10ull)*100ull, SI5351_CLK1); // VFO RX frequency initialization, TX frequency + FI 
  //si5351.set_freq((bfofrequency-txOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((bfofrequency+txOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency + FI
}

//function to handle the RX state
void rx(void){
  
   //Set CLK0 to output frequency. We multiply our frequenzy by 100 unsigned unsigned long because the frequency is set in
  //100ths of hertz not hertz. We set the clock 0
  //we subtract the tx local oscilator value for the mixer  
  si5351.set_freq((vfofrequency+rxOffset*10ull)*100ull, SI5351_CLK0); // VFO RX frequency initialization, TX frequency - FI
  si5351.set_freq((vfofrequency-rxOffset*10ull)*100ull, SI5351_CLK1); // VFO RX frequency initialization, TX frequency + FI
  //si5351.set_freq((bfofrequency+rxOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((bfofrequency-rxOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency + FI
}

//Interupt service routine this is used to read the encoder state when the interupt is triggered
ISR (PCINT1_vect){
//int clickdetect=0;
    if(digitalRead(A0)==LOW){
    temp1=0;}else temp1=1;

    if(digitalRead(A1)==LOW){
    temp2=0;}else temp2=2;
 
 grey=temp1+temp2;

if(grey==0){
  if(greyold==1){
    channel--;
  }
  if(greyold==2){
    channel++;  
  }  
}
if(grey!=greyold){
}
greyold=grey;
//return clickdetect;
}

Abaixo fotos e esboço ou programa coloquei em CLK1 em RX frequência de 34.765 Mhz, e TX - 455 = 34.310 Mhz, só para vocês terem uma noção o FI Offset será a mesma de 455 Khz ou que vocês digitarem no programa para CLK0 e CLK1, este esboço não serve para o Cobra 148 GTL ou transceptores SSB.
Vejam que permanece em CLK0 RX 26.965 Mhz, e TX FI - 455Khz.
Vejam em TX CLK0 - 455 Khz = 26.510 Mhz.

Vejam que em CLK1 digitei a frequência de 34.765 canal 1.


Vejam em TX CLK1 é - 455 Khz 34.310 Mhz.
Abaixo é o esboço algoritmo que fiz ás simples modificações para nossos projetos RTX em AM ou FM.
Selecione e copie todo programa esboço, abra o seu Arduino IDE na área de trabalho, limpe tudo e cole, vá em Arquivo depois Salvar como, renomeei o esboço e escolha a pasta a ser salvo.
Copie abaixo.

/* //Arduino pro mini based export VFO designed for repairing and upgrading old AM/FM C.B. radios.
//It is also a great visual upgrade with the modern styling of a multi colored Oled display.
//This sketch brought to you free of charge by circuit secrets
//           #####   ###  ######    #####   #     #  ###  ####### 
//          #     #   #   #     #  #     #  #     #   #      #    
//          #         #   #     #  #        #     #   #      #    
//          #         #   ######   #        #     #   #      #    
//          #         #   #   #    #        #     #   #      #    
//          #     #   #   #    #   #     #  #     #   #      #    
//           #####   ###  #     #   #####    #####   ###     #    
                                              
//       #####   #######   #####   ######   #######  #######   #####  
//      #     #  #        #     #  #     #  #           #     #     # 
//      #        #        #        #     #  #           #     #       
//       #####   #####    #        ######   #####       #      #####  
//            #  #        #        #   #    #           #           # 
//      #     #  #        #     #  #    #   #           #     #     # 
//       #####   #######   #####   #     #  #######     #      #####  
//If you find this useful please visit our youtube and subscribe for more youtube/circuitsecrets
//You may use this sketch at your own risk, we are not responsible for damages from use of this sketch.
//We make no claims to the quality of this sketch and it is intended to be for educational use only.
//You may distribute and modify this in any way you wish for free or comercially.
//We only ask that you reference the original producer and distributor circuit secrets.
//visit our website for more sketches, designs, schematics and diagrams..circuitsecrets.com//
*/
//--------------------------------------------------------------------------------------------
// Modified sketch for home-made or commercial transceivers, 
// Walkie Talkies, direct conversion superheterodyne or double conversion   
// by Waldir Cardoso. 2025/09/25.                       
// Blog: https://projetosetransceptores.blogspot.com/
//--------------------------------------------------------------------------------------------
//  Function.
//  1.RX TX Key
//  2.VFO (CLK0) 85 Channel CB + 5 channels RC display
//  3.VFO (CLK0) Frequency 24.205 Mhz to 29.705 Mhz  
//  4.STEP(10khz) Channel CB
//  5.BFO (CLK1) RX = 34.765 Mhz initialization, TX 34.765 Mhz - (IF)
//  6.VFO (CLK0) RX = 26.965 Mhz initialization, TX 26.965 Mhz - (IF)
//  6.IF with Intermediate Frequency (IF) offset 

//wire library for i2c  
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include "si5351.h"

#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display1(128, 64, &Wire, -1);

//variable to hold the desired frequency information for the si5351
unsigned long long vfofrequency=2696500000; // frequency display initialization
unsigned long long bfofrequency=0;

//Some radios use a local 10.240mhz oscilator and the offset if it is simply mixed with the other local oscilator
//would be -10240000 
unsigned long long txOffset=45500; //Enter your IF frequency, ex: 45500 = 455kHz, 1070000 = 10.7MHz, 0 = to direct convert receiver or RF generator, + will add and - will subtract IF offfset.
unsigned long long rxOffset=0;     //Enter your IF frequency
long int calibration=18000;        //This is used to callibrate the si5351.

//this holds the transmit and recieve state for switching the offset for the VFO
bool transmit=false;
//This is simple latching so when a channel button is pressed it only changes one channel before being released.
//bool channelLatch1=false;
//bool channelLatch2=false;
//bool menuLatch=false;
///variables used for menu control
//int menuItem=1;
//int modeSelector=0;

bool selectItem=false;
int grey=0;
int greyold=0;
int temp1=0;
int temp2=0;

//create instance of si5351
Si5351 si5351;
//variable to keep track of what channel we are on
int channel=1;
/*
//the dimensions of the splash screen bmp
#define LOGO_HEIGHT   64
#define LOGO_WIDTH    88

the splash screen bmp
static const unsigned char PROGMEM logo_bmp[] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xe0, 0x7f, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xea, 0xff, 0x0f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0x1d, 0xac, 0x7f, 0xc3, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x79, 0xae, 0x7f, 0xf8, 0xc4, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x88, 0xb7, 0xff, 0xfc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xe7, 0xae, 0xff, 0xff, 0xfe, 0x3e, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x8f, 0x00, 0x07, 0xf8, 
0xe3, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x38, 0x78, 0x3f, 0x20, 0xf3, 0xed, 0xbf, 0xff, 0xff, 0xff, 
0xfe, 0x6c, 0x63, 0xfe, 0xfc, 0x07, 0x07, 0x9f, 0xff, 0xff, 0xff, 0xfc, 0xc4, 0x8f, 0xfb, 0xff, 
0x1c, 0x01, 0xcf, 0xff, 0xff, 0xff, 0xf9, 0x37, 0x3f, 0xf7, 0xfe, 0x38, 0x30, 0x6f, 0xff, 0xff, 
0xff, 0xfb, 0xf4, 0x7f, 0xdf, 0xfc, 0xe0, 0x18, 0x27, 0xff, 0xff, 0xff, 0xf3, 0x79, 0xff, 0xbf, 
0xf1, 0xc4, 0x9e, 0x33, 0xff, 0xff, 0xff, 0xe5, 0x13, 0xd6, 0xff, 0xe7, 0xe7, 0xcf, 0x9b, 0xff, 
0xff, 0xff, 0xc8, 0xe7, 0xfd, 0xff, 0x8e, 0x32, 0xc6, 0xd9, 0xff, 0xff, 0xff, 0xdc, 0x4f, 0xbf, 
0xfe, 0x38, 0x10, 0xe6, 0x19, 0xff, 0xff, 0xff, 0x9e, 0x9f, 0xfd, 0xfc, 0x74, 0x18, 0x73, 0x71, 
0xff, 0xff, 0xff, 0xa7, 0xbf, 0xbf, 0xf1, 0xe2, 0x4c, 0xf1, 0xc7, 0xff, 0xff, 0xff, 0x31, 0x3f, 
0x6b, 0xe7, 0xcd, 0x0c, 0x5b, 0x8f, 0xff, 0xff, 0xff, 0x5e, 0x7d, 0xff, 0x8e, 0x2f, 0x06, 0x0e, 
0x1f, 0xff, 0xff, 0xfe, 0x4a, 0x7b, 0xfe, 0x3c, 0xa7, 0x93, 0x1c, 0xdf, 0xff, 0xff, 0xfe, 0x44, 
0xef, 0xfc, 0x74, 0x63, 0xc8, 0x31, 0xcf, 0xff, 0xff, 0xfe, 0xf4, 0xdf, 0xf9, 0xe2, 0x73, 0xc1, 
0xe7, 0xcf, 0xff, 0xff, 0xfe, 0xfc, 0x7f, 0xe3, 0xcb, 0x19, 0xe3, 0x87, 0xcf, 0xff, 0xff, 0xfc, 
0xf8, 0xff, 0xcf, 0xef, 0x08, 0xa7, 0x27, 0xcf, 0xff, 0xff, 0xfc, 0xf9, 0xff, 0x1c, 0xe1, 0x9c, 
0x3c, 0x67, 0xef, 0xff, 0xff, 0xfd, 0xfb, 0xfc, 0x70, 0x70, 0xcb, 0x39, 0xe7, 0xef, 0xff, 0xff, 
0xfd, 0xfb, 0xf9, 0xe0, 0xf8, 0x49, 0xe3, 0xf7, 0xef, 0xff, 0xff, 0xfd, 0xfb, 0xe3, 0xc8, 0x7c, 
0x21, 0xcf, 0xe7, 0xef, 0xff, 0xff, 0xfd, 0xfb, 0xc7, 0x4a, 0x7f, 0xa7, 0x1f, 0xe7, 0xcf, 0xff, 
0xff, 0xf9, 0xfb, 0x1f, 0x67, 0x3d, 0xbc, 0x7f, 0xe7, 0xcf, 0xff, 0xff, 0xf9, 0xfa, 0x39, 0xa3, 
0x3e, 0x38, 0xff, 0xe7, 0xcf, 0xff, 0xff, 0xfd, 0xf8, 0xe0, 0xf3, 0x9f, 0xe3, 0xff, 0xef, 0xcf, 
0xff, 0xff, 0xfd, 0xf3, 0xc4, 0xf9, 0xcf, 0xcf, 0xff, 0xef, 0xdf, 0xff, 0xff, 0xfd, 0xc7, 0xda, 
0x68, 0xc7, 0x1f, 0xff, 0xcf, 0xdf, 0xff, 0xff, 0xfd, 0x1c, 0xce, 0x3c, 0xce, 0x7f, 0xff, 0xcf, 
0x9f, 0xff, 0xff, 0xfc, 0x38, 0x4f, 0x36, 0x78, 0xff, 0x9f, 0x97, 0x9f, 0xff, 0xff, 0xfc, 0xf0, 
0x27, 0x9e, 0x73, 0xff, 0xbf, 0x9d, 0xbf, 0xff, 0xff, 0xf1, 0xc9, 0x23, 0x8b, 0xc7, 0xfc, 0xff, 
0x31, 0x3f, 0xff, 0xff, 0xe7, 0x8c, 0x33, 0xc3, 0x9f, 0xdd, 0xff, 0x3b, 0x7f, 0xff, 0xff, 0x8e, 
0x24, 0x19, 0xfe, 0x3f, 0xcf, 0xfe, 0x46, 0x7f, 0xff, 0xff, 0xdc, 0xa6, 0x09, 0xbc, 0xfe, 0x8b, 
0xfe, 0xc2, 0xff, 0xff, 0xff, 0xcc, 0xd3, 0x26, 0x71, 0xfd, 0xbf, 0xfc, 0xbc, 0xff, 0xff, 0xff, 
0xe6, 0x79, 0x03, 0xc7, 0xfd, 0x9f, 0xf9, 0x99, 0xff, 0xff, 0xff, 0xf6, 0x79, 0x83, 0x9f, 0xfc, 
0xbf, 0xf2, 0x49, 0xff, 0xff, 0xff, 0xf3, 0x3c, 0xce, 0x3f, 0xfe, 0xff, 0xe6, 0x73, 0xff, 0xff, 
0xff, 0xf9, 0x1c, 0x5c, 0xff, 0xff, 0xff, 0x8c, 0x27, 0xff, 0xff, 0xff, 0xf9, 0x9a, 0x71, 0xff, 
0xff, 0xff, 0x3e, 0x4f, 0xff, 0xff, 0xff, 0xfc, 0xcb, 0xe0, 0x7d, 0xf7, 0xfc, 0x73, 0x9f, 0xff, 
0xff, 0xff, 0xfe, 0xe3, 0x8e, 0x1f, 0xff, 0xf1, 0xb1, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x3f, 
0x83, 0xff, 0x86, 0x16, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x3c, 0x7f, 0xf0, 0x00, 0x3f, 0x0c, 0xff, 
0xff, 0xff, 0xff, 0xff, 0x90, 0x3f, 0xff, 0xc7, 0xd3, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 
0x1f, 0xff, 0xd8, 0x80, 0xa3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xc7, 0xff, 0xc0, 0xa0, 0x8f, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xc8, 0x0e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xf8, 0x7f, 0x98, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0x03, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
*/
//--------------void setup --------------------------------------------------------------------------------
void setup() { 
  
  //encoder pin function
  pinMode(13,INPUT_PULLUP);
  pinMode(A0,INPUT_PULLUP);
  pinMode(A1,INPUT_PULLUP);    
   
  // Enable interupts on port C
  PCICR |= B00000010;
  // Select PCINT pins 0 and 1 of port C a0 and a1
  PCMSK1 |= B00000011;
  delay(200);
  // put your setup code here, to run once:
  if(!display1.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
  //if it cannot start stop the program
    for(;;);
  }
  
  //clear the display buffer
  //display1.clearDisplay();
  //call the drawlogo function
  //drawlogo();
  //delay to show off the logo before starting the main program
  //delay(3000);
  display1.clearDisplay();
  //set the text size
  display1.setTextSize(2);
  // Set the text color, the 1306 only supports white
  display1.setTextColor(WHITE);        
  // Set the curser at the top left position
  display1.println("");
  display1.print("   Walkie    ");
  display1.print("Talkie");
  display1.display();
  delay(3000);
  //PrintTextToDisplay();
  //initialize the si5351, setting the oscilator load to the default, no refference frequency, no frequency correction
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, calibration); 
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);  //Output current 2MA, 4MA, 6MA or 8MA
  si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_8MA);  //Output current 2MA, 4MA, 6MA or 8MA
}
//-------------  void loop--------------------------------------------------------------------------------------------
void loop(){     
  //call the display and frequency calculation function
  displayChannelAndFrequency(channel);
 
 //read pin 13 to check for tx pin to be grounded
  if(digitalRead(13)==LOW){
    //set the transmit state to true
    tx();
    //set the transmit state to false when the pin is high
  }else rx();

//buttonState=encoderlogic();
  //Limit the channel range to typical export range
if(channel>275){
  channel=-275;
 }
  //Limit the channel range to typical export range
 if(channel<-275){
  channel=275;
 }
}
/*
//function to draw the logo to the screen
void drawlogo(void) {
  clear the display buffer
  display1.clearDisplay();
drawBitmap method is called with the desired center position of the image
the name of the image and the image size
this draws the bitmap to the buffer
  display1.drawBitmap(
    (display1.width()  - LOGO_WIDTH ) / 2,
    (display1.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
the contents of the buffer are displayed.
  display1.display();
}
*/
//function to display the vfo text takes the channel number as an argument
void displayChannelAndFrequency(int i){
  //we create a string and initialize it to the frequency for channel 1
  String frequency="26.965";
int tempchannel=0;
  //we create a switch to set the string to the corrosponding frequency of the selected channel
//organize frequency to channel display
tempchannel=i;
if(i>3){
  tempchannel--;
}
if(i>8){
  tempchannel--;
}
if(i>13){
  tempchannel--;
}
if(i>18){
  tempchannel--;
}
if(i>23){
  tempchannel--;
}
  //This code does all of the formating of the text
  //clear the buffer
  display1.clearDisplay();
  //set the text size
  display1.setTextSize(2);
  // Set the text color, the 1306 only supports white
  display1.setTextColor(WHITE);        
  // Set the curser at the top left position
  display1.println("         "); 
  if (i>0&i<91){
  display1.setCursor(0,0);             
  // Print CH to the display
  display1.println("CANAL");
  //set the cursor next to the CH text at the top
  display1.setCursor(70,0);             
  // print the channel number
  display1.println(tempchannel);
  display1.setCursor(95,0);             
  // print the channel number
  if(i==4){  
  display1.println("T1");}

  if(i==9){
  display1.println("T2");}

  if(i==14){
  display1.println("T3");}

  if(i==19){
  display1.println("T4");}

  if(i==24){
  display1.println("T5");}
 }   
  //VFO and BFO frequency initialization 
  unsigned long long tempchannelho=i;
  vfofrequency=26955000+(tempchannelho*10000ULL); // VFO CLK0 initialization frequency  
  bfofrequency=34755000+(tempchannelho*10000ULL); // BFO CLK1 initialization frequency
  //bfofrequency=34300000+(tempchannelho*10000ULL);
    
  //display1.clearDisplay();
  display1.setTextColor(WHITE);
  //set the text size
  display1.setTextSize(2);
  display1.setCursor(0,25);
  // Set the text color, the 1306 only supports white
  float tempvfoval=vfofrequency;
  float displayvalue=tempvfoval/1000000;           
  // print the frequency to the display
  //display1.println("test");  
  display1.print(displayvalue, 3);
  display1.println(".Mhz");
  display1.display();
 }
//function to handle the TX state
void tx(void){

  // Set CLK0 to output frequency. We multiply our frequenzy by 100 unsigned unsigned long because the frequency is set in
  //100ths of hertz not hertz. We set the clock 0
  //we subtract the tx local oscilator value for the mixer
  si5351.set_freq((vfofrequency-txOffset*10ull)*100ull, SI5351_CLK0); // VFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((vfofrequency+txOffset*10ull)*100ull, SI5351_CLK1); // VFO RX frequency initialization, TX frequency + FI 
  si5351.set_freq((bfofrequency-txOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((bfofrequency+txOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency + FI
}

//function to handle the RX state
void rx(void){
  
   //Set CLK0 to output frequency. We multiply our frequenzy by 100 unsigned unsigned long because the frequency is set in
  //100ths of hertz not hertz. We set the clock 0
  //we subtract the tx local oscilator value for the mixer  
  si5351.set_freq((vfofrequency+rxOffset*10ull)*100ull, SI5351_CLK0); // VFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((vfofrequency-rxOffset*10ull)*100ull, SI5351_CLK1); // VFO RX frequency initialization, TX frequency + FI
  si5351.set_freq((bfofrequency+rxOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency - FI
  //si5351.set_freq((bfofrequency-rxOffset*10ull)*100ull, SI5351_CLK1); // BFO RX frequency initialization, TX frequency + FI
}

//Interupt service routine this is used to read the encoder state when the interupt is triggered
ISR (PCINT1_vect){
//int clickdetect=0;
    if(digitalRead(A0)==LOW){
    temp1=0;}else temp1=1;

    if(digitalRead(A1)==LOW){
    temp2=0;}else temp2=2;
 
 grey=temp1+temp2;

if(grey==0){
  if(greyold==1){
    channel--;
  }
  if(greyold==2){
    channel++;  
  }  
}
if(grey!=greyold){
}
greyold=grey;
//return clickdetect;
}

sexta-feira, 19 de setembro de 2025

Buffer amplificador RF DDS VFO si5351.

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, para vocês que estão começando no mundo digital Arduino DDS VFO si5351, para seus projetos feito em casa ou transceptores comerciais, eu falei lá no fim do primeiro vídeo, sobre colocar um buffer ou amplificador nas saídas do si5351 CLK0, CLK1 ou CLK2, estas saídas mesmo que voces selecionem 6mA ou 8mA no programa " si5351.drive_strength (SI5351_CLK0, SI5351_DRIVE_8MA ". A saída de RF é muito baixa, considerando quase como um cristal ligado ao circuito oscilador. Por isso resolvi pesquisar na WEB e publicar alguns esquemas, que vocês poderão montar como amplificador, modulador FM ou Mixer retirando sinal CLK0, CLK1 ou CLK2, para transceptores comerciais ou feitos em casa, nas configurações: Amplificador banda ultra larga, banda larga, banda estreita. Como o si5351 tem uma pequena tolerância de desvio de frequência, sendo praticamente estável, então para nossos projetos o mais simples podemos usar um buffer de banda larga se quisermos abranger uma vasta gama de frequência, tendo sempre como principal os transistores usados em frequências elevadas VHF. considerando-se para uso em frequências baixas uma única banda exemplo: 11 metros PX CB poderemos tomar como referencia o esquema do UHIC 007 com varicap modulador FM, indutores, como Mixer. O exemplo servirá em outras única bandas até VHF de 144 a 148 Mhz modificando os indutores e capacitores e transistores usados para VHF. Abaixo estão alguns circuitos simples de buffers, vocês poderão escolher um deles montar, deverão fazer testes para melhor desempenho. No buffer de banda estreita para o Cobra 148 GTL em FM, AM, SSB, deverão ser testados, ajustes no esboço no driver " si5351.drive_strength (SI5351_CLK0, SI5351_DRIVE_8MA "começa por 2mA, se precisar aumente para 4 ou 6mA, vá dosando aumentando o áudio no trimpot de 10k FM DEV, ajuste L19 e L20 até obter uma modulação limpa em FM. Não abra muito o trimpot, pois muito áudio faz a largura de banda espalhar, prejudicando o áudio e sintonia, O diodo varicap poderá ser o  BB 109, BB 809 ou outros, talvez precise de um capacitor de pequeno valor em paralelo. Verifique se em FM, AM e SSB estão com mesma potencia na saída de L20. Então vamos aos circuitos.
Buffer amplificador DDS si5351 banda larga.
Outros buffer amplificador ultra larga e banda larga.
Buffer banda estreita para 27 Mhz PX CB.
Buffer banda estreita 27 Mhz AM, FM, SSB.

sábado, 30 de agosto de 2025

Esboço sketch Arduíno VFO DDS si5351 AM SSB 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á, assistam aos meus vídeos explicativos para incentivarem todos iniciantes em DDS VFO. Escrevi sobre algumas modificações que já fiz em sketches mês passado, e publiquei algumas modificações no sketch do oled_cb_vfo4 do Sr. Akio Mizuno JA2GQP.  Agora publico o algoritmo programa ou sketch postado em vídeo YouTube do Sr.  CT7API Manuel Ferreira. Meus agradecimentos Sr. Manuel Ferreira, por mostrar e disponibilizar a todos o programa que será bem vindo para todos do hobby. O sketch é simples e pequeno, tem os modos AM, LSB, USB, com deslocamento de 1.5 Khz para cada lado da banda AM. Step de 1Hz até 1 Mhz,   Os sketches podem ser adicionados em transceptores comerciais AM, SSB ou feitos em casa, basta modificar a FI e bandas laterais no sketch. Servirão para Naja, Minhoca, Lagunero 40M, Ararinha, e outros transceptores. 
São três sketches que vocês poderão escolher para seu equipamento ou construção do seu projeto transceptor. O primeiro só AM VFO, BFO conversão direta, o segundo AM, LSB, USB, em VFO e BFO FI 7.800 Khz Cobra 148 GTL. Terceiro é VFO AM conversão direta, e BFO AM, LSB, USB FI 10 Mhz. 
Modificações: Step com números em Khz ou 1 Mhz, selecionado acima de cada dígito a mudar frequência. Coloquei para 1 Mhz para melhor cobrir toda faixa entre 80 metros a 6 metros, modo AM, LSB, USB em CLK0, VFO e CLK1, BFO, ideal para Cobra 148 GTL e outros equipamentos comerciais. Rotary Encoder simples 5 pinos. Aceita os dois tipos de oled 128 x 32 e 128 x 64 SSD 1306.
Os sketches aqui postados poderão ser modificados, para modo CW, FM. FI pode ser qualquer uma entre 455 Khz AM até 21.4 Mhz FM, TX e RX. Memória em VFO, S/meter, modo canal etc. 
Para quem tem vasta experiência ou é programador poderá colocar alguns destes recursos, eu como já escrevi e disse no vídeo, não sou programador e nem sei muita coisa, estou aprendendo mas o que sei estou disponibilizando para incentivar os que tem dificuldades em fazer modificações e acha que é difícil. Nada é fácil se não tentarmos fazer ou executar, 
Bibliotecas para si5351 usadas neste projeto: SI5351 Arduino V.1.1.2 NT7S SI5351 Arduino V1.1.0
Pois outras mais recentes atualizadas não funcionaram e quebrei muito a cabeça para descobrir, pois a compilação do sketch só dava erro, eu procurava os erros no programa e não achava, depois de muito tentar claro que temos que fazer testes e fiz o teste com a biblioteca SI5351 Arduino V1.1.0 que compilou sem erros e pude assim começar minhas modificações. Depois de adicionar e modificar ás linhas de comando do si5351 em void setup e void loop, mesmo assim desinstalei a antiga e instalei  uma mais recente atualizada do NT7S e deu erro. então ficou assim com ás antigas mesmo. Por isso pessoal nem sempre o programa sketch está com erro, o erro poderá esta nas bibliotecas que não são para aquele sketch. 
Sugestão: Para equipamentos ou montagens em transceptores deve-se ter um buffer nas saídas usadas do si5351, as saídas CLK0, CLK1, CLK2, tem alguns mW de saída RF, melhor amplificar o sinal antes do circuito do transceptor. O sketch mesmo sem TX poderá serem adicionado circuitos no próprio equipamento para misturar uma frequência com a outra, formando uma frequência de TX. Ex: CLK0 + CLK1, ou CLK0 - CLK1, tudo depende do montador ou técnico e também da modificação no sketch. Temos como exemplo o Cobra 148 GTL com Mixer IC5 em L47 34.765 Mhz e L48 7.800 Khz, = 27.965 Mhz. Este sketch aceitou os dois oleds 128x32 e 128x64 SSD 1306. 
Sketch modificação FI, frequencia de inicialização, calibração si5351: FI poderá ser modificado para 455 Khz ou outra FI, modifiquem nas linhas "volatile int32_t AM  = 780000000ULL; ". Modifique a frequência de inicialização VFO de onde o equipamento vai operar em  volatile int32_t vfo = 2696500000ULL /  SI5351_FREQ_MULT; // frequency display initialization. No começo do sketch. Calibração do meu si5351 foi a melhor que se aproximou da correta frequência no meu Frequencímetro Minipa 7110, cada si5351 tem uma frequência de tolerância modifiquem na linha abaixo em void setup si5351.set_correction(18000); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason.
Vocês podem colocar o oled 128x32 0.91 SSD 1306 na versão Walkie Talkie. 
O sketch que preferir gravar, selecione todo conteúdo, e cole no Arduino IDE, adicione todas ás bibliotecas. 
Boa sorte e bons QSOs no seu novo DDS VFO montado por você.
Abaixo o esquema elétrico DDS VFO BFO para transceptores AM SSB. 
Bibliotecas na pasta Arduino libraries para este sketch.
Nunca atualizo o Arduino IDE, pois poderá criar conflitos de bibliotecas erros.
Conversão direta em CLK0.

Conversão direta AM CLK1 FI 7.800 Mhz.
1- sketch abaixo é para equipamentos Walkie Talkie homebrew conversão direta ou super heteródino AM com VFO em 27 Mhz  CLK0 e BFO CLK1 FI 7.800 Khz, do Cobra 148 GTL, . 
O sketch que preferir gravar, selecione todo conteúdo, e cole no Arduino IDE, adicione todas ás bibliotecas.

/********************************************************************************
 sketch modified and copied from the youtube open source 
 CT7API Manuel Ferreira. 
 by Waldir Cardoso. 08/2025. Blog: Projetos e Transceptores Brasil.
 this sketch is a VFO for Direct Conversion equipments or frequency generator
*********************************************************************************/
//---------------------------------------------------------------------------------
//  Function
// 1.VFO CLK0 Direct conversion
// 2.BFO CLK1 7.800 Khz AM mode
// 3.STEP(1MHz,100,10,1kHz,100,10,1Hz)
////////////////////////////////////////////////////////////////////////    
//Libraries
#include <si5351.h>                //https://github.com/etherkit/Si5351Arduino/releases/tag/v1.1.2
#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
//----------------------------------------------------------------------------------------------------
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define Adafruit Si5351 BUS BASE ADDR
#define F_MIN        100000000UL
#define F_MAX        23000000000UL
#define ENCODER_A    2
#define ENCODER_B    3
#define ENCODER_BTN  5
#define USB_PIN 6
#define LSB_PIN 7
#define AM_PIN  8
int lsbstate = 0;
int amstate = 0;
int usbstate = 0;

Si5351 si5351;  //Si5351 I2C Address 0x60
Rotary r = Rotary(3, 2);
volatile int32_t AM  = 780000000ULL; //Enter IF of your AM SSB transceiver
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 = "";

#define Direct_conversion //What you see on display is what you get

/**************************************/
/* Interrupt service routine for      */
/* encoder frequency change           */
/**************************************/
ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result == DIR_CW) 
  set_frequency(1);
  else if (result == DIR_CCW) 
  set_frequency(-1);
}
/**************************************/
/* Change the frequency               */
/* dir = 1    Increment               */
/* dir = -1   Decrement               */
/**************************************/
void set_frequency(short dir)
{
  if (dir == 1)
     vfo += radix;
     if (dir == -1){
     if  (vfo > radix ) {
    vfo -= radix;
     }}
  //if (dir == 1)
    //vfo += radix;
  //if (dir == -1)
    //vfo -= radix;
  changed_f = 1;
 }  
/**************************************/
/* Read the button with debouncing    */
/**************************************/
boolean get_button()
{
  if (!digitalRead(ENCODER_BTN))
  {
    delay(20);
    if (!digitalRead(ENCODER_BTN))
    {
      while (!digitalRead(ENCODER_BTN));
      return 1;
    }
  }
  return 0;
}

/**************************************/
/* Displays the frequency             */
/**************************************/
void display_frequency()
{
  uint16_t f, g;

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,1);
  display.print("      MODE ");
  display.println(tbfo);

  /**************************************/
  /* Displays the frequency change step */
  /**************************************/ 
  switch (radix)
  {
    case 1:
      display.println("                  1Hz");
      break;
    case 10:
      display.println("                 10Hz");
      break;
    case 100:
      display.println("               100Hz");
      break;
    case 1000:
      display.println("           1KHz");
      break;
    case 10000:
      display.println("         10KHz");
      break;
    case 100000:
      display.println("       100KHz");
      break;
      case 1000000:
      display.println("   1MHz");   
      break;
  }
  
  /**************************************/
  /* Displays the frequency             */
  /**************************************/

  display.setTextSize(2);

  f = vfo / 1000000;  //variable is now vfo instead of 'frequency'
  if (f < 10)
  display.print(' ');
  display.print(f);
  display.print('.');
  f = (vfo % 1000000) / 1000;
  if (f < 100)
  display.print('0');
  if (f < 10)
  display.print('0');
  display.print(f);
  display.print('.');
  f = vfo % 1000;
  if (f < 100)
    display.print('0');
  if (f < 10)
    display.print('0');
  display.print(f);
  display.display();
  display.clearDisplay();
}
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);
   
   si5351.set_correction(18000); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  //where you can determine the correction by using the serial monitor.
     
  //initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); //If you're using a 27Mhz crystal, put in 27000000 instead of 0
  // 0 is the default crystal frequency of 25Mhz.

  si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  // Set CLK0 to output the starting "vfo" frequency as set above by vfo = ?
 
  //Serial.println((long)((vfo * SI5351_FREQ_MULT) - bfo) * -1);
  //si5351.set_freq(((vfo * SI5351_FREQ_MULT) + bfo), SI5351_PLL_FIXED, SI5351_CLK0);
#ifdef Direct_conversion
  si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);
#endif
  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); //you can set this to 2MA, 4MA, 6MA or 8MA
  si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_6MA); //be careful though - measure into 50 ohms
  //si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA); //

  Splash();

  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
}

void loop()
{
  // Update the display if the frequency has been changed
  // if (changed_f)
  {
    display_frequency();
  
    Serial.println((long)((vfo * SI5351_FREQ_MULT) + bfo) * -1);
    //si5351.set_freq(((vfo * SI5351_FREQ_MULT) - bfo), SI5351_PLL_FIXED, SI5351_CLK1);    // subtrai á IF
    //you can also subtract the bfo to suit your needs
    //si5351.set_freq((vfo * SI5351_FREQ_MULT) + bfo  , SI5351_PLL_FIXED, SI5351_CLK0);  // soma á IF
#ifdef Direct_conversion      
    si5351.set_freq((vfo * SI5351_FREQ_MULT) , SI5351_PLL_FIXED, SI5351_CLK0);  // display frequency
#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";
    }           
    changed_f = 0;
  }

  // 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();
  }
 }

  void Splash() {
  display.setTextSize(1);
  display.setCursor(4, 5);
  display.print("   Walkie Talkie");
  display.setCursor(4, 25);
  display.print("       AM CB");
  display.display();
  delay(3000);
  display.clearDisplay();
}


Abaixo fotos sketch para Cobra 148 GTL.
Frequência em CLK1 Modo AM.
Frequência em CLK1 Modo LSB.
Frequência em CLK1 Modo USB.
Modo AM frequência display.
Frequência Modo AM CLK0.
Frequência em Modo LSB CLK0.
Frequência Modo USB CLK0.
2- sketch para o Cobra 148 GTL, ou outros equipamentos que tenham o VFO e BFO carrier no modo AM, LSB, USB,  modifiquem a FI nas linhas" volatile int32_t "  no começo do sketch. Poderão ser para os transceptores NajaMinhoca,  Ararinha 27 Mhz e outros convertido Walkie Talkie SSB 40 ou 11 metros. Modifiquem a FI no sketch, já expliquei acima desta postagem.

/********************************************************************************
 Sketch modified and copied from the youtube open source 
 CT7API Manuel Ferreira. 
 by Waldir Cardoso. 08/2025. https://projetosetransceptores.blogspot.com/
 Blog: Projetos e Transceptores. Brasil.
 this sketch is a VFO 34 Mhz AM SSB Cobra 148 GTL equipments or frequency generator
*********************************************************************************/
//---------------------------------------------------------------------------------
//  Function
// 1.VFO CLK0 34 Mhz AM LSB USB MODE
// 2.BFO CLK1 BFO FI 7.800 Khz AM LSB USB MODE
// 3.STEP(1MHz,100,10,1kHz,100,10,1Hz)
////////////////////////////////////////////////////////////////////////    
//Libraries
#include <si5351.h>                //https://github.com/etherkit/Si5351Arduino/releases/tag/v1.1.2
#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
//----------------------------------------------------------------------------------------------------
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define Adafruit Si5351 BUS BASE ADDR
#define F_MIN        100000000UL
#define F_MAX        23000000000UL
#define ENCODER_A    2
#define ENCODER_B    3
#define ENCODER_BTN  5
#define USB_PIN 6
#define LSB_PIN 7
#define AM_PIN  8
int lsbstate = 0;
int amstate = 0;
int usbstate = 0;

Si5351 si5351;  //Si5351 I2C Address 0x60
Rotary r = Rotary(3, 2);
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 = "";

#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) 
  set_frequency(1);
  else if (result == DIR_CCW) 
  set_frequency(-1);
}
/**************************************/
/* Change the frequency               */
/* dir = 1    Increment               */
/* dir = -1   Decrement               */
/**************************************/
void set_frequency(short dir)
{
  if (dir == 1)
     vfo += radix;
     if (dir == -1){
     if  (vfo > radix ) {
    vfo -= radix;
     }}
  //if (dir == 1)
    //vfo += radix;
  //if (dir == -1)
    //vfo -= radix;
  changed_f = 1;
 }  
/**************************************/
/* Read the button with debouncing    */
/**************************************/
boolean get_button()
{
  if (!digitalRead(ENCODER_BTN))
  {
    delay(20);
    if (!digitalRead(ENCODER_BTN))
    {
      while (!digitalRead(ENCODER_BTN));
      return 1;
    }
  }
  return 0;
}

/**************************************/
/* Displays the frequency             */
/**************************************/
void display_frequency()
{
  uint16_t f, g;

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,1);
  display.print("      MODE ");
  display.println(tbfo);

  /**************************************/
  /* Displays the frequency change step */
  /**************************************/ 
  switch (radix)
  {
    case 1:
      display.println("                  1Hz");
      break;
    case 10:
      display.println("                 10Hz");
      break;
    case 100:
      display.println("               100Hz");
      break;
    case 1000:
      display.println("           1KHz");
      break;
    case 10000:
      display.println("         10KHz");
      break;
    case 100000:
      display.println("       100KHz");
      break;
      case 1000000:
      display.println("   1MHz");   
      break;
  }
  
  /**************************************/
  /* Displays the frequency             */
  /**************************************/

  display.setTextSize(2);

  f = vfo / 1000000;  //variable is now vfo instead of 'frequency'
  if (f < 10)
  display.print(' ');
  display.print(f);
  display.print('.');
  f = (vfo % 1000000) / 1000;
  if (f < 100)
  display.print('0');
  if (f < 10)
  display.print('0');
  display.print(f);
  display.print('.');
  f = vfo % 1000;
  if (f < 100)
    display.print('0');
  if (f < 10)
    display.print('0');
  display.print(f);
  display.display();
  display.clearDisplay();
}
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);
   
   si5351.set_correction(18000); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  //where you can determine the correction by using the serial monitor.
     
  //initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); //If you're using a 27Mhz crystal, put in 27000000 instead of 0
  // 0 is the default crystal frequency of 25Mhz.

  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);

  si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);  
  si5351.set_freq((bfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK1);
  
  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); //you can set this to 2MA, 4MA, 6MA or 8MA
  si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_6MA); //be careful though - measure into 50 ohms
  //si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA); //
#endif
  Splash();

  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
}

void loop()
{
  // Update the display if the frequency has been changed
  // if (changed_f)
  {
    display_frequency();
 
#ifdef IF_Offset 
    
    Serial.println((long)((vfo * SI5351_FREQ_MULT) + bfo) * -1);
    //si5351.set_freq(((vfo * SI5351_FREQ_MULT) - bfo), SI5351_PLL_FIXED, SI5351_CLK1);    // subtrai á IF
    //you can also subtract the bfo to suit your needs
    si5351.set_freq((vfo * SI5351_FREQ_MULT) + bfo  , SI5351_PLL_FIXED, SI5351_CLK0);  // soma á IF
    si5351.set_freq( bfo,0,SI5351_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";
    }                 
    changed_f = 0;
  }

  // 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();
  }
 }

  void Splash() {
  display.setTextSize(1);
  display.setCursor(4, 5);
  display.print("     Cobra 148");
  display.setCursor(4, 25);
  display.print("        GTL");
  display.display();
  delay(3000);
  display.clearDisplay();
}

3-sketch para equipamentos CLK0 VFO 27 Mhz, conversão direta, CLK1 FI 10 Mhz BFO AM, LSB, USB, poderá ser usado no transceptor 27 Mhz e outros.

/**********************************************************************************
 Sketch modified and copied from the youtube open source 
 CT7API Manuel Ferreira. 
 by Waldir Cardoso. 08/2025. https://projetosetransceptores.blogspot.com/
 Blog: Projetos e Transceptores. Brasil.
 this sketch is a VFO Direct conversion BFO AM SSB equipments or frequency generator
***********************************************************************************/
//---------------------------------------------------------------------------------
//  Function
// 1.VFO CLK0 26 Mhz AM MODE
// 2.BFO CLK1 BFO FI 10.000 Khz AM LSB USB MODE
// 3.STEP(1MHz,100,10,1kHz,100,10,1Hz)
////////////////////////////////////////////////////////////////////////    
//Libraries
#include <si5351.h>                //https://github.com/etherkit/Si5351Arduino/releases/tag/v1.1.2
#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
//----------------------------------------------------------------------------------------------------
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define Adafruit Si5351 BUS BASE ADDR
#define F_MIN        100000000UL
#define F_MAX        23000000000UL
#define ENCODER_A    2
#define ENCODER_B    3
#define ENCODER_BTN  5
#define USB_PIN 6
#define LSB_PIN 7
#define AM_PIN  8
int lsbstate = 0;
int amstate = 0;
int usbstate = 0;

Si5351 si5351;  //Si5351 I2C Address 0x60
Rotary r = Rotary(3, 2);
volatile int32_t AM  = 1000000000ULL;
volatile int32_t LSB =  999850000ULL; //LSB = IF - 1500Hz
volatile int32_t USB = 1000150000ULL; //USB = IF + 1500Hz
volatile int32_t bfo = 1000000000ULL; //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 = "";

#define Direct_conversion //What you see on display is what you get

/**************************************/
/* Interrupt service routine for      */
/* encoder frequency change           */
/**************************************/
ISR(PCINT2_vect) {
  unsigned char result = r.process();
  if (result == DIR_CW) 
  set_frequency(1);
  else if (result == DIR_CCW) 
  set_frequency(-1);
}
/**************************************/
/* Change the frequency               */
/* dir = 1    Increment               */
/* dir = -1   Decrement               */
/**************************************/
void set_frequency(short dir)
{
  if (dir == 1)
     vfo += radix;
     if (dir == -1){
     if  (vfo > radix ) {
    vfo -= radix;
     }}
  //if (dir == 1)
    //vfo += radix;
  //if (dir == -1)
    //vfo -= radix;
  changed_f = 1;
 }  
/**************************************/
/* Read the button with debouncing    */
/**************************************/
boolean get_button()
{
  if (!digitalRead(ENCODER_BTN))
  {
    delay(20);
    if (!digitalRead(ENCODER_BTN))
    {
      while (!digitalRead(ENCODER_BTN));
      return 1;
    }
  }
  return 0;
}

/**************************************/
/* Displays the frequency             */
/**************************************/
void display_frequency()
{
  uint16_t f, g;

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,1);
  display.print("      MODE ");
  display.println(tbfo);

  /**************************************/
  /* Displays the frequency change step */
  /**************************************/ 
  switch (radix)
  {
    case 1:
      display.println("                  1Hz");
      break;
    case 10:
      display.println("                 10Hz");
      break;
    case 100:
      display.println("               100Hz");
      break;
    case 1000:
      display.println("           1KHz");
      break;
    case 10000:
      display.println("         10KHz");
      break;
    case 100000:
      display.println("       100KHz");
      break;
      case 1000000:
      display.println("   1MHz");   
      break;
  }
  
  /**************************************/
  /* Displays the frequency             */
  /**************************************/

  display.setTextSize(2);

  f = vfo / 1000000;  //variable is now vfo instead of 'frequency'
  if (f < 10)
  display.print(' ');
  display.print(f);
  display.print('.');
  f = (vfo % 1000000) / 1000;
  if (f < 100)
  display.print('0');
  if (f < 10)
  display.print('0');
  display.print(f);
  display.print('.');
  f = vfo % 1000;
  if (f < 100)
    display.print('0');
  if (f < 10)
    display.print('0');
  display.print(f);
  display.display();
  display.clearDisplay();
}
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);
   
   si5351.set_correction(18000); //**mine. There is a calibration sketch in File/Examples/si5351Arduino-Jason
  //where you can determine the correction by using the serial monitor.
     
  //initialize the Si5351
  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); //If you're using a 27Mhz crystal, put in 27000000 instead of 0
  // 0 is the default crystal frequency of 25Mhz.

  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);

#ifdef Direct_conversion
  si5351.set_freq((vfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK0);  
  //si5351.set_freq((bfo * SI5351_FREQ_MULT), SI5351_PLL_FIXED, SI5351_CLK1);
#endif 
  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); //you can set this to 2MA, 4MA, 6MA or 8MA
  si5351.drive_strength(SI5351_CLK1,SI5351_DRIVE_6MA); //be careful though - measure into 50 ohms
  //si5351.drive_strength(SI5351_CLK2,SI5351_DRIVE_2MA); //
//#endif
  Splash();

  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
}

void loop()
{
  // Update the display if the frequency has been changed
  // if (changed_f)
  {
    display_frequency();
 
//#ifdef IF_Offset 
    
    Serial.println((long)((vfo * SI5351_FREQ_MULT) + bfo) * -1);
    //si5351.set_freq(((vfo * SI5351_FREQ_MULT) - bfo), SI5351_PLL_FIXED, SI5351_CLK1); // subtrai á IF
    //you can also subtract the bfo to suit your needs
    //si5351.set_freq((vfo * SI5351_FREQ_MULT) + bfo  , SI5351_PLL_FIXED, SI5351_CLK0);  // soma á IF
    si5351.set_freq( bfo,0,SI5351_CLK1);
#ifdef Direct_conversion      
    si5351.set_freq((vfo * SI5351_FREQ_MULT) , SI5351_PLL_FIXED, SI5351_CLK0);  // display frequency
#endif
//#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";
    }                 
    changed_f = 0;
  }

  // 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();
  }
 }

  void Splash() {
  display.setTextSize(1);
  display.setCursor(4, 5);
  display.print("      Transceiver");
  display.setCursor(4, 25);
  display.print("       AM SSB");
  display.display();
  delay(3000);
  display.clearDisplay();
}