(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;
}
}