AD9850 Arduino vfo

IDE gerelateerde berichten
Berichten: 6
Geregistreerd: 04 Mei 2016, 18:58

AD9850 Arduino vfo

Berichtdoor pe1ryx » 04 Mei 2016, 19:08

Hallo,

Ik ben zend-amateur en heb een schakeling gemaakt om frequentie op te wekken.
Dit alles wordt Arduino bestuurd.
Nu is het probleem dat de aangegeven Frequentie in het display foutief word weergegeven.
Op dit moment is de frequentie die uit de schakeling komt 9mhz lager dan wat er op het display weergegeven word.
Hoe draai je dit om?
Heb vanalles geprobeerd,van - een + maken etc maar krijg het niet spits.
Tevens zou ik de stappen van 1khz-10khz-1mhz ed ook terug willen kunnen togglen...nu is het alleen Up en loopt dit wil dus ook stap terug kunnen maken.

Wie kan me uit de brand helpen want zelf kom ik er in het geheel niet meer uit.

cpp code
// Include the library code
#include <LiquidCrystal.h>
#include <rotary.h>
#include <EEPROM.h>

//Setup some items
#define W_CLK 8 // Pin 8 - connect to AD9851 module word load clock pin (CLK)
#define FQ_UD 9 // Pin 9 - connect to freq update pin (FQ)
#define DATA 10 // Pin 10 - connect to serial data load pin (DATA)
#define RESET 11 // Pin 11 - connect to reset pin (RST)
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
Rotary r = Rotary(2,3); // sets the pins the rotary encoder uses. Must be interrupt pins.
LiquidCrystal lcd(12, 13, 7, 6, 5, 4); // I used an odd pin combination because I need pin 2 and 3 for the interrupts.
int_fast32_t rx=15000000; // Base (starting) frequency of VFO. This only loads once. To force load again see ForceFreq variable below.
int_fast32_t rx2=1; // variable to hold the updated frequency
int_fast32_t increment = 10; // starting VFO update increment in HZ.
int_fast32_t iffreq = 9000000; // Intermedite Frequency - Amount to subtract (-) from base frequency. ********************************************
int buttonstate = 0;
int buttonstate2 = 0;
int GoIF = 1;
String hertz = "10 Hz";
int hertzPosition = 5;
byte ones,tens,hundreds,thousands,tenthousands,hundredthousands,millions ; //Placeholders
String freq; // string to hold the frequency
int_fast32_t timepassed = millis(); // int to hold the arduino miilis since startup
int memstatus = 1; // value to notify if memory is current or old. 0=old, 1=current.


int ForceFreq = 1; // Change this to 0 after you upload and run a working sketch to activate the EEPROM memory. YOU MUST PUT THIS BACK TO 0 AND UPLOAD THE SKETCH AGAIN AFTER STARTING FREQUENCY IS SET!



void setup() {
pinMode(A0,INPUT); // Connect to a button that goes to GND on push
pinMode(A5,INPUT); // IF sense **********************************************
digitalWrite(A0,HIGH);
digitalWrite(A5,HIGH);
lcd.begin(16, 2);
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
pinMode(FQ_UD, OUTPUT);
pinMode(W_CLK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(RESET, OUTPUT);
pulseHigh(RESET);
pulseHigh(W_CLK);
pulseHigh(FQ_UD); // this pulse enables serial mode on the AD9851 - Datasheet page 12.
lcd.setCursor(hertzPosition,1);
lcd.print(hertz);

// Load the stored frequency
if (ForceFreq == 0) {
freq = String(EEPROM.read(0))+String(EEPROM.read(1))+String(EEPROM.read(2))+String(EEPROM.read(3))+String(EEPROM.read(4))+String(EEPROM.read(5))+String(EEPROM.read(6));
rx = freq.toInt();
}
}

void loop() {
// Update the display and frequency if the new Freq NEQ the old Freq
if (rx != rx2){
showFreq();
sendFrequency(rx);
rx2 = rx;
}

// Rotate through the rate of tuning as you hold down the button
buttonstate = digitalRead(A0);
if(buttonstate == LOW) {
setincrement();
};

// Check for PIN low to drive IF offset Freq
buttonstate = digitalRead(A5);
if (buttonstate != buttonstate2){
if(buttonstate == LOW) {
lcd.setCursor(15,1);
lcd.print(".");
GoIF = 0;
buttonstate2 = buttonstate;
sendFrequency(rx);
}
else{
lcd.setCursor(15,1);
lcd.print(" ");
GoIF = 1;
buttonstate2 = buttonstate;
sendFrequency(rx);
};
};

// Write the frequency to memory if not stored and 2 seconds have passed since the last frequency change.
if(memstatus == 0){
if(timepassed+2000 < millis()){
storeMEM();
}
}

}


// Interrupt routine to catch the rotary encoder
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result) {
if (result == DIR_CW){rx=rx+increment;}
else {rx=rx-increment;};
if (rx >=39000000){rx=rx2;}; // UPPER VFO LIMIT
if (rx <=12000000){rx=rx2;}; // LOWER VFO LIMIT
}
}

// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {
if (GoIF == 1){frequency=frequency-iffreq;}; //If pin = low, subtract the IF frequency.
int32_t freq = frequency * 4294967295/30000000; // note 30 MHz clock on 9851. You can make 'slight' tuning variations here by adjusting the clock frequency.
for (int b=0; b<4; b++, freq>>=8) {
tfr_byte(freq & 0xFF);
}
tfr_byte(0x000); // Final control byte, all 0 for 9851 chip
pulseHigh(FQ_UD); // Done! Should see output
}
// transfers a byte, a bit at a time, LSB first to the 9851 via serial DATA line
void tfr_byte(byte data)
{
for (int i=0; i<8; i++, data>>=1) {
digitalWrite(DATA, data & 0x01);
pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high
}
}

void setincrement(){
if(increment == 10){increment = 100; hertz = "100 Hz"; hertzPosition=4;}
else if (increment == 100){increment = 1000; hertz="1 Khz"; hertzPosition=6;}
else if (increment == 1000){increment = 10000; hertz="10 Khz"; hertzPosition=5;}
else if (increment == 10000){increment = 100000; hertz="100 Khz"; hertzPosition=4;}
else if (increment == 100000){increment = 1000000; hertz="1 Mhz"; hertzPosition=6;}
else{increment = 10; hertz = "10 Hz"; hertzPosition=5;};
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(hertzPosition,1);
lcd.print(hertz);
delay(250); // Adjust this delay to speed up/slow down the button menu scroll speed.
};

void showFreq(){
millions = int(rx/1000000);
hundredthousands = ((rx/100000)%10);
tenthousands = ((rx/10000)%10);
thousands = ((rx/1000)%10);
hundreds = ((rx/100)%10);
tens = ((rx/10)%10);
ones = ((rx/1)%10);
lcd.setCursor(0,0);
lcd.print(" ");
if (millions > 9){lcd.setCursor(1,0);}
else{lcd.setCursor(2,0);}
lcd.print(millions);
lcd.print(".");
lcd.print(hundredthousands);
lcd.print(tenthousands);
lcd.print(thousands);
lcd.print(".");
lcd.print(hundreds);
lcd.print(tens);
lcd.print(ones);
lcd.print(" Mhz ");
timepassed = millis();
memstatus = 0; // Trigger memory write
};

void storeMEM(){
//Write each frequency section to a EPROM slot. Yes, it's cheating but it works!
EEPROM.write(0,millions);
EEPROM.write(1,hundredthousands);
EEPROM.write(2,tenthousands);
EEPROM.write(3,thousands);
EEPROM.write(4,hundreds);
EEPROM.write(5,tens);
EEPROM.write(6,ones);
memstatus = 1; // Let program know memory has been written
};

Advertisement

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: AD9850 Arduino vfo

Berichtdoor nicoverduin » 04 Mei 2016, 21:31

het probleem komt kennelijk meer voor : http://www.pa3ger.nl/zelfbouw/dds-ad985 ... t-arduino/

@edit: Ik heb ff een andere routine voor je geschreven om punten neer te zetten bij de duizentallen en miljoenen etc. De redenering is dat het alleen maar opmaak is. Dus zet ik het getal eerst om in een string en daarna vul ik de punten in op de juiste plek. Dat scheelt gelijk een zooi deel berekeningen en maakt alles wat eenvoudiger. Het werkt voor alle getallen van 0 to 2^32.
cpp code
char result[17];

void setup(){

Serial.begin(115200);

maakGetalMetSeparators(3876543210, result);
Serial.println(result);
}
void loop(){
}
/**
* @name maakGetalMetSeparators
* @param x long getal (max 10 cijfers)
* @param resultaat pointer naar een char veld dat de lengte + decimalen kan bevatten
* Het getal wordt eerst in een char array gezet. Daarna wordt de array afgelopen en een punt
* ingevuld na elke 3 cijfers werkend van achteren
*/
void maakGetalMetSeparators (uint32_t x, char * resultaat) {
sprintf(resultaat, "%lu", x); // maak string array van het getal
uint8_t index = (strlen(resultaat)-1) / 3; // bepaal aantal te plaatsen punten
char *ptrSrc = resultaat + strlen(resultaat)-3; // pointer naar eerste punt
while (index != 0) { // onder de 1000 geen punten
char *ptrDest = ptrSrc + 1; // schuif alles vanaf deze plek 1 naar rechts
memmove(ptrDest, ptrSrc, strlen(ptrSrc)+1); // schuif alles 1 een rechts
*ptrSrc = '.'; // plaats onze punt
index--; // verlaag aantal te plaatsen punten
ptrSrc = ptrSrc - 3; // schuif 3 plekken naar links
}
}
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: AD9850 Arduino vfo

Berichtdoor shooter » 05 Mei 2016, 22:22

er staat ergens rx/1%10 dat klopt toch niet?
dus gebruik de routine van nico maar.
paul deelen
shooter@home.nl

Berichten: 6
Geregistreerd: 04 Mei 2016, 18:58

Re: AD9850 Arduino vfo

Berichtdoor pe1ryx » 06 Mei 2016, 09:10

Whow...

Kun je me vertellen hoe ik dit stukje in de code implementeer?

Abacadabra voor mij

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: AD9850 Arduino vfo

Berichtdoor nicoverduin » 06 Mei 2016, 12:34

De huidige showFreq() functie kan eruit. En die vervangen door deze code:
cpp code
/**
* @name showFreq
* Toont de frequentie in Mhz op het scherm
*/
void showFreq() {
char regel[17]; // buffertje voor het resultaat
lcd.setCursor(0, 0); // maak de regel ff helemaal blanko
lcd.print(" ");
if (rx > 9000000) { // indien we onder de 10Mhz zitten dan een postie
lcd.setCursor(1, 0); // naar rechts
} else {
lcd.setCursor(2, 0);
}
maakGetalMetSeparators(rx, regel);
strcat(regel, " Mhz "); // is dit wel Mhz? Moet het niet Hz zijn?
lcd.print(regel);
timepassed = millis();
memstatus = 0; // Trigger memory write
}

/**
* @name maakGetalMetSeparators
* @param x long getal (max 10 cijfers)
* @param resultaat pointer naar een char veld dat de lengte + decimalen kan bevatten
* Het getal wordt eerst in een char array gezet. Daarna wordt de array afgelopen en een punt
* ingevuld na elke 3 cijfers werkend van achteren
*/
void maakGetalMetSeparators(uint_fast32_t x, char * resultaat) {
sprintf(resultaat, "%lu", x); // maak string array van het getal
uint8_t index = (strlen(resultaat) - 1) / 3;// bepaal aantal te plaatsen punten
char *ptrSrc = resultaat + strlen(resultaat) - 3;// pointer naar eerste punt
while (index != 0) { // onder de 1000 geen punten
char *ptrDest = ptrSrc + 1; // schuif alles vanaf deze plek 1 naar rechts
memmove(ptrDest, ptrSrc, strlen(ptrSrc) + 1);// schuif alles 1 een rechts
*ptrSrc = '.'; // plaats onze punt
index--; // verlaag aantal te plaatsen punten
ptrSrc = ptrSrc - 3; // schuif 3 plekken naar links
}
}


Alleen je EEProm gaat nog fout omdat die ook anders moet worden.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: AD9850 Arduino vfo

Berichtdoor nicoverduin » 06 Mei 2016, 13:03

Ik heb ff je programma aangepast. Deze mag je testen of dit werkt.
cpp code
// Include the library code
#include "Arduino.h"
#include <LiquidCrystal.h>
#include <rotary.h>
#include <EEPROM.h>

//Setup some items
#define W_CLK 8 // Pin 8 - connect to AD9851 module word load clock pin (CLK)
#define FQ_UD 9 // Pin 9 - connect to freq update pin (FQ)
#define DATA_S 10 // Pin 10 - connect to serial data load pin (DATA)
#define RESET 11 // Pin 11 - connect to reset pin (RST)
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
Rotary r = Rotary(2, 3); // sets the pins the rotary encoder uses. Must be interrupt pins.
LiquidCrystal lcd(12, 13, 7, 6, 5, 4); // I used an odd pin combination because I need pin 2 and 3 for the interrupts.
int_fast32_t rx = 15000000; // Base (starting) frequency of VFO. This only loads once. To force load again see ForceFreq variable below.
int_fast32_t rx2 = 1; // variable to hold the updated frequency
int_fast32_t increment = 10; // starting VFO update increment in HZ.
int_fast32_t iffreq = 9000000; // Intermedite Frequency - Amount to subtract (-) from base frequency. ********************************************
int buttonstate = 0;
int buttonstate2 = 0;
int GoIF = 1;
String hertz = "10 Hz";
int hertzPosition = 5;
String freq; // string to hold the frequency
uint_fast32_t timepassed = millis(); // long to hold the arduino millis since startup
int memstatus = 1; // value to notify if memory is current or old. 0=old, 1=current.
int ForceFreq = 1; // Change this to 0 after you upload and run a working sketch to activate the EEPROM memory. YOU MUST PUT THIS BACK TO 0 AND UPLOAD THE SKETCH AGAIN AFTER STARTING FREQUENCY IS SET!

void setup() {
pinMode(A0, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);
lcd.begin(16, 2);

PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();

pinMode(FQ_UD , OUTPUT);
pinMode(W_CLK , OUTPUT);
pinMode(DATA_S , OUTPUT);
pinMode(RESET , OUTPUT);
//
// initialize the AD9851
//
pulseHigh(RESET);
pulseHigh(W_CLK);
pulseHigh(FQ_UD); // this pulse enables serial mode on the AD9851 - Datasheet page 12.
//
// print default frequency
//
lcd.setCursor(hertzPosition, 1);
lcd.print(hertz);
//
// Load the stored frequency
//
if (ForceFreq == 0) {
EEPROM.get(0, rx); // get our long type frequency from EEPROM
}
}

void loop() {
//
// Update the display and frequency if the new Freq NEQ the old Freq
//
if (rx != rx2) {
showFreq();
sendFrequency(rx);
rx2 = rx;
}

// Rotate through the rate of tuning as you hold down the button
buttonstate = digitalRead(A0);
if (buttonstate == LOW) {
setincrement();
};

// Check for PIN low to drive IF offset Freq
buttonstate = digitalRead(A5);
if (buttonstate != buttonstate2) {
if (buttonstate == LOW) {
lcd.setCursor(15, 1);
lcd.print(".");
GoIF = 0;
buttonstate2 = buttonstate;
sendFrequency(rx);
} else {
lcd.setCursor(15, 1);
lcd.print(" ");
GoIF = 1;
buttonstate2 = buttonstate;
sendFrequency(rx);
};
};

// Write the frequency to memory if not stored and 2 seconds have passed since the last frequency change.
if (memstatus == 0) {
if (timepassed + 2000 < millis()) {
storeMEM();
}
}

}

// Interrupt routine to catch the rotary encoder
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result) {
if (result == DIR_CW) {rx=rx+increment;}
else {rx=rx-increment;};
if (rx >=39000000) {rx=rx2;}; // UPPER VFO LIMIT
if (rx <=12000000) {rx=rx2;}; // LOWER VFO LIMIT
}
}

// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {
if (GoIF == 1) {
frequency = frequency - iffreq;
}; //If pin = low, subtract the IF frequency.
int32_t freq = frequency * 4294967295 / 30000000; // note 30 MHz clock on 9851. You can make 'slight' tuning variations here by adjusting the clock frequency.
for (int b = 0; b < 4; b++, freq >>= 8) {
tfr_byte(freq & 0xFF);
}
tfr_byte(0x000); // Final control byte, all 0 for 9851 chip
pulseHigh(FQ_UD); // Done! Should see output
}
// transfers a byte, a bit at a time, LSB first to the 9851 via serial DATA line
void tfr_byte(byte data) {
for (int i = 0; i < 8; i++, data >>= 1) {
digitalWrite(DATA_S, data & 0x01);
pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high
}
}

void setincrement() {
if (increment == 10) {
increment = 100;
hertz = "100 Hz";
hertzPosition = 4;
} else if (increment == 100) {
increment = 1000;
hertz = "1 Khz";
hertzPosition = 6;
} else if (increment == 1000) {
increment = 10000;
hertz = "10 Khz";
hertzPosition = 5;
} else if (increment == 10000) {
increment = 100000;
hertz = "100 Khz";
hertzPosition = 4;
} else if (increment == 100000) {
increment = 1000000;
hertz = "1 Mhz";
hertzPosition = 6;
} else {
increment = 10;
hertz = "10 Hz";
hertzPosition = 5;
};
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(hertzPosition, 1);
lcd.print(hertz);
delay(250); // Adjust this delay to speed up/slow down the button menu scroll speed.
}
;


void storeMEM() {
//Write each frequency section to a EPROM slot. Yes, it's cheating but it works!
EEPROM.put(0, rx);
memstatus = 1; // Let program know memory has been written
}
;
/**
* @name showFreq
* Toont de frequentie in Mhz op het scherm
*/
void showFreq() {
char regel[17]; // buffertje voor het resultaat
lcd.setCursor(0, 0); // maak de regel ff helemaal blanko
lcd.print(" ");
if (rx > 9000000) { // indien we onder de 10Mhz zitten dan een postie
lcd.setCursor(1, 0); // naar rechts
} else {
lcd.setCursor(2, 0);
}
maakGetalMetSeparators(rx, regel);
strcat(regel, " Mhz "); // is dit wel Mhz? Moet het niet Hz zijn?
lcd.print(regel);
timepassed = millis();
memstatus = 0; // Trigger memory write
}

/**
* @name maakGetalMetSeparators
* @param x long getal (max 10 cijfers)
* @param resultaat pointer naar een char veld dat de lengte + decimalen kan bevatten
* Het getal wordt eerst in een char array gezet. Daarna wordt de array afgelopen en een punt
* ingevuld na elke 3 cijfers werkend van achteren
*/
void maakGetalMetSeparators(uint_fast32_t x, char * resultaat) {
sprintf(resultaat, "%lu", x); // maak string array van het getal
uint8_t index = (strlen(resultaat) - 1) / 3;// bepaal aantal te plaatsen punten
char *ptrSrc = resultaat + strlen(resultaat) - 3;// pointer naar eerste punt
while (index != 0) { // onder de 1000 geen punten
char *ptrDest = ptrSrc + 1; // schuif alles vanaf deze plek 1 naar rechts
memmove(ptrDest, ptrSrc, strlen(ptrSrc) + 1);// schuif alles 1 een rechts
*ptrSrc = '.'; // plaats onze punt
index--; // verlaag aantal te plaatsen punten
ptrSrc = ptrSrc - 3; // schuif 3 plekken naar links
}
}
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 6
Geregistreerd: 04 Mei 2016, 18:58

Re: AD9850 Arduino vfo

Berichtdoor pe1ryx » 07 Mei 2016, 19:48

Morgen ben ik weer thuis,probeer de code dan en laat weten of het werkt!

Dus deze verandering moet teweeg brengen dat de frequentie uitlezing de andere kant op gaat tov wat er uit de schakeling komt.

Begrijp niets van je werk Nico.



In alle gevallen alvast dank voor de genomen moeite,top!

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: AD9850 Arduino vfo

Berichtdoor nicoverduin » 07 Mei 2016, 21:16

Nee het verschil zit hem in het bordje heb ik begrepen. dat staat in dat artikel waarvan ik eerder de link heb gegeven. Zij hebben een afwijking van 25Hz. Nu kan je dat altijd wel corrigeren door er vlak voordat je de waarde laat zien er gewoon 9 vanaf haalt.
Dus deze regel :
cpp code
maakGetalMetSeparators(rx, regel);


in
cpp code
maakGetalMetSeparators(rx-9, regel);


Het aflopen van de frequenties is nog niet gedaan. Geen idee trouwens of die chip dat ook aankan.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 6
Geregistreerd: 04 Mei 2016, 18:58

Re: AD9850 Arduino vfo

Berichtdoor pe1ryx » 07 Mei 2016, 21:31

Nico,


Enkel dit is het probleem: ''Nu is het probleem dat de aangegeven Frequentie in het display foutief word weergegeven.
Op dit moment is de frequentie die uit de schakeling komt 9mhz lager dan wat er op het display weergegeven word.
Hoe draai je dit om?''

op het display wordt onjuist aangegeven,

uit schakeling is frequentie bijvoorbeeld 20mhz,op display moet aangegeven worden 11mhz...nu is het 20mhz out-op display staat 29mhz...dit moet omgedraaid worden!

dit heeft er mee te maken: int_fast32_t iffreq = 9000000; // Intermedite Frequency - Amount to subtract (-) from base frequency. ********************************************

er staat ook subtact (-!) ik wil dus +

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: AD9850 Arduino vfo

Berichtdoor nicoverduin » 07 Mei 2016, 23:30

Dan maak je van die 9000000 toch -9000000. - en - wordt automatisch +. Het is een int dus kan hij ook negatieve getallen aan.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Volgende

Terug naar Arduino IDE

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 3 gasten