(http://xv4y NULL.radioclub NULL.asia/wp-content/uploads/2013/03/100_3446 NULL.jpg)J’ai eu le temps de mettre la main à une première version d’un programme simple de VFO pour mon kit à base de DDS AD9850 ou AD9851 (http://xv4y NULL.radioclub NULL.asia/boutique/?slug=product_info NULL.php&products_id=33).
Cette première mouture reste assez simple avec juste un système VFO A et VFO B mais pas de mémoires. Les fonctionnalités des boutons suivent la description ci-dessous.
Pour une pression brève sur le bouton :
- UP : Augmente la valeur du chiffre sélectionné (pour le VFO sélectionné)
- DOWN : Diminue la valeur du chiffre sélectionné (pour le VFO sélectionné)
- LEFT : Sélectionne le chiffre de rang supérieur (plus à gauche)
- RIGHT : Sélectionne le chiffre de rang inférieur (plus à droite)
- OK : Valide la fréquence et la transmet au DDS
Pour une pression longue (supérieure à 1 seconde) sur le bouton :
- LEFT : Positionne la fréquence sur la limite basse de la bande suivante
- RIGHT : Egalise les fréquences des deux VFO (VFO A = VFO B)
- OK : Change le VFO sélectionné (VFO A/B)
A noté que la broche P2_2 du MSP430 (celle connectée à la broche 3 du connecteur 4 pins) est maintenant utilisée en entrée. Si son état change (passant à 0V par exemple), le VFO actuellement utilisé est momentanément interverti. Cela permet donc de trafiquer en split avec la fréquence transmise par le DDS qui change du VFO A vers VFO B (ou l’inverse) tant que la PTT est pressée.
/* Simple VFO with DDS for MSP430G2553 * Code for Energia 009 * By Yannick DEVOS - XV4Y - March 2013 http://xv4y.radioclub.asia/ Copyright 2012-2013 Yannick DEVOS under GPL 3.0 license Any commercial use or inclusion in a kit is subject to author approval ==== * Agile Frequency generation using AD9850/9851 DDS * Output to Nokia 5110 compatible LCD * Check if P2_2 has changed state and switch VFO (like when PTT is pressed to operate split) Usage for short press of buttons : - Up / Down increase or decrease the frequency following the choosen digit - Left / Right increase or decrease the digit - OK validate the frequency and send it to the DDS Long press of buttons : - Left Set the current VFO to the next band bottom frequency - Right VFO A = VFO B - OK Switch between VFO A and VFO B ==== Revision history : v1.00 2013-03-18 First release ==== This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You can download a copy of the GNU General Public License at <http://www.gnu.org/licenses/> */ // Here modify to your taste or needs #define PTT_key P2_2 #define ANALOG_BUTTONS A5 //#define AUTO_VALID // Uncomment if you want the DDS frequency to be udapted automatically after each value change #define DEFAULT_FREQ 8 // Value 8 in Frequencies array is 14000000 // Here under don't touch anything unless you know what you do #include <legacymsp430.h> #include <AD9850.h> // Library for AD9850 control by MSP430 #include <LCD_5110.h> // Frequencies (1 Hz precision) you can select const unsigned long int frequencies[] = { 137000, 471000, 501000, 1830000, 3500000, 5200000, 7000000, 10100000, 14000000, 18068000, 21000000, 24890000, 28000000, 50000000, 70000000}; const byte Analog_Noise = 5; // Margins for reading analog buttons boolean vfo=0, saved_PTT; // VFO A or B and PTT input state char multiplier, aff_multiplier, freq_select=DEFAULT_FREQ; unsigned long int frequency_A=frequencies[DEFAULT_FREQ], frequency_B=frequencies[DEFAULT_FREQ], debounce; char chaine_txt[6] = {' ', ' ', ' ', ' ', ' ', 0x00}; //AD9850 myDDS (P1_0, P1_1, P1_2, P1_4); // Call the AD9850 Library, AD9850 pins for CLOCK, LOAD, DATA and RESET AD9850 myDDS (P1_1, P1_2, P1_0, P1_4); // Call the AD9850 Library, AD9851 pins for CLOCK, LOAD, DATA and RESET LCD_5110 myScreen(P2_3, // Chip Select * P1_6, // Serial Clock * P2_5, // Serial Data * P2_4, // Data/Command * NULL, // Reset * P1_7, // Backlight NULL); // Push Button 0 //****************************************************************** // Defining pins mode // Encoding the WSPR sequence void setup() { pinMode(PTT_key, INPUT_PULLUP); myDDS.begin(); pinMode(ANALOG_BUTTONS, INPUT); myScreen.begin(); myScreen.setBacklight(1); myScreen.setFont(1); myScreen.text(0, 0, "sVFO"); myScreen.text(0, 2, "AD9850"); myScreen.setFont(0); myScreen.text(0, 4, "v1.00 - XV4Y"); myScreen.text(0, 5, "Init..."); delay(1000); myDDS.reset(); myDDS.SetFrequency( frequency_A, 0, false ); digitalWrite( PTT_key, LOW ); }; //****************************************************************** // Here starts the actual sequence sending void loop() { myScreen.clear(); myScreen.setBacklight(1); myScreen.setFont(1); if (vfo == 0) { myScreen.text(0, 0, "VFO A"); myDDS.SetFrequency( frequency_A, 0, false ); } else { myScreen.text(0, 0, "VFO B"); myDDS.SetFrequency( frequency_B, 0, false ); }; myScreen.setFont(0); display_freq (frequency_A, 3); display_freq (frequency_B, 5); while (read_buttons()==5 || read_buttons()==4 || read_buttons()==2) delay(10); // Debounce except for UP/DWN while (1) { // Update the frequencies display if (multiplier > 5) { aff_multiplier = multiplier + 2; } else if (multiplier > 2) { aff_multiplier = multiplier + 1; } else { aff_multiplier = multiplier; }; myScreen.text(0, 4, " "); if (vfo == 0) { myScreen.text(9-aff_multiplier, 4, "^"); } else { myScreen.text(9-aff_multiplier, 4, "v"); } display_freq (frequency_A, 3); display_freq (frequency_B, 5); // Read the analog buttons input if(read_buttons()==1) { // Up we increase frequency delay(200); // Debounce if (vfo == 0) { frequency_A = frequency_A + powf(10,(float)multiplier); } else { frequency_B = frequency_B + powf(10,(float)multiplier); }; #if defined AUTO_VALID break; #endif } else if (read_buttons()==3) { // Down we decrease frequency delay(200); // Debounce if (vfo == 0) { frequency_A = frequency_A - powf(10,(float)multiplier); } else { frequency_B = frequency_B - powf(10,(float)multiplier); }; #if defined AUTO_VALID break; #endif } else if (read_buttons()==2) { // Left we increase multiplier debounce = millis(); while (read_buttons()==2) { //Debounce if ((millis()-debounce)>1000) { // Long press we do "Band UP" freq_select++; if (freq_select > 14) freq_select = 0; if (vfo == 1) frequency_B = frequencies[freq_select]; else frequency_A=frequencies[freq_select]; multiplier--; break; }; }; multiplier++; if (multiplier > 8) multiplier = 8; } else if (read_buttons()==4) { // Right we decrease multiplier debounce = millis(); while (read_buttons()==4) { //Debounce if ((millis()-debounce)>1000) { // Long press we do VFO A=B if (vfo == 1) frequency_A = frequency_B; else frequency_B=frequency_A; multiplier++; break; }; }; multiplier--; if (multiplier < 0) multiplier = 0; } else if (read_buttons()==5) { // OK we go out debounce = millis(); while (read_buttons()==5) { //Debounce if ((millis()-debounce)>1000) { // Long press we switch VFO A/B if (vfo == 1) vfo=0; else vfo=1; break; }; }; break; // Short press we just leave the loop so the frequency is transmitted to the AD9850 } // Check if we are transmitting split (momentaneous VFO A->B switch) if (saved_PTT != digitalRead(PTT_key)) { saved_PTT = digitalRead(PTT_key); if (vfo == 1) vfo=0; else vfo=1; break; }; } }; //****************************************************************** // Display the frequency void display_freq (unsigned long freq, char ligne) { myScreen.text(10, ligne, " Hz "); chaine_txt[5] = 0x00; chaine_txt[4] = 0x30 + (((freq)/1)%10); chaine_txt[3] = 0x30 + (((freq)/10)%10); chaine_txt[2] = 0x30 + (((freq)/100)%10); chaine_txt[1] = '.'; chaine_txt[0] = 0x30 + (((freq)/1000)%10); myScreen.text(5, ligne, chaine_txt); chaine_txt[5] = 0x00; chaine_txt[4] = 0x30 + (((freq)/10000)%10); chaine_txt[3] = 0x30 + (((freq)/100000)%10); chaine_txt[2] = '.'; chaine_txt[1] = 0x30 + (((freq)/1000000)%10); chaine_txt[0] = 0x30 + (((freq)/10000000)%10); myScreen.text(0, ligne, chaine_txt); } //****************************************************************** // Display a 2 digits number void display_number (byte number, char column, char ligne) { chaine_txt[2] = 0x00; chaine_txt[1] = 0x30 + (number%10); chaine_txt[0] = 0x30 + ((number/10)%10); myScreen.text(column, ligne, chaine_txt); } //****************************************************************** // Return a button value depending on the analog reading byte read_buttons () { int value = analogRead(ANALOG_BUTTONS); if ( value<(1+Analog_Noise) ) { return 1; } else if ( value<(78+Analog_Noise) ) { return 2; } else if ( value<(146+Analog_Noise) ) { return 3; } else if ( value<(205+Analog_Noise) ) { return 4; } else if ( value<(255+Analog_Noise) ) { return 5; } else { return 0; } }