Introduction: Arduino Frequency Synthesiser Using 160MHz Si5351
This Instructable describes the construction, and operation, of a stand-alone frequency synthesiser suitable for use as a signal generator, or for use as the local oscillator in an amateur band transmitter or receiver.
My prototype was built on a piece of "Vero" board. The ATmega328P must be socketed if you choose to make your own "Vero" board Arduino. The Arduino source code is well annotated and contains links to all of the required "libraries". Construction is not critical.
Adafruit Si5351A Clock Generator:
The heart of this frequency synthesiser is the "Adafruit Si5351A Clock Generator Breakout Board" which can generate up to three outputs in the frequency range of 8KHz to 160MHz. The Si5351 breakout board is designed to run off 5 volts and has an I2C interface which makes it easy to connect to an Arduino. All that you need is an Arduino, a rotary encoder, a 16 character x 2 line I2C LCD display, and some software. The output level from this synthesiser is approximately 3 volts peak-to-peak.
Rotary Encoder:
The second most important component is the rotary encoder which outputs the following two-bit "Gray" code pattern:
.
11 (indent - CCW)
10
00
01
11 (indent - reference )
10
00
01
11 (indent - CW)
.
The encoder always rests at an indent (pattern 11) when the tuning knob is stationary. If the tuning knob is turned CCW (counter clock-wise) then the pattern sequence between indents is 01, 00, 10, 11. If, however, the tuning knob is turned CW (clock-wise) then the pattern sequence between indents is 10, 00, 01, 11. This pattern reversal allows us to determine the tuning direction. The new frequency is determined by multiplying the number of "indents" by the tuning step-size and adding/subtracting this offset to/from the current frequency.
The rotary encoder comes fitted with a single-pole push switch which I use to control the tuning step-size in increments of 10, 100, 1000, 10000, and 100000 Hz. A brief push on the tuning knob increases the tuning step-size. A longer push on the tuning knob causes the step-size to decrease.
All mechanical switches suffer from contact bounce which makes for erratic tuning. Instead of "debouncing" each switch with hardware I am using a software integrator.
A SPST band-change switch has been included. When the switch is activated it is possible to cycle through each of the amateur radio bands by rotating the tuning knob. The tuning knob behaves normally when the switch is deactivated.
Programming:
Programming the ATmega328P microcontroller is relatively simple. First install the "libraries" documented in "source_code.txt". Paste the contents of "source_code.txt" into a new arduino sketch and save it as "signal_generator.ino". Click "file/upload" and, all going well, "signal _generator.ino" will compile then upload to your Arduino R3 UNO. Once the file has been uploaded, unplug the ATmega328P microcontroller from your Arduino R3 UNO and insert it into your "Vero" board socket. Apply 9 volts and everything should light up.
Important:
Even though the breakout board runs off 5 volts, the Si5351 chip itself runs off 3.3 volts. This means that the maximum voltage from each output is 3.3 volts. A buffer is therefore required when interfacing to 5 volt logic circuits.
Click here to view my other instructables.
17 Comments
Question 2 years ago
Hi,
I have built this project, but using a large VFD display (that has the same interface as a standard two line LCD display) with the intention of making a decent digital signal generator, using a I2C to parellel driver based on the PCF8574 chip.
I have it all working (even gives a spot on 3.50000 MHZ output from the 5351 module). However I cannot get it to read the rotary encoder (though the push button works). I have tried 3 different encoders now, all using the "grey" code as you described, but still will not read the encoder (I am an electronics guy more than a programmer, but cant see anything obvious with the code)
Please Help :-(
Best Regards
George
Answer 2 years ago
Thank you for your interest in my project :)
Changing the display may have altered the Arduino timing slightly which will affect the software debounce algorithm.
Try the code in my instructable https://www.instructables.com/id/Simple-Rotary-De... This decoder uses a simpler algorithm that is extremely robust.
Question 2 years ago on Introduction
Buongiorno
non sono molto esperto nella programmazione di Arduino. La mia domanda:
Se voglio inserire una frequenza diversa degli 80 metri , esempio i 10 oppure i 20, cosa devo fare ?
Grazie
Answer 2 years ago
Grazie per l'interesse dimostrato per il mio progetto :)
Non sono richieste modifiche al codice o al circuito per ricevere qualsiasi frequenza tra trasmissione e 60 MHz.
Esistono due metodi per passare da una band all'altra.
Metodo 1:
L'encoder rotativo è dotato di un interruttore unipolare che utilizzo per controllare la dimensione del passo di sintonizzazione con incrementi di 10, 100, 1000, 10000 e 100000 Hz. Una breve pressione sulla manopola di sintonizzazione aumenta la dimensione del passo di sintonizzazione. Una pressione più lunga sulla manopola di sintonizzazione fa diminuire le dimensioni del passo.
Per cambiare tra 3,5 MHz e dire 14,1 MHz è necessario:
- premere brevemente la manopola di sintonia fino a quando il cursore "*" si trova sotto "3", quindi ruotare la manopola di sintonia fino a quando sul display non viene visualizzato "14,5 MHz"
- premere a lungo la manopola di sintonia fino a quando il cursore "*" si trova sotto "5", quindi ruotare la manopola di sintonia fino a quando sul display non viene visualizzato "14.1MHz".
Metodo 2:
È stato incluso un interruttore di cambio banda SPST. Quando l'interruttore è attivato, è possibile scorrere ciascuna delle bande radio amatoriali ruotando la manopola di sintonia. La manopola di sintonia si comporta normalmente quando l'interruttore è disattivato.
Per cambiare tra 3,5 MHz e dire 14,1 MHz è necessario:
- Attiva l'interruttore
- Ruota la manopola di sintonia fino a raggiungere 14 MHz
- Disattiva l'interruttore
- Posizionare il cursore "*" per dire incrementi di sintonia a 1000Hz e sintonizzarsi normalmente.
La frequenza di uscita per il sintetizzatore nel mio istruttivo https://www.instructables.com/id/Arduino-Frequenc... genera un segnale alla frequenza del display.
Il codice del sintetizzatore nel mio istruttore https://www.instructables.com/id/Arduino-Frequenc... è quasi identico al codice per il sintetizzatore di frequenza sopra, tranne per il fatto che la frequenza di uscita è doppia rispetto alla frequenza di visualizzazione consentire il circuito di divisione per due sulla scheda del ricevitore.
Il metodo di ottimizzazione è lo stesso per entrambi gli strumenti.
Thank you for your interest in my project :)
No code or circuit changes are required to receive any frequency between broadcast and 60MHz.
There are two methods for changing between amateur bands.
Method 1:
The rotary encoder comes fitted with a single-pole push switch which I use to control the tuning step-size in increments of 10, 100, 1000, 10000, and 100000 Hz. A brief push on the tuning knob increases the tuning step-size. A longer push on the tuning knob causes the step-size to decrease.
To change between 3.5MHz and say 14.1MHz you need to:
- briefly push the tuning knob until the "*" cursor is under the "3" then rotate the tuning knob until the display reads "14.5MHz"
- long-push the tuning knob until the "*" cursor is under the "5" then rotate the tuning knob until the display reads "14.1MHz".
Method 2:
A SPST band-change switch has been included. When the switch is activated it is possible to cycle through each of the amateur radio bands by rotating the tuning knob. The tuning knob behaves normally when the switch is deactivated.
To change between 3.5MHz and say 14.1MHz you need to:
- Activate the switch
- Rotate the tuning knob until you reach 14MHz
- De-activate the switch
- Position the "*" cursor to say 1000Hz tuning increments and tune normally.
The output frequency for the synthesiser in my instructable https://www.instructables.com/id/Arduino-Frequenc... generates a signal at the display frequency.
The synthesiser code in my instructable https://www.instructables.com/id/All-Band-Direct-... is almost identical to the code for the above frequency synthesiser except that the output frequency is twice the display frequency to allow for the divide-by-two circuit on the receiver board.
The tuning method is the same for both instructables.
6 years ago
What library do you used?
Reply 6 years ago
The "si5351" library may be found at https://github.com/etherkit/Si5351Arduino
The "si5351.h" and "si5351.cpp" files are contained in a folder named "src" which must be renamed to "si5351" (without the quotes).
The correct liquid crystal library depends on your LCD. I used one from http://arduino-info.wikispaces.com/LCD-Blue-I2C#v1
Reply 3 years ago
Hello,
I have built this generator and of course, the Si5351 part is NOT working
This post is confusing rename to what it is already called?????
Any help?
Reply 3 years ago
Thank you for your interest in this project :)
This project definitely works using the libraries that were available at the time of writing. Since then some of the libraries have changed.
The actual libraries that I used are attached to my reply(s) to Custech in the comment section below. Try downloading these ... hopefully these libraries will solve your problem.
Question 4 years ago
Hello, thank you for sharing your project and congratulations! I would like to ask you which version of the si5351 library did you use? I'm having problems compiling with many errors. The functions of the library and the code have different numbers of arguments. For example si5351.init () in your code has a single argument but in the library you indicated all the versions have two or three arguments. Does not work. Can you help me?
Answer 4 years ago
Thank you for your interest in my project :)
There are many I2C libraries for 16 character x 2 line LCD displays. Depending on your LCD some libraries may not work.
You comment "For example si5351.init () in your code has a single argument but in the library you indicated all the versions have two or three arguments." indicates that you are using a more recent library from https://github.com/etherkit/Si5351Arduino.
I have just looked at this site and it appears that the code has changed as under the heading "Changes from v1 to v2" it reads: "The init() method now has three parameters: the crystal load capacitance, the reference frequency, and the frequency correction value (with this last parameter being a new addition). You'll need to add that third parameter to your old init() calls, but then you can delete any set_correction() calls after that (unless you explicitly are changing the frequency correction after the initialization)."
This explains why my code (it's now two years old) only has a single parameter. It would appear that extra parameters must be added to some of my code lines if you wish to use the latest github code.
Also your comment "For example si5351.init() in your code has a single argument but in the library you indicated all the versions have two or three arguments." has me puzzled as there is no "si5351.init()" in my code. In line 40 I instantiate the word "clockgen" then use "clockgen.init()" in line 57?
The site http://arduino-info.wikispaces.com/LCD-Blue-I2C#v1 (see my code line 23) contains much helpful information ... but visit this site before July 31 as a pop-up message indicates that this site will no longer be available after this date.
My 16x2 line LCD is marked "YwRobot Arduino LCM1602 IIC V1" and the library I used from this site has a link "LCD Version 1 - Marked "YwRobot Arduino LCM1602 IIC V1" ALSO version marked "A0 A1 A2" on lower right (and also labelled "MH")".
When you click this link you are taken to a sample sketch in which there is a reference to https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/ which also contains a number of I2C libraries. Perhaps you could try one of these?
See also my comments to AdrianF2 below who asked "What library do you used?"
Reply 4 years ago
Hello, thank you for kindly responding. The part of the display did not give any error message so I do not think it will be a problem. But thanks for the tips. In the source code you mention the web address and the version of the display library that you used then became easy. I used the file Newliquidcrystal_1.3.5.zip at the indicated web address. The file name itself already tells you which version it is. The Si5351 library is what looks like a headache. I followed your guidelines for AdrianF2 but my problems are after that. It would be very simple if there was still the version of the library you used available for download. I will work with this new version following your guidelines. I apologize for my error Si5351.init (). I wanted to refer to the class method in the library that was changed and not to the clockgen object in your source code. I meant Si5351 :: init (). I will work here and when I finish I will post here the libraries and modifications that I made to work. Once again thank you very much for your kindness in helping.
Reply 4 years ago
Hi,
A zipped version of the (original) LiquidCrystal_I2C library is attached.
Thanks for drawing my attention to the fact that the original libraries have been updated.
Look forward to seeing your code updates.
Reply 4 years ago
Hi, thanks for attaching the display library. It will certainly be of help. But my problem as I mentioned is in the Si5351 library. I do not want to abuse your generosity. But could not you also send the library you used from Si5351? I'm sure it would make it a lot easier for me and other readers who want to build this project without having to go into the new Si5351 library. Many thanks again for your always generous help.
Reply 4 years ago
Hi,
This is the only other library that I can find. The files are dated 1/05/2017 ... hopefully this is what you are looking for.
Reply 4 years ago
Thanks a lot for the help. It will be useful to me and other readers I'm sure. Thank you so much!
7 years ago
Great synthesiser project.
Reply 7 years ago
Thank you :)