![]() |
Descrição
Gerador de clock Si5351A !
Este módulo foi construido especialmente para trabalhar sobre o Arduino Pro Mini ,nada impede de usar qualquer outra versão de placa .Usa se um cristal de 25MHz ou 27MHz , PLL
interno e divisores para que possa gerar praticamente qualquer
freqüência, de <8KHz até 150+ MHz.
O DDS Si5351A é um gerador de clock controlado I2C. Ele usa o clock para acionar vários PLLs e divisores , usando instruções I2C. Ao configurar o PLL e os divisores, você pode criar frequências precisas e arbitrárias. Existem três saídas independentes e cada uma pode ter uma frequência diferente.
Exemplo de esquema
Exemplo de código
Si5351_VFO.ino
}
Forte 73
O DDS Si5351A é um gerador de clock controlado I2C. Ele usa o clock para acionar vários PLLs e divisores , usando instruções I2C. Ao configurar o PLL e os divisores, você pode criar frequências precisas e arbitrárias. Existem três saídas independentes e cada uma pode ter uma frequência diferente.
Exemplo de esquema
Exemplo de código
Si5351_VFO.ino
| /* |
| Si5351 VFO |
| By LA3PNA 27 March 2015 |
| Modified by NT7S 25 April 2015 |
| Modified to be Si5351 Arduino v2 compliant by NT7S 21 Nov 2016 |
| This version uses the new version of the Si5351 library from NT7S. |
| see: http://arduino.cc/en/Reference/AttachInterrupt for what pins that have interrupts. |
| UNO and 328 boards: Encoder on pin 2 and 3. Center pin to GND. |
| Leonardo: Encoder on pin 0 and 1. Center pin to GND. |
| 100nF from each of the encoder pins to gnd is used to debounce |
| The pushbutton goes to pin 11 to set the tuning rate. |
| Pin 12 is the RX/TX pin. Put this pin LOW for RX, open or high for TX. |
| Single transistor switch to +RX will work. |
| VFO will NOT tune in TX. |
| LCD connections for for the LinkSprite 16 X 2 LCD Keypad Shield for Arduino. |
| Change as necessary for your LCD. |
| IF frequency is positive for sum product (IF = RF + LO) and negative for diff (IF = RF - LO) |
| VFO signal output on CLK0, BFO signal on CLK2 |
| */ |
| // Only leave one uncommented for the display you wish to use |
| #define OLED |
| //#define LCD |
| #include <si5351.h> |
| #include "Wire.h" |
| // Conditional includes based on which display is defined above |
| #if defined(LCD) |
| #include <LiquidCrystal.h> |
| LiquidCrystal lcd( 8, 9, 4, 5, 6, 7 ); |
| #endif |
| #if defined(OLED) |
| #include "U8glib.h" |
| U8GLIB_SSD1306_128X64_2X u8g(U8G_I2C_OPT_NONE); // I2C / TWI |
| #endif |
| // Class instantiation |
| Si5351 si5351; |
| // interrupt service routine vars |
| boolean A_set = false; |
| boolean B_set = false; |
| volatile unsigned long frequency = 7100000UL; // This will be the frequency it always starts on. |
| volatile int tx; |
| unsigned long iffreq = 0; // set the IF frequency in Hz. |
| const unsigned long freqstep[] = {50, 100, 500, 1000, 5000, 10000}; // set this to your wanted tuning rate in Hz. |
| int corr = 0; // this is the correction factor for the Si5351, use calibration sketch to find value. |
| unsigned int lastReportedPos = 1; // change management |
| static boolean rotating = false; // debounce management |
| int inData; |
| int txpin = 12; |
| int freqsteps = 1; |
| int stepbutton = 11; |
| #define arraylength (sizeof(freqstep) / sizeof(freqstep[0])) |
| // Define hardware pins based on platform |
| #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) |
| int encoderPinA = 0; // right |
| int encoderPinB = 1; // left |
| #endif |
| #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) |
| int encoderPinA = 2; // right |
| int encoderPinB = 3; // left |
| #endif |
| // Interrupt on A changing state |
| void doEncoderA() |
| { |
| // debounce |
| if (rotating) delay (1); // wait a little until the bouncing is done |
| // Test transition, did things really change? |
| if (digitalRead(encoderPinA) != A_set) { // debounce once more |
| A_set = !A_set; |
| // adjust counter + if A leads B |
| if (A_set && !B_set) { |
| if (!tx) { |
| frequency += freqstep[freqsteps]; // hehre is the amount to increase the freq |
| } |
| rotating = false; // no more debouncing until loop() hits again |
| } |
| } |
| } |
| // Interrupt on B changing state, same as A above |
| void doEncoderB() |
| { |
| if (rotating) delay (1); |
| if (digitalRead(encoderPinB) != B_set) { |
| B_set = !B_set; |
| // adjust counter - 1 if B leads A |
| if (B_set && !A_set) { |
| if (!tx) { |
| frequency -= freqstep[freqsteps]; // here is the amount to decrease the freq |
| } |
| rotating = false; |
| } |
| } |
| } |
| void sprintf_seperated(char *str, unsigned long num) |
| { |
| // We will print out the frequency as a fixed length string and pad if less than 100s of MHz |
| char temp_str[6]; |
| int zero_pad = 0; |
| // MHz |
| if(num / 1000000UL > 0) |
| { |
| sprintf(str, "%3lu", num / 1000000UL); |
| zero_pad = 1; |
| } |
| else |
| { |
| strcat(str, " "); |
| } |
| num %= 1000000UL; |
| // kHz |
| if(zero_pad == 1) |
| { |
| sprintf(temp_str, ",%03lu", num / 1000UL); |
| strcat(str, temp_str); |
| } |
| else if(num / 1000UL > 0) |
| { |
| sprintf(temp_str, ",%3lu", num / 1000UL); |
| strcat(str, temp_str); |
| zero_pad = 1; |
| } |
| else |
| { |
| strcat(str, " "); |
| } |
| num %= 1000UL; |
| // Hz |
| if(zero_pad == 1) |
| { |
| sprintf(temp_str, ",%03lu", num); |
| strcat(str, temp_str); |
| } |
| else |
| { |
| sprintf(temp_str, ",%3lu", num); |
| strcat(str, temp_str); |
| } |
| strcat(str, " MHz"); |
| } |
| #if defined(OLED) |
| void draw_oled(void) |
| { |
| char temp_str[21]; |
| u8g.setFont(u8g_font_unifont); |
| //u8g.setFont(u8g_font_helvR12); |
| sprintf_seperated(temp_str, frequency); |
| u8g.drawStr(0, 32, temp_str); |
| u8g.setFont(u8g_font_unifont); |
| sprintf(temp_str, "Step: %5u", freqstep[freqsteps]); |
| u8g.drawStr(0, 56, temp_str); |
| } |
| #endif |
| #if defined(LCD) |
| void draw_lcd(void) |
| { |
| char temp_str[21]; |
| sprintf_seperated(temp_str, frequency); |
| lcd.setCursor(0, 0); |
| lcd.print(temp_str); |
| lcd.setCursor(6, 1); |
| sprintf(temp_str, "%5u", freqstep[freqsteps]); |
| lcd.print(temp_str); |
| } |
| #endif |
| void setup() |
| { |
| Serial.begin(9600); |
| // Set GPIO |
| pinMode(encoderPinA, INPUT); |
| pinMode(encoderPinB, INPUT); |
| pinMode(stepbutton, INPUT); |
| pinMode(txpin, INPUT); |
| // Turn on pullup resistors |
| digitalWrite(encoderPinA, HIGH); |
| digitalWrite(encoderPinB, HIGH); |
| digitalWrite(stepbutton, HIGH); |
| digitalWrite(txpin, HIGH); |
| #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) |
| //Code in here will only be compiled if an Arduino Leonardo is used. |
| // encoder pin on interrupt 0 (pin 0) |
| attachInterrupt(0, doEncoderA, CHANGE); |
| // encoder pin on interrupt 1 (pin 1) |
| attachInterrupt(1, doEncoderB, CHANGE); |
| #endif |
| #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) |
| //Code in here will only be compiled if an Arduino Uno (or older) is used. |
| // encoder pin on interrupt 0 (pin 2) |
| attachInterrupt(0, doEncoderA, CHANGE); |
| // encoder pin on interrupt 1 (pin 3) |
| attachInterrupt(1, doEncoderB, CHANGE); |
| #endif |
| // Initialize the display |
| #if defined(LCD) |
| lcd.begin(16, 2); |
| lcd.print("Si5351 VFO"); |
| delay(2000); |
| lcd.clear(); |
| lcd.setCursor(0, 1); |
| lcd.print("Step: "); |
| #endif |
| #if defined(OLED) |
| //U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // I2C / TWI |
| // Assign default color value |
| if (u8g.getMode() == U8G_MODE_R3G3B2) |
| { |
| u8g.setColorIndex(255); // white |
| } |
| else if (u8g.getMode() == U8G_MODE_GRAY2BIT) |
| { |
| u8g.setColorIndex(3); // max intensity |
| } |
| else if (u8g.getMode() == U8G_MODE_BW) |
| { |
| u8g.setColorIndex(1); // pixel on |
| } |
| else if (u8g.getMode() == U8G_MODE_HICOLOR) |
| { |
| u8g.setHiColorByRGB(255,255,255); |
| } |
| #endif |
| si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, corr); |
| si5351.set_freq((frequency + iffreq) * 100ULL, SI5351_CLK0); |
| si5351.set_freq(iffreq * 100ULL, SI5351_CLK2); |
| } |
| void loop() |
| { |
| if(digitalRead(txpin)) |
| { |
| tx = 0; |
| } |
| else |
| { |
| tx = 1; |
| } |
| rotating = true; // reset the debouncer |
| if (lastReportedPos != frequency) |
| { |
| lastReportedPos = frequency; |
| // Handle LCD |
| #if defined(LCD) |
| draw_lcd(); |
| #endif |
| si5351.set_freq((frequency + iffreq) * 100ULL, SI5351_CLK0); |
| } |
| // Handle OLED |
| #if defined(OLED) |
| u8g.firstPage(); |
| do |
| { |
| draw_oled(); |
| } while(u8g.nextPage()); |
| delay(50); |
| #endif |
| if (Serial.available() > 0) // see if incoming serial data: |
| { |
| inData = Serial.read(); // read oldest byte in serial buffer: |
| } |
| if (inData == 'F') |
| { |
| frequency = Serial.parseInt(); |
| inData = 0; |
| } |
| if (digitalRead(stepbutton) == LOW ) |
| { |
| delay(50); // delay to debounce |
| if (digitalRead(stepbutton) == LOW ) |
| { |
| freqsteps = freqsteps + 1; |
| if (freqsteps > arraylength - 1 ) |
| { |
| freqsteps = 0; |
| } |
| delay(50); //delay to avoid many steps at one |
| } |
| } |
Forte 73


Nenhum comentário:
Postar um comentário