Forum Électro-Bidouilleur

Sections => Vos projets et Montages d'Électronique => Discussion démarrée par: Manu le mai 02, 2021, 03:08:40 pm

Titre: SI5351A sur Arduino JCR (Modif Oled 128x32)
Posté par: Manu le mai 02, 2021, 03:08:40 pm
Bonjour,

Voici le générateur avec un Arduino Nano et le si5351A que j'ai testé. En suivant la méthode du créateur original (liens add) j'ai donc adapter un écran OLED 128x32 et aussi changer le RX a TX interrupteur par un boutton poussoir.

(https://i.ibb.co/nnw7xYs/IMG-20210502-192015.jpg)
(https://i.ibb.co/mXkqXMb/IMG-20210502-192015.jpg)

Liste des fonctions disponibles:
Freq de 10Khz  -  225Mhz Max
IF 455Khz  (Intermediate Frequency "IF" offset, adjustable sur le code Arduino )
mode VFO & L O
Step:
  1 Hz
10 Hz
1 Khz
5 Khz
10 Khz
1 Mhz

Band Preset:
GEN ( Clock Generateur )
MW
160m
80m
60m
49m
40m
31m
25m
22m
20m
19m
16m
13m
11m
10m
6m
WFM
AIR
2m
1m

Matérielles nécessaires:
Oui je sais, tous les composents sont d'excelente qualité.  ;D

-Boite chocolats pour éviter les interférences avec les ovni
(https://i.ibb.co/P4Qr96d/Sin-t-tulowerwe.png)
-Rotary Encoder avec push button
(https://i.ibb.co/94D332J/dfsgvfdvgd.png)
-Arduino Nano
-Oled 128x32
-x2 push button
-si5351A
(https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.RkSg39Xn4ovli7dgXmYoKgHaHa%26pid%3DApi%26h%3D160&f=1)

Test sur mon Siglent SDS1202X-E
(https://i.ibb.co/n3TRjCG/si5351-A-Test-2021.png)


Code adapter pour:
-OLED 128x32 ( manque d'espace j'ai éliminé la GraphBar du Tuner )
-Push button ( éviter les interrupteurs )

/**********************************************************************************************************
  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.

Mod. 2021-05-02
forum.bidouilleur.ca
-128x32 OLED
-Push Button for RX & TX mode
-GraphBar Tuner Removed
***********************************************************************************************************/

//Libraries
#include <Wire.h>                 //IDE Standard
#include <Rotary.h>               //Ben Buxton https://github.com/brianlow/Rotary
#include <si5351.h>               //Etherkit https://github.com/etherkit/Si5351Arduino
#include <Adafruit_GFX.h>         //Adafruit GFX https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_SSD1306.h>     //Adafruit SSD1306 https://github.com/adafruit/Adafruit_SSD1306

//User preferences
//------------------------------------------------------------------------------------------------------------
#define IF         455       //Enter your IF frequency, ex: 455 = 455kHz, 10700 = 10.7MHz, 0 = to direct convert receiver or RF generator, + will add and - will subtract IF offfset.
#define BAND_INIT  2         //Enter your initial Band (1-21) at startup, ex: 1 = Freq Generator, 2 = 800kHz (MW), 7 = 7.2MHz (40m), 11 = 14.1MHz (20m).
#define XT_CAL_F   33000     //Si5351 calibration factor, adjust to get exatcly 10MHz. Increasing this value will decreases the frequency and vice versa.
#define S_GAIN     303       //Adjust the sensitivity of Signal Meter A/D input: 101 = 500mv; 202 = 1v; 303 = 1.5v; 404 = 2v; 505 = 2.5v; 1010 = 5v (max).
#define tunestep   A0        //The pin used by tune step push button.
#define band       A1        //The pin used by band selector push button.
#define rx_tx      A2        //The pin used by RX / TX selector switch, RX = switch open, TX = switch closed to GND. When in TX, the IF value is not considered.
#define adc        A3        //The pin used by Signal Meter A/D input.
//------------------------------------------------------------------------------------------------------------

Rotary r = Rotary(2, 3);
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);
Si5351 si5351;

unsigned long freq, freqold, fstep;
long interfreq = IF, interfreqold = 0;
long cal = XT_CAL_F;
unsigned int smval;
byte encoder = 1;
byte stp, n = 1;
byte stpRXTX, m = 1;
byte count, x, xo;
bool sts = 0;
unsigned int period = 100;
unsigned long time_now = 0;

ISR(PCINT2_vect) {
  char result = r.process();
  if (result == DIR_CW) set_frequency(1);
  else if (result == DIR_CCW) set_frequency(-1);
}

void set_frequency(short dir) {
  if (encoder == 1) {                         //Up/Down frequency
    if (dir == 1) freq = freq + fstep;
    if (freq >= 225000000) freq = 225000000;
    if (dir == -1) freq = freq - fstep;
    if (fstep == 1000000 && freq <= 1000000) freq = 1000000;
    else if (freq < 10000) freq = 10000;
  }
  if (encoder == 1) {                       //Up/Down graph tune pointer
    if (dir == 1) n = n + 1;
    if (n > 42) n = 1;
    if (dir == -1) n = n - 1;
    if (n < 1) n = 42;
  }
}

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(tunestep, INPUT_PULLUP);
  pinMode(band, INPUT_PULLUP);
  pinMode(rx_tx, INPUT_PULLUP);

  //statup_text();  //If you hang on startup, comment

  si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
  si5351.set_correction(cal, SI5351_PLL_INPUT_XO);
  si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA);
  si5351.output_enable(SI5351_CLK0, 1);                  //1 - Enable / 0 - Disable CLK
  si5351.output_enable(SI5351_CLK1, 0);
  si5351.output_enable(SI5351_CLK2, 0);

  PCICR |= (1 << PCIE2);
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
  sei();

  count = BAND_INIT;
  bandpresets();
  stp = 4;
  stpRXTX = 1;
  setstep();
}

void loop() {
  if (freqold != freq) {
    time_now = millis();
    tunegen();
    freqold = freq;
  }

  if (interfreqold != interfreq) {
    time_now = millis();
    tunegen();
    interfreqold = interfreq;
  }

  if (xo != x) {
    time_now = millis();
    xo = x;
  }

  if (digitalRead(tunestep) == LOW) {
    time_now = (millis() + 300);
    setstep();
    delay(300);
  }

  if (digitalRead(band) == LOW) {
    time_now = (millis() + 300);
    inc_preset();
    delay(300);
  }

  if (digitalRead(rx_tx) == LOW) {
    time_now = (millis() + 300);
    RXTX();
    //sts = 1;
    delay(300);
  } //else sts = 0;

  if ((time_now + period) > millis()) {
    displayfreq();
    layout();
  }
  sgnalread();
}

void tunegen() {
  si5351.set_freq((freq + (interfreq * 1000ULL)) * 100ULL, SI5351_CLK0);
}

void displayfreq() {
  unsigned int m = freq / 1000000;
  unsigned int k = (freq % 1000000) / 1000;
  unsigned int h = (freq % 1000) / 1;

  display.clearDisplay();
  display.setTextSize(2);

  char buffer[15] = "";
  if (m < 1) {
    display.setCursor(44, 1); sprintf(buffer, "%003d.%003d", k, h);
  }
  else if (m < 100) {
    display.setCursor(8, 1); sprintf(buffer, "%2d.%003d.%003d", m, k, h);
  }
  else if (m >= 100) {
    unsigned int h = (freq % 1000) / 10;
    display.setCursor(2, 1); sprintf(buffer, "%2d.%003d.%02d", m, k, h);
  }
  display.print(buffer);
}

void setstep() {
  switch (stp) {
    case 1: stp = 2; fstep = 1; break;
    case 2: stp = 3; fstep = 10; break;
    case 3: stp = 4; fstep = 1000; break;
    case 4: stp = 5; fstep = 5000; break;
    case 5: stp = 6; fstep = 10000; break;
    case 6: stp = 1; fstep = 1000000; break;
  }
}


void RXTX() {
  switch (stpRXTX) {
    case 1: stpRXTX = 2; sts = 1;; break;
    case 2: stpRXTX = 1; sts = 0; break;
  }
}

void inc_preset() {
  count++;
  if (count > 21) count = 1;
  bandpresets();
  delay(50);
}

void bandpresets() {
  switch (count)  {
    case 1: freq = 100000; tunegen(); break;
    case 2: freq = 800000; break;
    case 3: freq = 1800000; break;
    case 4: freq = 3650000; break;
    case 5: freq = 4985000; break;
    case 6: freq = 6180000; break;
    case 7: freq = 7200000; break;
    case 8: freq = 10000000; break;
    case 9: freq = 11780000; break;
    case 10: freq = 13630000; break;
    case 11: freq = 14100000; break;
    case 12: freq = 15000000; break;
    case 13: freq = 17655000; break;
    case 14: freq = 21525000; break;
    case 15: freq = 27015000; break;
    case 16: freq = 28400000; break;
    case 17: freq = 50000000; break;
    case 18: freq = 100000000; break;
    case 19: freq = 130000000; break;
    case 20: freq = 144000000; break;
    case 21: freq = 220000000; break;
  }
  si5351.pll_reset(SI5351_PLLA);
  stp = 4; setstep();
}

void layout() {
  display.setTextColor(WHITE);
;
  display.setTextSize(1);
  display.setCursor(56,17);
  if (stp == 2) display.print("  1Hz"); if (stp == 3) display.print(" 10Hz"); if (stp == 4) display.print(" 1kHz");
  if (stp == 5) display.print(" 5kHz"); if (stp == 6) display.print("10kHz"); if (stp == 1) display.print(" 1MHz");
  display.setTextSize(1);
  display.setCursor(83, 25);
  display.print(interfreq);
  display.print("k.IF");
  display.setTextSize(1);
  display.setCursor(35,17);
  if (interfreq == 0) display.print("VFO");
  if (interfreq != 0) display.print("L O");
  display.setCursor(116, 17);
  if (!sts) display.print("RX"); if (!sts) interfreq = IF;
  if (sts) display.print("TX"); if (sts) interfreq = 0;
  bandlist(); drawbargraph();
  display.display();
}

void bandlist() {
  display.setTextSize(1);
  display.setCursor(0, 17);
  if (count == 1) display.print("GEN"); if (count == 2) display.print("MW"); if (count == 3) display.print("160m"); if (count == 4) display.print("80m");
  if (count == 5) display.print("60m"); if (count == 6) display.print("49m"); if (count == 7) display.print("40m"); if (count == 8) display.print("31m");
  if (count == 9) display.print("25m"); if (count == 10) display.print("22m"); if (count == 11) display.print("20m"); if (count == 12) display.print("19m");
  if (count == 13) display.print("16m"); if (count == 14) display.print("13m"); if (count == 15) display.print("11m"); if (count == 16) display.print("10m");
  if (count == 17) display.print("6m"); if (count == 18) display.print("WFM"); if (count == 19) display.print("AIR"); if (count == 20) display.print("2m");
  if (count == 21) display.print("1m");
  if (count == 1) interfreq = 0; else if (!sts) interfreq = IF;
}

void sgnalread() {
  smval = analogRead(adc); x = map(smval, 0, S_GAIN, 1, 14); if (x > 14) x = 14;
}

void drawbargraph() {
  byte y = map(n, 1, 32, 1, 14);
  display.setTextSize(1);
  switch (y) {
  }

  //Bargraph
  display.setCursor(0, 25); display.print("SM");
  switch (x) {
    case 14: display.fillRect(80, 26, 2, 6, WHITE);
    case 13: display.fillRect(75, 26, 2, 6, WHITE);
    case 12: display.fillRect(70, 26, 2, 6, WHITE);
    case 11: display.fillRect(65, 26, 2, 6, WHITE);
    case 10: display.fillRect(60, 26, 2, 6, WHITE);
    case 9: display.fillRect(55, 26, 2, 6, WHITE);
    case 8: display.fillRect(50, 26, 2, 6, WHITE);
    case 7: display.fillRect(45, 26, 2, 6, WHITE);
    case 6: display.fillRect(40, 26, 2, 6, WHITE);
    case 5: display.fillRect(35, 26, 2, 6, WHITE);
    case 4: display.fillRect(30, 26, 2, 6, WHITE);
    case 3: display.fillRect(25, 26, 2, 6, WHITE);
    case 2: display.fillRect(20, 26, 2, 6, WHITE);
    case 1: display.fillRect(15, 26, 2, 6, WHITE);
  }
}

void statup_text() {
  display.setTextSize(1); display.setCursor(13, 9);
  display.print("Si5351 VFO/RF GEN");
  display.setCursor(6, 20);
  display.print("JCR RADIO - Ver 2.0");
  display.display(); delay(2000);
}


Liens du Créateur:
https://create.arduino.cc/projecthub/CesarSound (https://create.arduino.cc/projecthub/CesarSound)
Schema: (remplacer l'interrupteur RX & TX par un bouton poussoir )
(https://hackster.imgix.net/uploads/attachments/1267332/v2_BiosDbFUaA.jpg?auto=compress%2Cformat&w=1280&h=960&fit=max)
SI5351_VFO_RF_GEN_OLED_V2_JCR
https://create.arduino.cc/projecthub/CesarSound/10khz-to-225mhz-vfo-rf-generator-with-si5351-version-2-bfa619?ref=user&ref_id=1465945&offset=0 (https://create.arduino.cc/projecthub/CesarSound/10khz-to-225mhz-vfo-rf-generator-with-si5351-version-2-bfa619?ref=user&ref_id=1465945&offset=0)
Youtube
https://www.youtube.com/watch?v=fsYQ3MWN5KU (https://www.youtube.com/watch?v=fsYQ3MWN5KU)
Dropbox
https://www.dropbox.com/s/60s22lbj80lgfh5/SI5351_VFO_RF_GEN_OLED_V2_JCR.zip?dl=0 (https://www.dropbox.com/s/60s22lbj80lgfh5/SI5351_VFO_RF_GEN_OLED_V2_JCR.zip?dl=0)
PCB
https://www.pcbway.com/project/shareproject/10kHZ_255MHz_SIGNAL_GENERATOR_OLED_LCD.html (https://www.pcbway.com/project/shareproject/10kHZ_255MHz_SIGNAL_GENERATOR_OLED_LCD.html)


Liens EB:
EB_#374 Flash - Plus de Quartz de disponible...Solution Si5351?
https://www.youtube.com/watch?v=iiufQ4UmA7A (https://www.youtube.com/watch?v=iiufQ4UmA7A)
EB_#284....Partie 1
..
EB_#313 Construction - Synthétiseur d'Horloge HF, Partie 9: Premiers essais.
https://www.youtube.com/watch?v=tDw9KD-WG50 (https://www.youtube.com/watch?v=tDw9KD-WG50)
EB_#244 Mini-Plaquette - Synthétiseur HF Si-5351A
https://www.youtube.com/watch?v=l36m98S7QYc (https://www.youtube.com/watch?v=l36m98S7QYc)
EB_#317 Construction - Synthétiseur d'Horloge HF, Partie 10: Le logiciel
https://www.youtube.com/watch?v=_CUuk6Xp7YQ (https://www.youtube.com/watch?v=_CUuk6Xp7YQ)

Liens Cyrob:
Cyrob: Le module Adafruit Si5351A
https://www.youtube.com/watch?v=RpbPqOtwAD4 (https://www.youtube.com/watch?v=RpbPqOtwAD4)
Titre: Re : SI5351A sur Arduino JCR (Modif Oled 128x32)
Posté par: Électro-Bidouilleur le mai 04, 2021, 09:07:15 pm
Beau projet! Bravo. Merci d'avoir partagé.