├── How_to_compile.txt ├── READ.ME ├── antenna_analyzer_p1.ino ├── antuino_schematic.pdf ├── gui.ino ├── ks0108_Arduino.h ├── plot.ino └── si5351.ino /How_to_compile.txt: -------------------------------------------------------------------------------- 1 | The Antuino software uses 128x64 LCD display with KS0108 chipset. 2 | You have to install the GLCD library by clicking on "sketch" menu and choosing "include library" 3 | 4 | IMPORTANT, VERY IMPORTANT: 5 | We had to reconfigure how the GLCD is connected to the Arduino. So it is different from the that of the standard GLCD library's pin configuration. Our custom configuration of the GLCD pin connection is defined in a file called ks0108_Arduino.h 6 | 7 | The libraries are organized as individual folders under an Arduino folder. 8 | You have to move ks0108_Arduino.h to the glcd subfolder under the libraries folder of Arduino IDE. 9 | 10 | 11 | -------------------------------------------------------------------------------- /READ.ME: -------------------------------------------------------------------------------- 1 | # autuino 2 | -------------------------------------------------------------------------------- /antenna_analyzer_p1.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* 7 | * TO DO 8 | * 1. save the last freq, mode 9 | * 2. plot the powerf 10 | */ 11 | 12 | 13 | int nextChar = 0; 14 | unsigned long centerFreq=14000000l; //initially set to 25 MHz 15 | unsigned long spanFreq=25000000l; //intiially set to 50 MHz 16 | long spans[] = { 17 | 25000000l, 18 | 10000000l, 19 | 5000000l, 20 | 1000000l, 21 | 22 | 500000l, 23 | 100000l, 24 | 50000l, 25 | 10000l, 26 | 5000l 27 | }; 28 | 29 | int selectedSpan = 0; 30 | #define MAX_SPANS 8 31 | 32 | int enc_prev_state = 3; 33 | 34 | uint32_t xtal_freq_calibrated = 27000000l; 35 | 36 | /* I/O ports to read the tuning mechanism */ 37 | #define ENC_A (A3) 38 | #define ENC_B (A1) 39 | #define FBUTTON (A2) 40 | 41 | /* offsets into the EEPROM storage for calibration */ 42 | #define MASTER_CAL 0 43 | #define LAST_FREQ 4 44 | #define OPEN_HF 8 45 | #define OPEN_VHF 12 46 | #define OPEN_UHF 16 47 | #define LAST_SPAN 20 48 | #define LAST_MODE 24 49 | 50 | //to switch on/off various clocks 51 | #define SI_CLK0_CONTROL 16 // Register definitions 52 | #define SI_CLK1_CONTROL 17 53 | #define SI_CLK2_CONTROL 18 54 | 55 | #define IF_FREQ (24996000l) 56 | #define MODE_ANTENNA_ANALYZER 0 57 | #define MODE_MEASUREMENT_RX 1 58 | #define MODE_NETWORK_ANALYZER 2 59 | unsigned long mode = MODE_ANTENNA_ANALYZER; 60 | 61 | char b[32], c[32], serial_in[32]; 62 | int return_loss; 63 | unsigned long frequency = 10000000l; 64 | int openHF = 96; 65 | int openVHF = 96; 66 | int openUHF = 68; 67 | 68 | #define DBM_READING (A6) 69 | int dbmOffset = -114; 70 | 71 | int menuOn = 0; 72 | unsigned long timeOut = 0; 73 | 74 | 75 | const int PROGMEM vswr[] = { 76 | 999, 77 | 174, 78 | 87, 79 | 58, 80 | 44, 81 | 35, 82 | 30, 83 | 26, 84 | 23, 85 | 21, 86 | 19, 87 | 18, 88 | 17, 89 | 16, 90 | 15, 91 | 14, 92 | 14, 93 | 13, 94 | 13, 95 | 12, 96 | 12, 97 | 12, 98 | 12, 99 | 11, 100 | 11, 101 | 11, 102 | 11, 103 | 1, 104 | 10, 105 | 10, 106 | 10 107 | }; 108 | 109 | 110 | void active_delay(int delay_by){ 111 | unsigned long timeStart = millis(); 112 | 113 | while (millis() - timeStart <= delay_by) { 114 | //Background Work 115 | } 116 | } 117 | 118 | int tuningClicks = 0; 119 | int tuningSpeed = 0; 120 | 121 | void updateDisplay(){ 122 | sprintf(b, "%ldK, %ldK/div", frequency/1000, spanFreq/10000); 123 | GLCD.DrawString(b, 20, 57); 124 | } 125 | 126 | int calibrateClock(){ 127 | int knob = 0; 128 | int32_t prev_calibration; 129 | char *p; 130 | 131 | GLCD.ClearScreen(); 132 | GLCD.DrawString("1. Monitor Antenna", 0, 0); 133 | GLCD.DrawString(" port on 10 MHz freq.", 0, 10); 134 | GLCD.DrawString("2. Tune to zerbeat and", 0, 20); 135 | GLCD.DrawString("3. Click to Save", 0, 30); 136 | 137 | GLCD.DrawString("Save", 64, 45); 138 | GLCD.DrawRect(60,40,35,20); 139 | 140 | 141 | //keep clear of any previous button press 142 | while (btnDown()) 143 | active_delay(100); 144 | active_delay(100); 145 | 146 | prev_calibration = xtal_freq_calibrated; 147 | xtal_freq_calibrated = 27000000l; 148 | 149 | si5351aSetFrequency_clk1(10000000l); 150 | ltoa(xtal_freq_calibrated - 27000000l, c, 10); 151 | GLCD.FillRect(0,40,50,15, WHITE); 152 | GLCD.DrawString(c, 4, 45); 153 | 154 | while (!btnDown()) 155 | { 156 | knob = enc_read(); 157 | 158 | if (knob > 0) 159 | xtal_freq_calibrated += 10; 160 | else if (knob < 0) 161 | xtal_freq_calibrated -= 10; 162 | else 163 | continue; //don't update the frequency or the display 164 | 165 | si5351aSetFrequency_clk1(10000000l); 166 | 167 | ltoa(xtal_freq_calibrated - 27000000l, c, 10); 168 | GLCD.FillRect(0,40,50,15, WHITE); 169 | GLCD.DrawString(c, 4, 45); 170 | } 171 | 172 | while(btnDown()) 173 | delay(100); 174 | delay(100); 175 | GLCD.ClearScreen(); 176 | GLCD.DrawString("Calibration Saved", 0, 25); 177 | 178 | EEPROM.put(MASTER_CAL, xtal_freq_calibrated); 179 | delay(2000); 180 | } 181 | 182 | int readOpen(unsigned long f){ 183 | int i, r; 184 | 185 | takeReading(f); 186 | delay(100); 187 | r = 0; 188 | for (i = 0; i < 10; i++){ 189 | r += analogRead(DBM_READING)/5; 190 | delay(50); 191 | } 192 | delay(1000); 193 | 194 | return r/10; 195 | } 196 | 197 | int calibrateMeter(){ 198 | 199 | GLCD.ClearScreen(); 200 | GLCD.DrawString("Disconnect Antenna", 0, 0); 201 | GLCD.DrawString("port and press Button", 0, 10); 202 | GLCD.DrawString("to calibrate SWR", 0, 20); 203 | GLCD.DrawString("OK", 10, 42); 204 | GLCD.DrawRect(5,35,20,20); 205 | 206 | //wait for a button down 207 | while(!btnDown()) 208 | active_delay(50); 209 | 210 | GLCD.ClearScreen(); 211 | GLCD.DrawString("Calibrating.....", 10, 25); 212 | delay(1000); 213 | 214 | int i, r; 215 | mode = MODE_ANTENNA_ANALYZER; 216 | delay(100); 217 | r = readOpen(20000000l); 218 | Serial.print("open reading of HF is ");Serial.println(r); 219 | EEPROM.put(OPEN_HF, r); 220 | 221 | r = readOpen(140000000l); 222 | Serial.print("open reading of VHF is ");Serial.println(r); 223 | EEPROM.put(OPEN_VHF, r); 224 | 225 | r = readOpen(440000000l); 226 | Serial.print("open reading of UHF is ");Serial.println(r); 227 | EEPROM.put(OPEN_UHF, r); 228 | 229 | menuOn = 0; 230 | 231 | GLCD.ClearScreen(); 232 | GLCD.DrawString("Done!",10,25); 233 | delay(1000); 234 | 235 | //switch off just the tracking source 236 | si5351aOutputOff(SI_CLK0_CONTROL); 237 | takeReading(centerFreq); 238 | updateDisplay(); 239 | } 240 | 241 | int openReading(unsigned long f){ 242 | if (f < 60000000l) 243 | return openHF; 244 | else if (f < 150000000l) 245 | return openVHF; 246 | else 247 | return openUHF; 248 | } 249 | 250 | long prev_freq = 0; //this is used only inside takeReading, it should have been static local 251 | int prevMode = 0; 252 | void takeReading(long newfreq){ 253 | long local_osc; 254 | 255 | if (newfreq < 20000l) 256 | newfreq = 20000l; 257 | if (newfreq < 150000000l) 258 | { 259 | if (newfreq < 50000000l) 260 | local_osc = newfreq + IF_FREQ; 261 | else 262 | local_osc = newfreq - IF_FREQ; 263 | } else { 264 | newfreq = newfreq / 3; 265 | local_osc = newfreq - IF_FREQ/3; 266 | } 267 | 268 | if (prev_freq != newfreq || prevMode != mode){ 269 | switch(mode){ 270 | case MODE_MEASUREMENT_RX: 271 | si5351aSetFrequency_clk2(local_osc); 272 | si5351aOutputOff(SI_CLK1_CONTROL); 273 | si5351aOutputOff(SI_CLK0_CONTROL); 274 | break; 275 | case MODE_NETWORK_ANALYZER: 276 | si5351aSetFrequency_clk2(local_osc); 277 | si5351aOutputOff(SI_CLK1_CONTROL); 278 | si5351aSetFrequency_clk0(newfreq); 279 | break; 280 | default: 281 | si5351aSetFrequency_clk2(local_osc); 282 | si5351aSetFrequency_clk1(newfreq); 283 | si5351aOutputOff(SI_CLK0_CONTROL); 284 | } 285 | prev_freq = newfreq; 286 | prevMode = mode; 287 | // Serial.print(mode);Serial.print(':'); 288 | // Serial.println(prev_freq); 289 | } 290 | } 291 | 292 | void setup() { 293 | GLCD.Init(); 294 | GLCD.SelectFont(System5x7); 295 | 296 | Serial.begin(9600); 297 | Serial.print("Listening: \n"); 298 | //setupVSWRGrid(); 299 | b[0]= 0; 300 | 301 | Wire.begin(); 302 | Serial.begin(9600); 303 | Serial.flush(); 304 | Serial.println(F("*Antuino v1.2")); 305 | analogReference(DEFAULT); 306 | 307 | unsigned long last_freq = 0; 308 | EEPROM.get(MASTER_CAL, xtal_freq_calibrated); 309 | EEPROM.get(LAST_FREQ, last_freq); 310 | EEPROM.get(OPEN_HF, openHF); 311 | EEPROM.get(OPEN_VHF, openVHF); 312 | EEPROM.get(OPEN_UHF, openUHF); 313 | EEPROM.get(LAST_SPAN, selectedSpan); 314 | EEPROM.get(LAST_MODE, mode); 315 | 316 | //the openHF reading is actually -19.5 dbm 317 | dbmOffset = -19.5 - openHF; 318 | 319 | Serial.println(last_freq); 320 | if (0 < last_freq && last_freq < 500000000l) 321 | centerFreq = last_freq; 322 | 323 | if (xtal_freq_calibrated < 26900000l || xtal_freq_calibrated > 27100000l) 324 | xtal_freq_calibrated = 27000000l; 325 | 326 | if (mode < 0 || mode > 2) 327 | mode = 0; 328 | 329 | spanFreq = spans[selectedSpan]; 330 | 331 | pinMode(ENC_A, INPUT_PULLUP); 332 | pinMode(ENC_B, INPUT_PULLUP); 333 | pinMode(FBUTTON, INPUT_PULLUP); 334 | 335 | updateScreen(); 336 | 337 | // printLine2(F("Antuino v2.0")); 338 | 339 | if (btnDown()){ 340 | calibration_mode(); 341 | } 342 | 343 | si5351aOutputOff(SI_CLK0_CONTROL); 344 | takeReading(frequency); 345 | updateMeter(); 346 | } 347 | 348 | int prev = 0; 349 | void loop() 350 | { 351 | doMenu(); 352 | // doTuning2(); 353 | // checkButton(); 354 | 355 | int r = analogRead(DBM_READING); 356 | if (r != prev){ 357 | takeReading(centerFreq); 358 | updateMeter(); 359 | prev = r; 360 | } 361 | 362 | delay(50); 363 | } 364 | -------------------------------------------------------------------------------- /antuino_schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/afarhan/antuino/82e5cd45595af8d53cb1ecd486c2c690a6bebdca/antuino_schematic.pdf -------------------------------------------------------------------------------- /gui.ino: -------------------------------------------------------------------------------- 1 | int x1, y1, w, h, x2, y2; 2 | #define X_OFFSET 18 3 | 4 | 5 | #define MENU_CHANGE_MHZ 0 6 | #define MENU_CHANGE_KHZ 1 7 | #define MENU_CHANGE_HZ 2 8 | #define MENU_MODE_SWR 3 9 | #define MENU_MODE_PWR 4 10 | #define MENU_MODE_SNA 5 11 | #define MENU_SPAN 6 12 | #define MENU_PLOT 7 13 | 14 | #define ACTION_SELECT 1 15 | #define ACTION_DESELECT 2 16 | #define ACTION_UP 3 17 | #define ACTION_DOWN 4 18 | 19 | int uiFocus = MENU_CHANGE_MHZ, knob=0, uiSelected = -1; 20 | 21 | 22 | //returns true if the button is pressed 23 | int btnDown(){ 24 | if (digitalRead(FBUTTON) == HIGH) 25 | return 0; 26 | else 27 | return 1; 28 | } 29 | 30 | byte enc_state (void) { 31 | return (analogRead(ENC_A) > 500 ? 1 : 0) + (analogRead(ENC_B) > 500 ? 2: 0); 32 | } 33 | 34 | int enc_read(void) { 35 | int result = 0; 36 | byte newState; 37 | int enc_speed = 0; 38 | 39 | long stop_by = millis() + 100; 40 | 41 | while (millis() < stop_by) { // check if the previous state was stable 42 | newState = enc_state(); // Get current state 43 | 44 | if (newState != enc_prev_state) 45 | delay (1); 46 | 47 | if (enc_state() != newState || newState == enc_prev_state) 48 | continue; 49 | //these transitions point to the encoder being rotated anti-clockwise 50 | if ((enc_prev_state == 0 && newState == 2) || 51 | (enc_prev_state == 2 && newState == 3) || 52 | (enc_prev_state == 3 && newState == 1) || 53 | (enc_prev_state == 1 && newState == 0)){ 54 | result--; 55 | } 56 | //these transitions point o the enccoder being rotated clockwise 57 | if ((enc_prev_state == 0 && newState == 1) || 58 | (enc_prev_state == 1 && newState == 3) || 59 | (enc_prev_state == 3 && newState == 2) || 60 | (enc_prev_state == 2 && newState == 0)){ 61 | result++; 62 | } 63 | enc_prev_state = newState; // Record state for next pulse interpretation 64 | enc_speed++; 65 | active_delay(1); 66 | } 67 | return(result/2); 68 | } 69 | 70 | void freqtoa(unsigned long f, char *s){ 71 | char p[16]; 72 | 73 | memset(p, 0, sizeof(p)); 74 | ultoa(f, p, DEC); 75 | s[0] = 0; 76 | // strcpy(s, "FREQ: "); 77 | 78 | //one mhz digit if less than 10 M, two digits if more 79 | 80 | if (f >= 100000000l){ 81 | strncat(s, p, 3); 82 | strcat(s, "."); 83 | strncat(s, &p[3], 3); 84 | strcat(s, "."); 85 | strncat(s, &p[6], 3); 86 | } 87 | else if (f >= 10000000l){ 88 | strcat(s, " "); 89 | strncat(s, p, 2); 90 | strcat(s, "."); 91 | strncat(s, &p[2], 3); 92 | strcat(s, "."); 93 | strncat(s, &p[5], 3); 94 | } 95 | else { 96 | strcat(s, " "); 97 | strncat(s, p, 1); 98 | strcat(s, "."); 99 | strncat(s, &p[1], 3); 100 | strcat(s, "."); 101 | strncat(s, &p[4], 3); 102 | } 103 | } 104 | 105 | void updateMeter(){ 106 | int percentage = 0; 107 | int vswr_reading; 108 | 109 | //draw the meter 110 | GLCD.FillRect(0, 15, 128, 8, WHITE); 111 | 112 | if (mode == MODE_ANTENNA_ANALYZER) 113 | strcat(c, " ANT"); 114 | else if (mode == MODE_MEASUREMENT_RX) 115 | strcat(c, " MRX"); 116 | else if (mode == MODE_NETWORK_ANALYZER) 117 | strcat(c, " SNA"); 118 | 119 | if (mode == MODE_ANTENNA_ANALYZER){ 120 | return_loss = openReading(frequency) - analogRead(DBM_READING)/5; 121 | //Serial.println(return_loss); 122 | if (return_loss > 30) 123 | return_loss = 30; 124 | if (return_loss < 0) 125 | return_loss = 0; 126 | 127 | vswr_reading = pgm_read_word_near(vswr + return_loss); 128 | sprintf (c, " %d.%01d", vswr_reading/10, vswr_reading%10); 129 | percentage = vswr_reading - 10; 130 | }else if (mode == MODE_MEASUREMENT_RX){ 131 | sprintf(c, "%ddbm", analogRead(DBM_READING)/5 + dbmOffset); 132 | percentage = 110 + analogRead(DBM_READING)/5 + dbmOffset; 133 | } 134 | else if (mode == MODE_NETWORK_ANALYZER) { 135 | sprintf(c, "%ddbm", analogRead(DBM_READING)/5 + dbmOffset); 136 | percentage = 110 + analogRead(DBM_READING)/5 + dbmOffset; 137 | } 138 | 139 | GLCD.DrawString(c, 0, 15); 140 | //leave the offset to 37 pixels 141 | GLCD.DrawRoundRect(45, 15, 82, 6, 2); 142 | GLCD.FillRect(47, 17, (percentage * 8)/10, 2, BLACK); 143 | } 144 | 145 | // this builds up the top line of the display with frequency and mode 146 | void updateHeading() { 147 | int vswr_reading; 148 | // tks Jack Purdum W8TEE 149 | // replaced fsprint commmands by str commands for code size reduction 150 | 151 | memset(c, 0, sizeof(c)); 152 | memset(b, 0, sizeof(b)); 153 | 154 | ultoa(frequency, b, DEC); 155 | 156 | if (mode == MODE_ANTENNA_ANALYZER) 157 | strcpy(c, "SWR "); 158 | else if (mode == MODE_MEASUREMENT_RX) 159 | strcpy(c, "PWR "); 160 | else if (mode == MODE_NETWORK_ANALYZER) 161 | strcpy(c, "SNA "); 162 | 163 | //one mhz digit if less than 10 M, two digits if more 164 | 165 | if (frequency >= 100000000l){ 166 | strncat(c, b, 3); 167 | strcat(c, "."); 168 | strncat(c, &b[3], 3); 169 | strcat(c, "."); 170 | strncat(c, &b[6], 3); 171 | } 172 | else if (frequency >= 10000000l){ 173 | strncat(c, b, 2); 174 | strcat(c, "."); 175 | strncat(c, &b[2], 3); 176 | strcat(c, "."); 177 | strncat(c, &b[5], 3); 178 | } 179 | else { 180 | strncat(c, b, 1); 181 | strcat(c, "."); 182 | strncat(c, &b[1], 3); 183 | strcat(c, "."); 184 | strncat(c, &b[4], 3); 185 | } 186 | 187 | GLCD.DrawString(c, 0, 0); 188 | 189 | itoa(spanFreq/10000, c, 10); 190 | strcat(c, "K/d"); 191 | GLCD.DrawString(c, 128-(strlen(c)*6), 0); 192 | } 193 | 194 | 195 | void drawCalibrationMenu(int selection){ 196 | 197 | GLCD.ClearScreen(); 198 | GLCD.FillRect(0, 0, 128, 64, WHITE); 199 | GLCD.DrawString("Calibration Mode", 0,0); 200 | GLCD.DrawString("Return Loss", 20, 20); 201 | GLCD.DrawString("Freq Calibrate", 20, 40); 202 | 203 | if (selection == 0) 204 | GLCD.DrawRect(15,15,100,20); 205 | if (selection == 1) 206 | GLCD.DrawRect(15,35,100,20); 207 | } 208 | 209 | void calibration_mode(){ 210 | int i, select_freq_cal = 0; 211 | 212 | drawCalibrationMenu(select_freq_cal); 213 | 214 | //wait for the button to be lifted 215 | while(btnDown()) 216 | delay(100); 217 | delay(100); 218 | 219 | while(!btnDown()){ 220 | i = enc_read(); 221 | 222 | if(i > 0 && select_freq_cal == 0){ 223 | select_freq_cal = 1; 224 | drawCalibrationMenu(select_freq_cal); 225 | } 226 | else if (i < 0 && select_freq_cal == 1){ 227 | select_freq_cal = 0; 228 | drawCalibrationMenu(select_freq_cal); 229 | } 230 | delay(50); 231 | } 232 | 233 | while(btnDown()) 234 | delay(100); 235 | delay(100); 236 | 237 | if (!select_freq_cal) 238 | calibrateMeter(); 239 | else 240 | calibrateClock(); 241 | 242 | updateScreen(); 243 | } 244 | 245 | void uiFreq(int action){ 246 | 247 | GLCD.FillRect(0, 25, 128, 11, WHITE); 248 | freqtoa(centerFreq, b); 249 | GLCD.DrawString(b, 39, 27); 250 | if (uiFocus == MENU_CHANGE_MHZ) 251 | GLCD.DrawRect(38,25,18,11); 252 | else if (uiFocus == MENU_CHANGE_KHZ) 253 | GLCD.DrawRect(62,25,18,11); 254 | else if (uiFocus == MENU_CHANGE_HZ) 255 | GLCD.DrawRect(86,25,18,11); 256 | 257 | Serial.print("uiFreq action:"); 258 | Serial.println(action); 259 | if (!action) 260 | return; 261 | 262 | if (action == ACTION_SELECT) { 263 | //invert the selection 264 | //GLCD.InvertRect(55, 49, 24, 8); 265 | 266 | if (uiFocus == MENU_CHANGE_MHZ) 267 | GLCD.InvertRect(38,25,18,11); 268 | else if (uiFocus == MENU_CHANGE_KHZ) 269 | GLCD.InvertRect(62,25,18,11); 270 | else if (uiFocus == MENU_CHANGE_HZ) 271 | GLCD.InvertRect(86,25,18,11); 272 | 273 | //wait for the button to be released 274 | while(btnDown()) 275 | delay(100); 276 | //wait for a bit to debounce it 277 | delay(300); 278 | 279 | while(!btnDown()){ 280 | int r = analogRead(DBM_READING); 281 | if (r != prev){ 282 | takeReading(centerFreq); 283 | updateMeter(); 284 | prev = r; 285 | } 286 | int i = enc_read(); 287 | if (i < 0 && centerFreq > 1000000l){ 288 | if (uiFocus == MENU_CHANGE_MHZ) 289 | centerFreq += 1000000l * i; 290 | else if (uiFocus == MENU_CHANGE_KHZ) 291 | centerFreq += 1000l * i; 292 | else if (uiFocus == MENU_CHANGE_HZ) 293 | centerFreq += i; 294 | if (centerFreq < 4000000000l && centerFreq > 150000000l) 295 | centerFreq = 150000000l; 296 | delay(200); 297 | } 298 | else if (i > 0 && centerFreq < 499000000l){ 299 | if (uiFocus == MENU_CHANGE_MHZ) 300 | centerFreq += 1000000l * i; 301 | else if (uiFocus == MENU_CHANGE_KHZ) 302 | centerFreq += 1000l * i; 303 | else if (uiFocus == MENU_CHANGE_HZ) 304 | centerFreq += i; 305 | delay(200); 306 | } 307 | else 308 | continue; 309 | 310 | GLCD.FillRect(0, 25, 128, 11, WHITE); 311 | freqtoa(centerFreq, b); 312 | GLCD.DrawString(b, 39, 27); 313 | 314 | 315 | if (uiFocus == MENU_CHANGE_MHZ) 316 | GLCD.InvertRect(38,25,18,11); 317 | else if (uiFocus == MENU_CHANGE_KHZ) 318 | GLCD.InvertRect(62,25,18,11); 319 | else if (uiFocus == MENU_CHANGE_HZ) 320 | GLCD.InvertRect(86,25,18,11); 321 | } 322 | delay(200); //wait for the button to debounce 323 | 324 | GLCD.FillRect(0, 25, 128, 11, WHITE); 325 | freqtoa(centerFreq, b); 326 | GLCD.DrawString(b, 39, 27); 327 | if (uiFocus == MENU_CHANGE_MHZ) 328 | GLCD.DrawRect(38,25,18,11); 329 | else if (uiFocus == MENU_CHANGE_KHZ) 330 | GLCD.DrawRect(62,25,18,11); 331 | else if (uiFocus == MENU_CHANGE_HZ) 332 | GLCD.DrawRect(86,25,18,11); 333 | 334 | } 335 | } 336 | 337 | void uiSWR(int action){ 338 | GLCD.FillRect(7,38,20,10, WHITE); 339 | GLCD.DrawString("SWR", 9, 40); 340 | 341 | if (action == ACTION_SELECT){ 342 | mode = MODE_ANTENNA_ANALYZER; 343 | uiPWR(0); 344 | uiSNA(0); 345 | updateScreen(); 346 | EEPROM.put(LAST_MODE, mode); 347 | } 348 | 349 | if (uiFocus == MENU_MODE_SWR) 350 | GLCD.DrawRect(7,38,20,10); 351 | 352 | if (mode == MODE_ANTENNA_ANALYZER) 353 | GLCD.InvertRect(8,39,18,8); 354 | 355 | takeReading(centerFreq); 356 | updateMeter(); 357 | } 358 | 359 | void uiPWR(int action){ 360 | GLCD.FillRect(31,38,20,10, WHITE); 361 | GLCD.DrawString("PWR", 33, 40); 362 | 363 | if (action == ACTION_SELECT){ 364 | mode = MODE_MEASUREMENT_RX; 365 | uiSWR(0); 366 | uiSNA(0); 367 | updateScreen(); 368 | EEPROM.put(LAST_MODE, mode); 369 | } 370 | if (uiFocus == MENU_MODE_PWR) 371 | GLCD.DrawRect(31,38,20,10); 372 | if (mode == MODE_MEASUREMENT_RX) 373 | GLCD.InvertRect(32,39,18,8); 374 | takeReading(centerFreq); 375 | updateMeter(); 376 | } 377 | 378 | 379 | void uiSNA(int action){ 380 | GLCD.FillRect(55,38,20,10, WHITE); 381 | GLCD.DrawString("SNA", 57, 40); 382 | 383 | if (action == ACTION_SELECT){ 384 | mode = MODE_NETWORK_ANALYZER; 385 | uiSWR(0); 386 | uiPWR(0); 387 | updateScreen(); 388 | EEPROM.put(LAST_MODE, mode); 389 | } 390 | if (uiFocus == MENU_MODE_SNA) 391 | GLCD.DrawRect(55,38,20,10); 392 | if (mode == MODE_NETWORK_ANALYZER) 393 | GLCD.InvertRect(56,39,18,8); 394 | takeReading(centerFreq); 395 | updateMeter(); 396 | } 397 | 398 | void uiSpan(int action){ 399 | 400 | GLCD.FillRect(55, 49, 24, 12, WHITE); 401 | if (spanFreq >= 1000000l) 402 | sprintf(b, "SPAN +/-%3ldM", spanFreq/1000000l); 403 | else 404 | sprintf(b, "SPAN +/-%3ldK", spanFreq/1000l); 405 | 406 | GLCD.DrawString(b, 6,52); 407 | if (uiFocus == MENU_SPAN) 408 | GLCD.DrawRect(55, 50, 24, 10); 409 | 410 | if (action == ACTION_SELECT) { 411 | //invert the selection 412 | GLCD.InvertRect(55, 51, 24, 8); 413 | 414 | //wait for the button to be released 415 | while(btnDown()) 416 | delay(100); 417 | //wait for a bit to debounce it 418 | delay(300); 419 | 420 | while(!btnDown()){ 421 | int i = enc_read(); 422 | if (selectedSpan > 0 && i < -1){ 423 | selectedSpan--; 424 | spanFreq = spans[selectedSpan]; 425 | EEPROM.put(LAST_SPAN, selectedSpan); 426 | delay(200); 427 | } 428 | else if (selectedSpan < MAX_SPANS && i > 0){ 429 | selectedSpan++; 430 | spanFreq = spans[selectedSpan]; 431 | EEPROM.put(LAST_SPAN, selectedSpan); 432 | delay(200); 433 | } 434 | else 435 | continue; 436 | 437 | GLCD.FillRect(55, 49, 24, 10, WHITE); 438 | if (spanFreq >= 1000000l) 439 | sprintf(b, "SPAN +/-%3ldM", spanFreq/1000000l); 440 | else 441 | sprintf(b, "SPAN +/-%3ldK", spanFreq/1000l); 442 | GLCD.DrawString(b, 6,52); 443 | GLCD.InvertRect(55, 51, 24, 8); 444 | } 445 | delay(200); 446 | } 447 | } 448 | 449 | void uiPlot(int action){ 450 | GLCD.FillRect(90, 42, 37,20, WHITE); 451 | GLCD.DrawRect(90, 42, 37,20); 452 | GLCD.DrawString("PLOT", 98, 49); 453 | 454 | if (uiFocus == MENU_PLOT) 455 | GLCD.DrawRect(92, 44, 33, 16); 456 | 457 | if (action == ACTION_SELECT){ 458 | if (mode == MODE_ANTENNA_ANALYZER) 459 | setupVSWRGrid(); 460 | else 461 | plotPower(); 462 | updateScreen(); 463 | } 464 | } 465 | 466 | 467 | void uiMessage(int id, int action){ 468 | 469 | switch(id){ 470 | case MENU_CHANGE_MHZ: 471 | case MENU_CHANGE_KHZ: 472 | case MENU_CHANGE_HZ: 473 | uiFreq(action); 474 | break; 475 | case MENU_MODE_SWR: 476 | uiSWR(action); 477 | break; 478 | case MENU_MODE_PWR: 479 | uiPWR(action); 480 | break; 481 | case MENU_MODE_SNA: 482 | uiSNA(action); 483 | break; 484 | case MENU_SPAN: 485 | uiSpan(action); 486 | break; 487 | case MENU_PLOT: 488 | uiPlot(action); 489 | break; 490 | default: 491 | return; 492 | } 493 | } 494 | 495 | void updateScreen(){ 496 | 497 | // draw the title bar 498 | strcpy(b, "#Antuino - "); 499 | 500 | GLCD.ClearScreen(); 501 | switch (mode){ 502 | case MODE_ANTENNA_ANALYZER: 503 | strcat(b, "SWR"); 504 | break; 505 | case MODE_MEASUREMENT_RX: 506 | strcat(b, "PWR"); 507 | break; 508 | case MODE_NETWORK_ANALYZER: 509 | strcat(b, "SNA"); 510 | break; 511 | } 512 | GLCD.DrawString(b, 1, 1); 513 | GLCD.InvertRect(0,0, 128,9); 514 | 515 | //update all the elements in the display 516 | updateMeter(); 517 | uiFreq(0); 518 | uiSWR(0); 519 | uiPWR(0); 520 | uiSNA(0); 521 | uiSpan(0); 522 | uiPlot(0); 523 | } 524 | 525 | void doMenu(){ 526 | unsigned long last_freq; 527 | int i = enc_read(); 528 | 529 | //btnState = btnDown(); 530 | if (btnDown()){ 531 | 532 | //on every button, save the freq. 533 | EEPROM.get(LAST_FREQ, last_freq); 534 | if (last_freq != centerFreq){ 535 | EEPROM.put(LAST_FREQ, centerFreq); 536 | } 537 | 538 | Serial.print("btn before:");Serial.println(uiSelected); 539 | if (uiSelected == -1) 540 | uiMessage(uiFocus, ACTION_SELECT); 541 | if (uiSelected != -1){ 542 | uiMessage(uiFocus, ACTION_DESELECT); 543 | Serial.print("btn after:");Serial.println(uiSelected); 544 | 545 | } 546 | } 547 | 548 | if (i == 0) 549 | return; 550 | 551 | if (i > 0 && knob < 80){ 552 | knob += i; 553 | } 554 | if (i < 0 && knob >= 0){ 555 | knob += i; //caught ya 556 | } 557 | 558 | if (uiFocus != knob/10){ 559 | int prev = uiFocus; 560 | uiFocus = knob/10; 561 | uiMessage(prev, 0); 562 | uiMessage(uiFocus, 0); 563 | } 564 | } 565 | -------------------------------------------------------------------------------- /ks0108_Arduino.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ks0108_Arduino.h - User specific configuration for Arduino GLCD library 3 | * 4 | * Use this file to set io pins 5 | * This version is for a standard ks0108 display 6 | * connected using the default Arduino wiring 7 | * 8 | */ 9 | 10 | #ifndef GLCD_PIN_CONFIG_H 11 | #define GLCD_PIN_CONFIG_H 12 | 13 | /* 14 | * define name for pin configuration 15 | */ 16 | #define glcd_PinConfigName "ks0108-Arduino" 17 | 18 | /*********************************************************/ 19 | /* Configuration for assigning LCD bits to Arduino Pins */ 20 | /*********************************************************/ 21 | /* Data pin definitions 22 | */ 23 | #define glcdData0Pin 5 24 | #define glcdData1Pin 6 25 | #define glcdData2Pin 7 26 | #define glcdData3Pin 8 27 | #define glcdData4Pin 9 28 | #define glcdData5Pin 10 29 | #define glcdData6Pin 11 30 | #define glcdData7Pin 12 31 | 32 | /* Arduino pins used for Commands 33 | * default assignment uses the first five analog pins 34 | */ 35 | 36 | #define glcdCSEL1 13 37 | #define glcdCSEL2 14 38 | 39 | #if NBR_CHIP_SELECT_PINS > 2 40 | #define glcdCSEL3 3 // third chip select if needed 41 | #endif 42 | 43 | #if NBR_CHIP_SELECT_PINS > 3 44 | #define glcdCSEL4 2 // fourth chip select if needed 45 | #endif 46 | 47 | #define glcdRW 4 48 | #define glcdDI 3 49 | #define glcdEN 2 50 | // Reset Bit - uncomment the next line if reset is connected to an output pin 51 | //#define glcdRES 19 // Reset Bit 52 | 53 | #endif //GLCD_PIN_CONFIG_H 54 | -------------------------------------------------------------------------------- /plot.ino: -------------------------------------------------------------------------------- 1 | int16_t plot_readings[128]; 2 | #define Y_OFFSET 14 3 | 4 | unsigned long f, f1, f2, stepSize; 5 | 6 | 7 | int freq2screen(unsigned long freq){ 8 | unsigned long f1, f2, hz_per_pixel; 9 | 10 | hz_per_pixel = spanFreq / 100; 11 | f1 = centerFreq - spanFreq/2; 12 | return (int)((freq - f1)/hz_per_pixel) + X_OFFSET; 13 | } 14 | 15 | int pwr2screen(int y){ 16 | return -y/2 + Y_OFFSET; 17 | } 18 | 19 | int vswr2screen(int y){ 20 | if (y >= 100) 21 | y = 99; 22 | return y/2 + Y_OFFSET-1; 23 | } 24 | 25 | void setupPowerGrid(){ 26 | int x, y; 27 | char p[20]; 28 | 29 | GLCD.ClearScreen(); 30 | 31 | while(btnDown()) 32 | delay(100); 33 | 34 | updateHeading(); 35 | 36 | 37 | //sprintf(p, "%ldK, %ldK/div", centerFreq/1000, spanFreq/10000); 38 | //GLCD.DrawString(p, 0, 57); 39 | 40 | //draw the horizontal grid 41 | for (y = -10; y >= -90; y-= 20){ 42 | for (x = X_OFFSET; x <= 100+ X_OFFSET; x += 2) 43 | GLCD.SetDot(x,pwr2screen(y),BLACK); 44 | } 45 | 46 | //draw the vertical grid 47 | f1 = centerFreq - (spanFreq/2); 48 | f2 = centerFreq + (spanFreq/2); 49 | for (f = f1; f <= f2; f += spanFreq/10){ 50 | for (y =0; y <= 50; y += 2) 51 | GLCD.SetDot(freq2screen(f),y+Y_OFFSET-2,BLACK); 52 | } 53 | 54 | for (y = -10; y >= -90; y-= 20){ 55 | itoa(y, p, 10); 56 | GLCD.DrawString(p, 0, pwr2screen(y)-4); 57 | } 58 | 59 | } 60 | 61 | 62 | void setupVSWRGrid(){ 63 | int x, y; 64 | char p[20]; 65 | 66 | GLCD.ClearScreen(); 67 | 68 | while(btnDown()) 69 | delay(100); 70 | 71 | updateHeading(); 72 | 73 | //draw the horizontal grid 74 | for (y = 0; y <= 100; y += 20){ 75 | Serial.print("d"); 76 | Serial.println(vswr2screen(y)); 77 | for (x = X_OFFSET; x <= 100+ X_OFFSET; x += 2) 78 | GLCD.SetDot(x,vswr2screen(y),BLACK); 79 | } 80 | 81 | //draw the vertical grid 82 | f1 = centerFreq - (spanFreq/2); 83 | if (f1 < 0) 84 | f1 = 0; 85 | f2 = f1 + spanFreq; 86 | for (f = f1; f <= f2; f += spanFreq/10){ 87 | Serial.print(f); 88 | Serial.print(","); 89 | Serial.println(freq2screen(f)); 90 | for (y =0; y <= 50; y += 2) 91 | GLCD.SetDot(freq2screen(f),y+Y_OFFSET,BLACK); 92 | } 93 | 94 | for (y = Y_OFFSET; y < 100 + Y_OFFSET; y += 20){ 95 | itoa(y/10, p, 10); 96 | strcat(p, "."); 97 | GLCD.DrawString(p, 0, vswr2screen(y)-8); 98 | } 99 | 100 | f1 = centerFreq - (spanFreq/2); 101 | f2 = f1 + spanFreq; 102 | stepSize = (f2 - f1)/100; 103 | int i = 0, vswr_reading; 104 | 105 | Serial.print("f1 "); Serial.println(f1); 106 | Serial.print("f2 "); Serial.println(f2); 107 | Serial.print("step "); Serial.println(stepSize); 108 | 109 | for (f = f1; f < f2; f += stepSize){ 110 | takeReading(f); 111 | delay(20); 112 | //now take the readings 113 | return_loss = openReading(f) - analogRead(DBM_READING)/5; 114 | if (return_loss > 30) 115 | return_loss = 30; 116 | if (return_loss < 0) 117 | return_loss = 0; 118 | 119 | vswr_reading = pgm_read_word_near(vswr + return_loss); 120 | plot_readings[i] = vswr_reading; 121 | //Serial.print(vswr_reading); Serial.print(' '); Serial.print(f); Serial.print(' ');Serial.print(freq2screen(f)); 122 | //Serial.print("x");Serial.print(vswr_reading);Serial.print(' ');Serial.println(vswr2screen(vswr_reading)); 123 | 124 | if (i == 0) 125 | GLCD.SetDot(freq2screen(f),vswr2screen(vswr_reading),BLACK); 126 | else 127 | GLCD.DrawLine(i + X_OFFSET-1, vswr2screen(plot_readings[i-1]), i + X_OFFSET, vswr2screen(plot_readings[i])); 128 | i++; 129 | } 130 | 131 | int current_pos = 50; 132 | 133 | powerHeading(current_pos); 134 | while (!btnDown()){ 135 | i = enc_read(); 136 | 137 | if ((i < 0 && current_pos + i >= 0) || 138 | (i > 0 && current_pos + i <= 100)){ 139 | current_pos += i; 140 | powerHeading(current_pos); 141 | } 142 | } 143 | 144 | while(btnDown()) 145 | delay(100); 146 | } 147 | 148 | void updateCursor(int pos, char*text){ 149 | GLCD.FillRect(0,0,127,10, WHITE); 150 | GLCD.DrawString(text, 0, 0); 151 | GLCD.DrawLine(pos+ X_OFFSET, 8, pos + X_OFFSET,9); 152 | } 153 | 154 | 155 | void powerHeading(int current_pos){ 156 | 157 | GLCD.FillRect(0,0,127,12, WHITE); 158 | freqtoa(f1 + (stepSize * current_pos), b); 159 | GLCD.DrawString(b, 0, 0); 160 | 161 | if (mode == MODE_ANTENNA_ANALYZER) 162 | sprintf (b, " %d.%01d", plot_readings[current_pos]/10,plot_readings[current_pos] % 10); 163 | else 164 | sprintf(b, "%ddbm", plot_readings[current_pos]); 165 | 166 | GLCD.DrawString(b, 80, 0); 167 | GLCD.DrawLine(current_pos+ X_OFFSET, 8, current_pos + X_OFFSET,11); 168 | } 169 | 170 | void plotPower(){ 171 | int x, y, pwr; 172 | char p[20]; 173 | 174 | GLCD.ClearScreen(); 175 | 176 | while(btnDown()) 177 | delay(100); 178 | 179 | //draw the horizontal grid 180 | for (y = 0; y <= 100; y += 20){ 181 | Serial.print("d"); 182 | Serial.println(pwr2screen(y)); 183 | for (x = X_OFFSET; x <= 100+ X_OFFSET; x += 2) 184 | GLCD.SetDot(x,vswr2screen(y),BLACK); 185 | } 186 | 187 | //draw the vertical grid 188 | f1 = centerFreq - (spanFreq/2); 189 | if (f1 < 0) 190 | f1 = 0; 191 | f2 = f1 + spanFreq; 192 | for (f = f1; f <= f2; f += spanFreq/10){ 193 | for (y =0; y <= 50; y += 2) 194 | GLCD.SetDot(freq2screen(f),y+Y_OFFSET,BLACK); 195 | } 196 | 197 | 198 | for (y = -80; y <= -20; y += 20){ 199 | itoa(y, p, 10); 200 | GLCD.DrawString(p, 0, pwr2screen(y)-4); 201 | } 202 | 203 | f1 = centerFreq - (spanFreq/2); 204 | f2 = f1 + spanFreq; 205 | stepSize = (f2 - f1)/100; 206 | int i = 0, vswr_reading; 207 | 208 | for (f = f1; f < f2; f += stepSize){ 209 | takeReading(f); 210 | delay(50); 211 | //now take the readings 212 | analogRead(DBM_READING); 213 | analogRead(DBM_READING); 214 | analogRead(DBM_READING); 215 | 216 | int r = analogRead(DBM_READING)/5 + dbmOffset; 217 | plot_readings[i] = r; 218 | Serial.print(plot_readings[i]); 219 | Serial.print('-'); 220 | 221 | if (i == 0) 222 | GLCD.SetDot(X_OFFSET, pwr2screen(plot_readings[i]),BLACK); 223 | else 224 | GLCD.DrawLine(i + X_OFFSET-1, pwr2screen(plot_readings[i-1]), i + X_OFFSET, pwr2screen(plot_readings[i])); 225 | i++; 226 | } 227 | 228 | int current_pos = 50; 229 | 230 | powerHeading(current_pos); 231 | while (!btnDown()){ 232 | i = enc_read(); 233 | 234 | if ((i < 0 && current_pos + i >= 0) || 235 | (i > 0 && current_pos + i <= 100)){ 236 | current_pos += i; 237 | powerHeading(current_pos); 238 | 239 | /* GLCD.FillRect(0,0,127,12, WHITE); 240 | 241 | freqtoa(f1 + (stepSize * current_pos), p); 242 | GLCD.DrawString(p, 0, 0); 243 | sprintf(p, "%ddbm", plot_readings[current_pos]); 244 | GLCD.DrawString(p, 80, 0); 245 | GLCD.DrawLine(current_pos+ X_OFFSET, 8, current_pos + X_OFFSET,11); */ 246 | } 247 | } 248 | 249 | while(btnDown()) 250 | delay(100); 251 | } 252 | 253 | -------------------------------------------------------------------------------- /si5351.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define SI_CLK0_CONTROL 16 // Register definitions 4 | #define SI_CLK1_CONTROL 17 5 | #define SI_CLK2_CONTROL 18 6 | #define SI_SYNTH_PLL_A 26 7 | #define SI_SYNTH_PLL_B 34 8 | #define SI_SYNTH_MS_0 42 9 | #define SI_SYNTH_MS_1 50 10 | #define SI_SYNTH_MS_2 58 11 | #define SI_PLL_RESET 177 12 | 13 | #define SI_R_DIV_1 0b00000000 // R-division ratio definitions 14 | #define SI_R_DIV_2 0b00010000 15 | #define SI_R_DIV_4 0b00100000 16 | #define SI_R_DIV_8 0b00110000 17 | #define SI_R_DIV_16 0b01000000 18 | #define SI_R_DIV_32 0b01010000 19 | #define SI_R_DIV_64 0b01100000 20 | #define SI_R_DIV_128 0b01110000 21 | 22 | #define SI_CLK_SRC_PLL_A 0b00000000 23 | #define SI_CLK_SRC_PLL_B 0b00100000 24 | 25 | void i2cSendRegister (byte regist, byte value){ // Writes "byte" into "regist" of Si5351a via I2C 26 | Wire.beginTransmission(96); // Starts transmission as master to slave 96, which is the 27 | // I2C address of the Si5351a (see Si5351a datasheet) 28 | Wire.write(regist); // Writes a byte containing the number of the register 29 | Wire.write(value); // Writes a byte containing the value to be written in the register 30 | Wire.endTransmission(); // Sends the data and ends the transmission 31 | } 32 | 33 | void si5351aOutputOff(uint8_t clk) 34 | { 35 | //i2c_init(); 36 | 37 | i2cSendRegister(clk, 0x80); // Refer to SiLabs AN619 to see bit values - 0x80 turns off the output stage 38 | 39 | //i2c_exit(); 40 | } 41 | 42 | 43 | void setupPLL(uint8_t pll, uint8_t mult, uint32_t num, uint32_t denom) 44 | { 45 | uint32_t P1; // PLL config register P1 46 | uint32_t P2; // PLL config register P2 47 | uint32_t P3; // PLL config register P3 48 | 49 | P1 = (uint32_t)(128 * ((float)num / (float)denom)); 50 | P1 = (uint32_t)(128 * (uint32_t)(mult) + P1 - 512); 51 | P2 = (uint32_t)(128 * ((float)num / (float)denom)); 52 | P2 = (uint32_t)(128 * num - denom * P2); 53 | P3 = denom; 54 | 55 | i2cSendRegister(pll + 0, (P3 & 0x0000FF00) >> 8); 56 | i2cSendRegister(pll + 1, (P3 & 0x000000FF)); 57 | i2cSendRegister(pll + 2, (P1 & 0x00030000) >> 16); 58 | i2cSendRegister(pll + 3, (P1 & 0x0000FF00) >> 8); 59 | i2cSendRegister(pll + 4, (P1 & 0x000000FF)); 60 | i2cSendRegister(pll + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16)); 61 | i2cSendRegister(pll + 6, (P2 & 0x0000FF00) >> 8); 62 | i2cSendRegister(pll + 7, (P2 & 0x000000FF)); 63 | } 64 | 65 | // 66 | // Set up MultiSynth with integer divider and R divider 67 | // R divider is the bit value which is OR'ed onto the appropriate register, it is a #define in si5351a.h 68 | // 69 | void setupMultisynth(uint8_t synth, uint32_t divider, uint8_t rDiv) 70 | { 71 | uint32_t P1; // Synth config register P1 72 | uint32_t P2; // Synth config register P2 73 | uint32_t P3; // Synth config register P3 74 | 75 | P1 = 128 * divider - 512; 76 | P2 = 0; // P2 = 0, P3 = 1 forces an integer value for the divider 77 | P3 = 1; 78 | 79 | i2cSendRegister(synth + 0, (P3 & 0x0000FF00) >> 8); 80 | i2cSendRegister(synth + 1, (P3 & 0x000000FF)); 81 | i2cSendRegister(synth + 2, ((P1 & 0x00030000) >> 16) | rDiv); 82 | i2cSendRegister(synth + 3, (P1 & 0x0000FF00) >> 8); 83 | i2cSendRegister(synth + 4, (P1 & 0x000000FF)); 84 | i2cSendRegister(synth + 5, ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16)); 85 | i2cSendRegister(synth + 6, (P2 & 0x0000FF00) >> 8); 86 | i2cSendRegister(synth + 7, (P2 & 0x000000FF)); 87 | } 88 | 89 | // This example sets up PLL A 90 | // and MultiSynth 0 91 | // and produces the output on CLK0 92 | // 93 | void si5351aSetFrequency(uint32_t frequency) 94 | { 95 | uint32_t pllFreq; 96 | uint32_t xtalFreq = xtal_freq_calibrated; 97 | uint32_t l; 98 | float f; 99 | uint8_t mult; 100 | uint32_t num; 101 | uint32_t denom; 102 | uint32_t divider; 103 | 104 | divider = 900000000 / frequency;// Calculate the division ratio. 900,000,000 is the maximum internal 105 | // PLL frequency: 900MHz 106 | if (divider % 2) divider--; // Ensure an even integer division ratio 107 | 108 | pllFreq = divider * frequency; // Calculate the pllFrequency: the divider * desired output frequency 109 | 110 | mult = pllFreq / xtalFreq; // Determine the multiplier to get to the required pllFrequency 111 | l = pllFreq % xtalFreq; // It has three parts: 112 | f = l; // mult is an integer that must be in the range 15..90 113 | f *= 1048575; // num and denom are the fractional parts, the numerator and denominator 114 | f /= xtalFreq; // each is 20 bits (range 0..1048575) 115 | num = f; // the actual multiplier is mult + num / denom 116 | denom = 1048575; // For simplicity we set the denominator to the maximum 1048575 117 | 118 | // Set up PLL A with the calculated multiplication ratio 119 | setupPLL(SI_SYNTH_PLL_A, mult, num, denom); 120 | // Set up MultiSynth divider 0, with the calculated divider. 121 | // The final R division stage can divide by a power of two, from 1..128. 122 | // reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file) 123 | // If you want to output frequencies below 1MHz, you have to use the 124 | // final R division stage 125 | setupMultisynth(SI_SYNTH_MS_0, divider, SI_R_DIV_1); 126 | // Reset the PLL. This causes a glitch in the output. For small changes to 127 | // the parameters, you don't need to reset the PLL, and there is no glitch 128 | i2cSendRegister(SI_PLL_RESET, 0xA0); 129 | // Finally switch on the CLK0 output (0x4F) 130 | // and set the MultiSynth0 input to be PLL A 131 | i2cSendRegister(SI_CLK1_CONTROL, 0x4F | SI_CLK_SRC_PLL_A); 132 | } 133 | 134 | void si5351aSetFrequency_clk0(uint32_t frequency) 135 | { 136 | uint32_t pllFreq; 137 | uint32_t xtalFreq = xtal_freq_calibrated; 138 | uint32_t l; 139 | float f; 140 | uint8_t mult; 141 | uint32_t num; 142 | uint32_t denom; 143 | uint32_t divider; 144 | 145 | divider = 900000000 / frequency;// Calculate the division ratio. 900,000,000 is the maximum internal 146 | // PLL frequency: 900MHz 147 | if (divider % 2) divider--; // Ensure an even integer division ratio 148 | 149 | pllFreq = divider * frequency; // Calculate the pllFrequency: the divider * desired output frequency 150 | //sprintf(buff,"pllFreq: %ld", (long)pllFreq); 151 | //Serial.println(buff); 152 | 153 | mult = (pllFreq / xtalFreq); // Determine the multiplier to get to the required pllFrequency 154 | l = pllFreq % xtalFreq; // It has three parts: 155 | f = l; // mult is an integer that must be in the range 15..90 156 | f *= 1048575; // num and denom are the fractional parts, the numerator and denominator 157 | f /= xtalFreq; // each is 20 bits (range 0..1048575) 158 | num = f; // the actual multiplier is mult + num / denom 159 | denom = 1048575; // For simplicity we set the denominator to the maximum 1048575 160 | 161 | // Set up PLL B with the calculated multiplication ratio 162 | setupPLL(SI_SYNTH_PLL_A, mult, num, denom); 163 | // Set up MultiSynth divider 0, with the calculated divider. 164 | // The final R division stage can divide by a power of two, from 1..128. 165 | // reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file) 166 | // If you want to output frequencies below 1MHz, you have to use the 167 | // final R division stage 168 | setupMultisynth(SI_SYNTH_MS_0, divider, SI_R_DIV_1); 169 | // Reset the PLL. This causes a glitch in the output. For small changes to 170 | // the parameters, you don't need to reset the PLL, and there is no glitch 171 | i2cSendRegister(SI_PLL_RESET, 0xA0); 172 | // Finally switch on the CLK2 output (0x4F) 173 | // and set the MultiSynth0 input to be PLL A 174 | i2cSendRegister(SI_CLK0_CONTROL, 0x4F | SI_CLK_SRC_PLL_A); 175 | } 176 | 177 | void si5351aSetFrequency_clk1(uint32_t frequency) 178 | { 179 | uint32_t pllFreq; 180 | uint32_t xtalFreq = xtal_freq_calibrated; 181 | uint32_t l; 182 | float f; 183 | uint8_t mult; 184 | uint32_t num; 185 | uint32_t denom; 186 | uint32_t divider; 187 | 188 | divider = 900000000 / frequency;// Calculate the division ratio. 900,000,000 is the maximum internal 189 | // PLL frequency: 900MHz 190 | if (divider % 2) divider--; // Ensure an even integer division ratio 191 | 192 | pllFreq = divider * frequency; // Calculate the pllFrequency: the divider * desired output frequency 193 | 194 | mult = (pllFreq / xtalFreq); // Determine the multiplier to get to the required pllFrequency 195 | l = pllFreq % xtalFreq; // It has three parts: 196 | f = l; // mult is an integer that must be in the range 15..90 197 | f *= 1048575; // num and denom are the fractional parts, the numerator and denominator 198 | f /= xtalFreq; // each is 20 bits (range 0..1048575) 199 | num = f; // the actual multiplier is mult + num / denom 200 | denom = 1048575; // For simplicity we set the denominator to the maximum 1048575 201 | 202 | // Set up PLL A with the calculated multiplication ratio 203 | setupPLL(SI_SYNTH_PLL_A, mult, num, denom); 204 | // Set up MultiSynth divider 0, with the calculated divider. 205 | // The final R division stage can divide by a power of two, from 1..128. 206 | // reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file) 207 | // If you want to output frequencies below 1MHz, you have to use the 208 | // final R division stage 209 | setupMultisynth(SI_SYNTH_MS_1, divider, SI_R_DIV_1); 210 | // Reset the PLL. This causes a glitch in the output. For small changes to 211 | // the parameters, you don't need to reset the PLL, and there is no glitch 212 | i2cSendRegister(SI_PLL_RESET, 0xA0); 213 | // Finally switch on the CLK0 output (0x4F) 214 | // and set the MultiSynth0 input to be PLL A 215 | i2cSendRegister(SI_CLK1_CONTROL, 0x4F | SI_CLK_SRC_PLL_A); 216 | } 217 | 218 | 219 | void si5351aSetFrequency_clk2(uint32_t frequency) 220 | { 221 | uint32_t pllFreq; 222 | uint32_t xtalFreq = xtal_freq_calibrated; 223 | uint32_t l; 224 | float f; 225 | uint8_t mult; 226 | uint32_t num; 227 | uint32_t denom; 228 | uint32_t divider; 229 | 230 | divider = 900000000 / frequency;// Calculate the division ratio. 900,000,000 is the maximum internal 231 | // PLL frequency: 900MHz 232 | if (divider % 2) divider--; // Ensure an even integer division ratio 233 | 234 | pllFreq = divider * frequency; // Calculate the pllFrequency: the divider * desired output frequency 235 | //sprintf(buff,"pllFreq: %ld", (long)pllFreq); 236 | //Serial.println(buff); 237 | 238 | mult = (pllFreq / xtalFreq); // Determine the multiplier to get to the required pllFrequency 239 | l = pllFreq % xtalFreq; // It has three parts: 240 | f = l; // mult is an integer that must be in the range 15..90 241 | f *= 1048575; // num and denom are the fractional parts, the numerator and denominator 242 | f /= xtalFreq; // each is 20 bits (range 0..1048575) 243 | num = f; // the actual multiplier is mult + num / denom 244 | denom = 1048575; // For simplicity we set the denominator to the maximum 1048575 245 | 246 | // Set up PLL B with the calculated multiplication ratio 247 | setupPLL(SI_SYNTH_PLL_B, mult, num, denom); 248 | // Set up MultiSynth divider 0, with the calculated divider. 249 | // The final R division stage can divide by a power of two, from 1..128. 250 | // reprented by constants SI_R_DIV1 to SI_R_DIV128 (see si5351a.h header file) 251 | // If you want to output frequencies below 1MHz, you have to use the 252 | // final R division stage 253 | setupMultisynth(SI_SYNTH_MS_2, divider, SI_R_DIV_1); 254 | // Reset the PLL. This causes a glitch in the output. For small changes to 255 | // the parameters, you don't need to reset the PLL, and there is no glitch 256 | i2cSendRegister(SI_PLL_RESET, 0xA0); 257 | // Finally switch on the CLK2 output (0x4F) 258 | // and set the MultiSynth0 input to be PLL A 259 | i2cSendRegister(SI_CLK2_CONTROL, 0x4F | SI_CLK_SRC_PLL_B); 260 | } 261 | 262 | --------------------------------------------------------------------------------