HomeMade
Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - Wersja do druku

+- HomeMade (http://sp-hm.pl)
+-- Dział: Urządzenia nadawczo odbiorcze KF (/forum-62.html)
+--- Dział: Syntezy częstotliwości i moduły DSP (/forum-74.html)
+--- Wątek: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO (/thread-2164.html)

Strony: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 15-10-2014 22:32

Obiecane zmiany:

Limitujemy częstotliwość pracy naszej syntezy. Dotychczas krecąc enkoderem mogliśmy naszą syntezę wkręcic na na niedostępne dla AD9850 zakresy prac.
W związku z tym musimy zdefiniować dwie zmienne pomocnicze:

Kod:
const long low_frequency_limit = 0;          //dolny limit częstotliwości
const long high_frequency_limit = 30000000;  //górny limit częstotliwości

Dodatkowo wydzieliłem zmianę częstotliwości którą wysyłamy do DDS-a do osobnej funkcji. Przyda nam się to by spokojnie można było obsługiwać shift częstotliwości dla pośredniej. No i oczywiście łatwiej będzie zarządzać zmianą częstotliwości z jednego miejsca.

Kod:
//funkcja zmieniajaca częstotliwość DDS-a
void set_frequency(int plus_or_minus){
  if(plus_or_minus == 1){                          //jeśli na plus to dodajemy
    frequency = frequency + step_value;            //częstotliwość = częstotliwość + krok    
  }
  else if(plus_or_minus == -1){                    //jeśli na minus to odejmujemy
    frequency = frequency - step_value;            //częstotliwość = częstotliwość - krok    
  }
if(frequency <= low_frequency_limit) frequency = low_frequency_limit;                 //dolny limit
if(frequency >= high_frequency_limit) frequency = high_frequency_limit;               //górny limit
    AD9850.set_frequency(frequency);  //ustawiam syntezę na odpowiedniej częstotliwości  
}

Pełny kod po zmianach poniżej i w załączniku:

Kod:
//**************************************************​**********************//
// Złomek - kumpel Heńka, projekt pogladowy obsługi DDS AD9850,
// wyświetlacza nokii 5110 i jakiegoś enkodera.
// Projekt otwarty http://sp-hm.pl
// SQ9MDD -  początkowy szkielet programu v 1.0.0
// S_____ -
// S_____ -
//
//**************************************************​**********************//
/* CHANGELOG (nowe na górze)
2014.10.15 - v.1.0.3 limit czestotliwości górnej i dolnej
przeniesienie wysyłania częstotliwości do DDS do osobnej funkcji
2014.10.14 - v.1.0.2 zmiana kroku syntezy
2014.10.12 - początek projektu wspólnego na sp-hm.pl
wymiana biblioteki wyświetlacza lcd na LCDD5110 basic
2014.05.22 - pierwsza wersja kodu warsztaty arduino w komorowie.  
*/
//**************************************************​**********************//
//podłączamy bibliotekę syntezera
#include <AH_AD9850.h>

//podłączamy bibliotekę enkodera
#include <RotaryEncoder.h>;

//podłączamy bibliotekę do obsługi wyświetlacza
#include <LCD5110_Basic.h>

//inicjalizujemy komunikację z syntezerem
//syntezer   - arduino
//CLK        - PIN 8
//FQUP       - PIN 9
//BitData    - PIN 10
//RESET      - PIN 11
AH_AD9850 AD9850(8, 9, 10, 11);

// inicjalizujemy wyświetlacz
// lcd    - arduino
// sclk   - PIN 7
// sdin   - PIN 6
// dc     - PIN 5
// reset  - PIN 3
// sce    - PIN 4
LCD5110 lcd(7,6,5,3,4);
extern uint8_t SmallFont[]; //czcionka z biblioteki
extern uint8_t MediumNumbers[];//czcionka z biblioteki

//inicjalizujemy enkoder
//AO - w lewo
//A1 - w prawo
//nalezy pamiętać o kondensatorach (100nF) pomiędzy liniami encodera a masą
RotaryEncoder encoder(A0,A1,5,6,1000);

//zmienne do modyfikacji
const int kontrast = 70;                     //kontrast wyświetlacza
const int pulses_for_groove = 2;             //ilość impulsów na ząbek enkodera zmienić w zależności od posiadanego egzemplarza
const int step_input = A2;                   //wejście do podłączenia przełącznika zmiany kroku
const long low_frequency_limit = 0;          //dolny limit częstotliwości
const long high_frequency_limit = 30000000;  //górny limit częstotliwości

//zmienne wewnętrzne,
//jeśli nie trzeba proszę nie modyfikować
char buffor[] = "              ";            //zmienna pomocnicza do wyrzucania danych na lcd
long frequency = 10000000;                   //zmienna dla częstotliwości, wstawiamy tam częstotliwość od której startujemy
long step_value = 100;                       //domyślny krok syntezy
int enc_sum = 0;                             //zmienna pomocnicza do liczenia impulsów z enkodera

//funkcja do zmiany kroku syntezy

//funkcja do obsługi wyświetlania zmiany częstotliwości
void show_frequency(){
  lcd.setFont(SmallFont);                    //ustawiamy czcionkę
  sprintf(buffor,"%08lu",frequency);         //konwersja danych do wyświetlenia (ładujemy longa do stringa
  lcd.print(buffor,CENTER,0);                //wyświetlamy dane na lcd
}

//funkcja do wyświetlania aktualnego kroku syntezera
void show_step(){
  lcd.setFont(SmallFont);                     //ustawiamy czcionkę
  sprintf(buffor,"%08lu",step_value);         //konwersja danych do wyświetlenia (ładujemy longa do stringa
  lcd.print(buffor,CENTER,8);                 //wyświetlamy dane na lcd (8 oznacza drugi rząd)
}

//funkcja zmieniajaca częstotliwość DDS-a
void set_frequency(int plus_or_minus){
  if(plus_or_minus == 1){                          //jeśli na plus to dodajemy
    frequency = frequency + step_value;            //częstotliwość = częstotliwość + krok    
  }
  else if(plus_or_minus == -1){                    //jeśli na minus to odejmujemy
    frequency = frequency - step_value;            //częstotliwość = częstotliwość - krok    
  }
if(frequency <= low_frequency_limit) frequency = low_frequency_limit;                 //dolny limit
if(frequency >= high_frequency_limit) frequency = high_frequency_limit;               //górny limit
    AD9850.set_frequency(frequency);  //ustawiam syntezę na odpowiedniej częstotliwości  
}

// setup funkcja odpalana przy starcie
void setup(){  
  Serial.begin(9600);                          //uruchamiam port szeregowy w celach diagnostycznych
  AD9850.set_frequency(0,0,frequency);        //odpalamy syntezer i ustawiamy częstotliwość startową
  delay(1000);                                //sekunda opóźnienia
  lcd.InitLCD(kontrast);                      //odpalamy lcd ustawiamy kontrast
  show_frequency();                           //pokazmy cos na lcd
  pinMode(step_input,INPUT_PULLUP);           //inicjalizujemy wejście zmiany kroku i podciągamy je do plusa
  show_step();
}

void loop(){  
  int enc = encoder.readEncoder();        //czytamy wartość z encodera
  if(enc != 0) {                          //jeśli wartość jest inna niż zero sumujemy
    enc_sum = enc_sum + enc;              //jeden ząbek encodera to +2 lub -2 tutaj to zliczam
    Serial.println(enc);                  //wyrzucamy na port rs-232 wartość licznika enkodera (debugowanie)
  }
  
  //obsługa klawisza zmiany kroku
  if(digitalRead(step_input) == LOW){     //sprawdzanie czy przycisk jest wcisnięty
   delay(100);                            //odczekajmy 100msec
    if(digitalRead(step_input) == LOW){   //jeśli klawisz nadal jest wcisnięty (czyli nie są to zakłócenia)
       switch(step_value){                //za pomocą instrukcji swich zmieniamy krok
          case 100000:                    //jeśli krok jest 100kHz ustaw 100Hz
            step_value = 100;
          break;
          case 10000:                     //jeśli krok jest 10kHz ustaw 100kHz
            step_value = 100000;
          break;
          case 1000:                      //jeśli krok jest 1kHz ustaw 10kHz
            step_value = 10000;
          break;
          case 100:                       //jeśli krok jest 100Hz ustaw 1kHz
            step_value = 1000;
          break;
       }
    }
    show_step();                          //pokazuję zmianę kroku na lcd
    delay(300);                           //zwłoka po zmianie kroku 300msec
  }
  
  //jesli zaliczyliśmy ząbek dodajemy lub odejmujemy do częstotliwości wartość kroku (na razie na sztywno 100Hz)
  if(enc_sum >= pulses_for_groove){
    set_frequency(1);                     //wywołuję funkcje zmiany częstotliwości z parametrem +
    show_frequency();                     //drukuję częstotliwość na wyświetlaczu za pomocą gotowej funkcji
    enc_sum = 0;                          //reset zmiennej zliczającej impulsy enkodera
  }
  if(enc_sum <= -(pulses_for_groove)){
    set_frequency(-1);                    //wywołuję funkcje zmiany częstotliwości z parametrem -
    show_frequency();                     //drukuję częstotliwość na wyświetlaczu za pomocą gotowej funkcji      
    enc_sum = 0;                          //reset zmiennej zliczającej impulsy enkodera
  }  
  delayMicroseconds(5);                    //małe opóźnienie dla prawidłowego działania enkodera
}

//testowanie dostępnego RAMU
/*
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
*/
//**************************************************​**********************//
// Złomek - kumpel Heńka, projekt pogladowy obsługi DDS AD9850,
// wyświetlacza nokii 5110 i jakiegoś enkodera.
// Projekt otwarty http://sp-hm.pl
// SQ9MDD -  początkowy szkielet programu v 1.0.0
// S_____ -
// S_____ -
//
//**************************************************​**********************//
/* CHANGELOG (nowe na górze)
2014.10.15 - v.1.0.3 limit czestotliwości górnej i dolnej
przeniesienie wysyłania częstotliwości do DDS do osobnej funkcji
2014.10.14 - v.1.0.2 zmiana kroku syntezy
2014.10.12 - początek projektu wspólnego na sp-hm.pl
wymiana biblioteki wyświetlacza lcd na LCDD5110 basic
2014.05.22 - pierwsza wersja kodu warsztaty arduino w komorowie.  
*/
//**************************************************​**********************//
//podłączamy bibliotekę syntezera
#include <AH_AD9850.h>

//podłączamy bibliotekę enkodera
#include <RotaryEncoder.h>;

//podłączamy bibliotekę do obsługi wyświetlacza
#include <LCD5110_Basic.h>

//inicjalizujemy komunikację z syntezerem
//syntezer   - arduino
//CLK        - PIN 8
//FQUP       - PIN 9
//BitData    - PIN 10
//RESET      - PIN 11
AH_AD9850 AD9850(8, 9, 10, 11);

// inicjalizujemy wyświetlacz
// lcd    - arduino
// sclk   - PIN 7
// sdin   - PIN 6
// dc     - PIN 5
// reset  - PIN 3
// sce    - PIN 4
LCD5110 lcd(7,6,5,3,4);
extern uint8_t SmallFont[]; //czcionka z biblioteki
extern uint8_t MediumNumbers[];//czcionka z biblioteki

//inicjalizujemy enkoder
//AO - w lewo
//A1 - w prawo
//nalezy pamiętać o kondensatorach (100nF) pomiędzy liniami encodera a masą
RotaryEncoder encoder(A0,A1,5,6,1000);

//zmienne do modyfikacji
const int kontrast = 70;                     //kontrast wyświetlacza
const int pulses_for_groove = 2;             //ilość impulsów na ząbek enkodera zmienić w zależności od posiadanego egzemplarza
const int step_input = A2;                   //wejście do podłączenia przełącznika zmiany kroku
const long low_frequency_limit = 0;          //dolny limit częstotliwości
const long high_frequency_limit = 30000000;  //górny limit częstotliwości

//zmienne wewnętrzne,
//jeśli nie trzeba proszę nie modyfikować
char buffor[] = "              ";            //zmienna pomocnicza do wyrzucania danych na lcd
long frequency = 10000000;                   //zmienna dla częstotliwości, wstawiamy tam częstotliwość od której startujemy
long step_value = 100;                       //domyślny krok syntezy
int enc_sum = 0;                             //zmienna pomocnicza do liczenia impulsów z enkodera

//funkcja do zmiany kroku syntezy

//funkcja do obsługi wyświetlania zmiany częstotliwości
void show_frequency(){
  lcd.setFont(SmallFont);                    //ustawiamy czcionkę
  sprintf(buffor,"%08lu",frequency);         //konwersja danych do wyświetlenia (ładujemy longa do stringa
  lcd.print(buffor,CENTER,0);                //wyświetlamy dane na lcd
}

//funkcja do wyświetlania aktualnego kroku syntezera
void show_step(){
  lcd.setFont(SmallFont);                     //ustawiamy czcionkę
  sprintf(buffor,"%08lu",step_value);         //konwersja danych do wyświetlenia (ładujemy longa do stringa
  lcd.print(buffor,CENTER,8);                 //wyświetlamy dane na lcd (8 oznacza drugi rząd)
}

//funkcja zmieniajaca częstotliwość DDS-a
void set_frequency(int plus_or_minus){
  if(plus_or_minus == 1){                          //jeśli na plus to dodajemy
    frequency = frequency + step_value;            //częstotliwość = częstotliwość + krok    
  }
  else if(plus_or_minus == -1){                    //jeśli na minus to odejmujemy
    frequency = frequency - step_value;            //częstotliwość = częstotliwość - krok    
  }
if(frequency <= low_frequency_limit) frequency = low_frequency_limit;                 //dolny limit
if(frequency >= high_frequency_limit) frequency = high_frequency_limit;               //górny limit
    AD9850.set_frequency(frequency);  //ustawiam syntezę na odpowiedniej częstotliwości  
}

// setup funkcja odpalana przy starcie
void setup(){  
  Serial.begin(9600);                          //uruchamiam port szeregowy w celach diagnostycznych
  AD9850.set_frequency(0,0,frequency);        //odpalamy syntezer i ustawiamy częstotliwość startową
  delay(1000);                                //sekunda opóźnienia
  lcd.InitLCD(kontrast);                      //odpalamy lcd ustawiamy kontrast
  show_frequency();                           //pokazmy cos na lcd
  pinMode(step_input,INPUT_PULLUP);           //inicjalizujemy wejście zmiany kroku i podciągamy je do plusa
  show_step();
}

void loop(){  
  int enc = encoder.readEncoder();        //czytamy wartość z encodera
  if(enc != 0) {                          //jeśli wartość jest inna niż zero sumujemy
    enc_sum = enc_sum + enc;              //jeden ząbek encodera to +2 lub -2 tutaj to zliczam
    Serial.println(enc);                  //wyrzucamy na port rs-232 wartość licznika enkodera (debugowanie)
  }
  
  //obsługa klawisza zmiany kroku
  if(digitalRead(step_input) == LOW){     //sprawdzanie czy przycisk jest wcisnięty
   delay(100);                            //odczekajmy 100msec
    if(digitalRead(step_input) == LOW){   //jeśli klawisz nadal jest wcisnięty (czyli nie są to zakłócenia)
       switch(step_value){                //za pomocą instrukcji swich zmieniamy krok
          case 100000:                    //jeśli krok jest 100kHz ustaw 100Hz
            step_value = 100;
          break;
          case 10000:                     //jeśli krok jest 10kHz ustaw 100kHz
            step_value = 100000;
          break;
          case 1000:                      //jeśli krok jest 1kHz ustaw 10kHz
            step_value = 10000;
          break;
          case 100:                       //jeśli krok jest 100Hz ustaw 1kHz
            step_value = 1000;
          break;
       }
    }
    show_step();                          //pokazuję zmianę kroku na lcd
    delay(300);                           //zwłoka po zmianie kroku 300msec
  }
  
  //jesli zaliczyliśmy ząbek dodajemy lub odejmujemy do częstotliwości wartość kroku (na razie na sztywno 100Hz)
  if(enc_sum >= pulses_for_groove){
    set_frequency(1);                     //wywołuję funkcje zmiany częstotliwości z parametrem +
    show_frequency();                     //drukuję częstotliwość na wyświetlaczu za pomocą gotowej funkcji
    enc_sum = 0;                          //reset zmiennej zliczającej impulsy enkodera
  }
  if(enc_sum <= -(pulses_for_groove)){
    set_frequency(-1);                    //wywołuję funkcje zmiany częstotliwości z parametrem -
    show_frequency();                     //drukuję częstotliwość na wyświetlaczu za pomocą gotowej funkcji      
    enc_sum = 0;                          //reset zmiennej zliczającej impulsy enkodera
  }  
  delayMicroseconds(5);                    //małe opóźnienie dla prawidłowego działania enkodera
}

//testowanie dostępnego RAMU
/*
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
*/

Kolejny etap naszej pracy to wprowadzenie offsetu dla pośredniej.
Juz wkrótce Wink


UPDATE

Właśnie zwróciłem uwagę że arduino posiada funkcję constrain która ogranicza ładnie min i max dla zmiennej.

W mojej wersji softu po kompilacji: Wielkość binarna szkicu: 10 368 bajtów.

Jeśli jednak użyję constrain czyli zamiast:

Kod:
if(frequency <= low_frequency_limit) frequency = low_frequency_limit;                 //dolny limit
if(frequency >= high_frequency_limit) frequency = high_frequency_limit;               //górny limit

użyję kodu:

Kod:
frequency = constrain(frequency,low_frequency_limit,high_frequ​ency_limit);

to kod wynikowy się zmniejsza: Wielkość binarna szkicu: 10 328 bajtów

Poprawione źródło w załączniku: zlomek_v_1_0_3-141015b.zip


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ6IYY - 16-10-2014 23:14

Witam. Odpaliłem Arduino Uno i załadowałem Zlomek jest :
LCD wyświetla ,impulsator zmienia wartość i mam dwa pytania :
pitanie 1:
//inicjalizujemy enkoder
//AO - w lewo
//A1 - w prawo
//nalezy pamiętać o kondensatorach (100nF) pomiędzy liniami encodera a masą
RotaryEncoder
encoder(A0,A1,5,6,1000);
na który pin podpiąć obsługa klawisza zmiany kroku 5,6 ??
LCD jest tam podpięty ?
// inicjalizujemy wyświetlacz
// lcd - arduino
// sclk - PIN 7
// sdin - PIN 6
// dc - PIN 5
// reset - PIN 3
// sce - PIN 4
LCD5110 lcd(7,6,5,3,4)
pitanie 2:
DDS z AD9851 zegar 30MHz podpinamy trochę inaczej??{sterujemy}
http://blog.marxy.org/2008/05/controlling-ad9851-dds-with-arduino.html
pozdrawiam


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 16-10-2014 23:47

Cześć.

Klawisz zmiany kroku podpinasz tak jak opisane jest w kodzie:

Kod:
const int step_input = A2;                   //wejście do podłączenia przełącznika zmiany kroku

Czyli wejscie A2 do masy poprzez przełacznik w enkoderze albo zewnętrzny przełącznik dajesz jeśli nie masz przełącznika w enkoderze.

Jeśli chodzi o AD9850 jest to opisane jasno i nie kombinujemy inaczej:

Kod:
//syntezer pin    - arduino pin
//CLK        - PIN 8
//FQUP       - PIN 9
//BitData    - PIN 10
//RESET      - PIN 11



RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ6IYY - 17-10-2014 10:43

Witam dzekuje za odpowiedz a na temat AD9850 sie zgadzam jest to opisane jasno i nie kombinujemy
Ale ja mam AD9851 z zegarem 30Mhz PCB home made i podpiecie jest:
Kod:
//syntezer pin - arduino pin
//CLK - PIN 8
//FQUP - PIN 9
//BitData - PIN 10
//RESET - PIN 11
a co z sterowaniem dds-a zegar nie pasuje 30 zamiast 125MHz brak 6x zegar itp.
czy najlepiej wydać na nowy DDS z AD9850 i mieć święti spokój na razie potem pomyśleć o AD9851
pozdrawiam


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ5KVS - 17-10-2014 15:43

Nie wiem jak to jest jeśli chodzi o piny, ale jeśli chodzi o obliczanie tuning-word to jest dokładnie identycznie.
Natomiast - jak tu kilka postów wyżej rozmawialiśmy o wielkości kodu wynikowego - na Atmedze32 to faktycznie można nie spotkać tego problemu, ale na 168 czy 88 można. Tam użycie funkcji zmiennoprzecinkowej zabiera kilkadziesiąt jak nie więcej kodu więcej. Stąd moje kiedyś poszukiwania jak obliczyć wystarczająco dokładnie tuning-word do DDS'a, bez używania FLOAT.

http://www.picbasic.co.uk/forum/content.php?r=497-How-to-calculate-the-32bit-tuning-value-for-the-AD9850-DDS-chip
Może się komuś przyda Smile


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 18-10-2014 9:32

Tuning word jest zdefiniowany w AH_AD9850.cpp który znajduje się w katalogu libraries/AH_AD9850 w folderze gdzie zainstalowano arduino.

Kod:
//Calculate the frequency of the HEX value
  //x=4294967295/125;        //Suitable for 125M Crystal
  //x = 4294967295/125;
  //x = 34359738
  x = 34360200;   //< --- kalibracja tutaj
  //x = 70450000;

Wydaje mi się że jeśli wartość 4294967295 podzielisz na 30 a nie tak jak jest na 125 to może to zadziałać. Tak zgaduję Wink

No i przy okazji Ryśku informacja też dla Ciebie gdzie można pogrzebać by skalibrować tego DDS-a. Jak widzisz tutaj mam wpisaną wartość inną niż wynika z obliczeń, to jest skalibrowana moja synteza.


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 19-10-2014 11:55

W dzisiejszym odcinku zróbmy wreszcie tę syntezę możliwą do użycia.
Na początek w jakimś jednopasmowym urządzeniu. Dzięki temu łatwiej jest zrozumieć wszystkie mechanizmy działania takiej syntezy, i pozwala to na wymyślenie dalszej ścieżki rozwoju.
Dla prostoty tłumaczania zakładamy hipotetycznie że nasz odbiornik będzie pracował w zakresie 3500kHz do 3800kHz z pośrednią 8000kHz

Jako ze w naszym projekcie wychodziliśmy od częstotliwości wyświetlanej, więc to tę częstotliwość będziemy przeliczać by uzyskać właściwą częstotliwość generatora.

Częstotliwość generatora może być sumą lub różnicą pośredniej i czestotliwości wyświetlanej. W naszym kodzie będzie to miało następującą postać:

Kod:
long frequency_to_dds = abs(posrednia + frequency);

Dla tak skonstruowanego przeliczenia do programu wprowadzamy jako parametr częstotliwość pośrednią jako "-pośrednia" lub "pośrednia"*

Kod:
const long posrednia = -8000000;

Poniżej cały kod syntezy:
Kod:
//**************************************************​**********************//
// Złomek - kumpel Heńka, projekt pogladowy obsługi DDS AD9850,
// wyświetlacza nokii 5110 i jakiegoś enkodera.
// Projekt otwarty http://sp-hm.pl/thread-2164.html
// SQ9MDD -  początkowy szkielet programu v 1.0.0
// S_____ -
// S_____ -
//
//**************************************************​**********************//
/* CHANGELOG (nowe na górze)
2014.10.19 - v.1.0.4 wprowadzamy pośrednią kilka zmiennych do sekcji konfiguracji
drobne czyszczenie kodu, poprawki w komentarzach
2014.10.15 - v.1.0.3 limit czestotliwości górnej i dolnej
przeniesienie wysyłania częstotliwości do DDS do osobnej funkcji
2014.10.14 - v.1.0.2 zmiana kroku syntezy
2014.10.12 - początek projektu wspólnego na sp-hm.pl
wymiana biblioteki wyświetlacza lcd na LCDD5110 basic
2014.05.22 - pierwsza wersja kodu warsztaty arduino w komorowie.  
*/
//**************************************************​**********************//
//podłączamy bibliotekę syntezera
#include <AH_AD9850.h>

//podłączamy bibliotekę enkodera
#include <RotaryEncoder.h>;

//podłączamy bibliotekę do obsługi wyświetlacza
#include <LCD5110_Basic.h>

//inicjalizujemy komunikację z syntezerem
//syntezer   - arduino
//CLK        - PIN 8
//FQUP       - PIN 9
//BitData    - PIN 10
//RESET      - PIN 11
AH_AD9850 AD9850(8, 9, 10, 11);

// inicjalizujemy wyświetlacz
// lcd    - arduino
// sclk   - PIN 7
// sdin   - PIN 6
// dc     - PIN 5
// reset  - PIN 3
// sce    - PIN 4
LCD5110 lcd(7,6,5,3,4);
extern uint8_t SmallFont[]; //czcionka z biblioteki
extern uint8_t MediumNumbers[];//czcionka z biblioteki

//inicjalizujemy enkoder
//AO - w lewo
//A1 - w prawo
//nalezy pamiętać o kondensatorach (100nF) pomiędzy liniami encodera a masą
RotaryEncoder encoder(A0,A1,5,6,1000);

//**************************************************​**************************************************​*************************
//zmienne do modyfikacji każdy ustawia to co potrzebuje
const int kontrast = 70;                     //kontrast wyświetlacza
const int pulses_for_groove = 2;             //ilość impulsów na ząbek enkodera zmienić w zależności od posiadanego egzemplarza
const int step_input = A2;                   //wejście do podłączenia przełącznika zmiany kroku
const long low_frequency_limit = 3500000;    //dolny limit częstotliwości
const long high_frequency_limit = 3800000;   //górny limit częstotliwości
const long start_frequency = 3715000;        //częstotliwość startowa
const long posrednia = -8000000;             //częstotliwość pośredniej, każdy dobiera swoją w zależności od konstrukcji radia
//**************************************************​**************************************************​*************************

//zmienne wewnętrzne,
//jeśli nie trzeba proszę nie modyfikować
char buffor[] = "              ";            //zmienna pomocnicza do wyrzucania danych na lcd
long frequency = start_frequency;            //zmienna dla częstotliwości, wstawiamy tam częstotliwość od której startujemy
long step_value = 100;                       //domyślny krok syntezy
int enc_sum = 0;                             //zmienna pomocnicza do liczenia impulsów z enkodera

//funkcja do obsługi wyświetlania zmiany częstotliwości
void show_frequency(){
  lcd.setFont(SmallFont);                    //ustawiamy czcionkę
  sprintf(buffor,"%08lu",frequency);         //konwersja danych do wyświetlenia (ładujemy częstotliwość do stringa i na ekran)
  lcd.print(buffor,CENTER,0);                //wyświetlamy dane na lcd
}

//funkcja do wyświetlania aktualnego kroku syntezera
void show_step(){
  lcd.setFont(SmallFont);                     //ustawiamy czcionkę
  sprintf(buffor,"%08lu",step_value);         //konwersja danych do wyświetlenia (ładujemy krok syntezy do stringa i na ekran)
  lcd.print(buffor,CENTER,8);                 //wyświetlamy dane na lcd (8 oznacza drugi rząd)
}

//funkcja zmieniajaca częstotliwość DDS-a
void set_frequency(int plus_or_minus){
  if(plus_or_minus == 1){                                                        //jeśli na plus to dodajemy
    frequency = frequency + step_value;                                          //częstotliwość = częstotliwość + krok    
  }  
  else if(plus_or_minus == -1){                                                  //jeśli na minus to odejmujemy
    frequency = frequency - step_value;                                          //częstotliwość = częstotliwość - krok    
  }
    frequency = constrain(frequency,low_frequency_limit,high_frequ​ency_limit);   //limitowanie zmiennej
    long frequency_to_dds = abs(posrednia + frequency);                          //a tutaj obliczam częstotliwość wynikową
    AD9850.set_frequency(frequency_to_dds);                                      //ustawiam syntezę na odpowiedniej częstotliwości  
    Serial.println(frequency_to_dds);
}

// setup funkcja odpalana przy starcie
void setup(){  
  Serial.begin(9600);                         //uruchamiam port szeregowy w celach diagnostycznych      
  lcd.InitLCD(kontrast);                      //odpalamy lcd ustawiamy kontrast
  pinMode(step_input,INPUT_PULLUP);           //inicjalizujemy wejście zmiany kroku i podciągamy je do plusa
  set_frequency(0);                           //odpalamy syntezer i ustawiamy częstotliwość startową
  delay(1000);                                //sekunda opóźnienia  
  show_frequency();                           //pokazujemy częstotliwość na lcd
  show_step();                                //pokazujemy krok syntezy
}

void loop(){  
  int enc = encoder.readEncoder();        //czytamy wartość z encodera
  if(enc != 0) {                          //jeśli wartość jest inna niż zero sumujemy
    enc_sum = enc_sum + enc;              //jeden ząbek encodera to +2 lub -2 tutaj to zliczam
    Serial.println(enc);                  //wyrzucamy na port rs-232 wartość licznika enkodera (debugowanie)
  }
  
  //obsługa klawisza zmiany kroku
  if(digitalRead(step_input) == LOW){     //sprawdzanie czy przycisk jest wcisnięty
   delay(100);                            //odczekajmy 100msec
    if(digitalRead(step_input) == LOW){   //jeśli klawisz nadal jest wcisnięty (czyli nie są to zakłócenia)
       switch(step_value){                //za pomocą instrukcji swich zmieniamy krok
          case 100000:                    //jeśli krok jest 100kHz ustaw 100Hz
            step_value = 100;
          break;
          case 10000:                     //jeśli krok jest 10kHz ustaw 100kHz
            step_value = 100000;
          break;
          case 1000:                      //jeśli krok jest 1kHz ustaw 10kHz
            step_value = 10000;
          break;
          case 100:                       //jeśli krok jest 100Hz ustaw 1kHz
            step_value = 1000;
          break;
       }
    }
    show_step();                          //pokazuję zmianę kroku na lcd
    delay(300);                           //zwłoka po zmianie kroku 300msec
  }
  
  //jesli zaliczyliśmy ząbek dodajemy lub odejmujemy do częstotliwości wartość kroku (na razie na sztywno 100Hz)
  if(enc_sum >= pulses_for_groove){
    set_frequency(1);                     //wywołuję funkcje zmiany częstotliwości z parametrem +
    show_frequency();                     //drukuję częstotliwość na wyświetlaczu za pomocą gotowej funkcji
    enc_sum = 0;                          //reset zmiennej zliczającej impulsy enkodera
  }
  if(enc_sum <= -(pulses_for_groove)){
    set_frequency(-1);                    //wywołuję funkcje zmiany częstotliwości z parametrem -
    show_frequency();                     //drukuję częstotliwość na wyświetlaczu za pomocą gotowej funkcji      
    enc_sum = 0;                          //reset zmiennej zliczającej impulsy enkodera
  }  
  delayMicroseconds(5);                    //małe opóźnienie dla prawidłowego działania enkodera
  
}

//testowanie ilości dostępnego RAMU
/*
int freeRam () {
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
*/


W kolejnych odcinkach(mały roadmap):
- dodamy logo złomka przy starcie
- opracujemy ładniejszy sposób wyświetlania danych
- spróbujemy zrobić jakiś prosty s-metr
- przygotujemy możliwość pracy ze splitem
- przystosujemy syntezę do pracy na kilku pasmach
- przygotujemy zapis częstotliwości pracy do eepromu



* podane częstotliwości są czysto hipotetyczne i jakakolwiek ich zbieżność z prawdziwymi częstotliwościami jest tylko przypadkowa



RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SP6IFN - 19-10-2014 12:58

O super! Bardzo ładnie się wątek rozwija. Coraz ciekawsze rzeczy do zapamiętania. Gratulacje dla autora wątku!
Rysio!


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ6IYY - 19-10-2014 13:18

Nek żyje Zlomek lub Zlomek żyje Rolleyes w celu ćwiczeń krok 10Hz i większe numerki(nosze okularki)Cool[attachment=9103]


RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 19-10-2014 13:27

Brawo Michał widzę że już zaczyna się zabawa i bardzo dobrze. Dokładnie ten efekt chciałem osiągnąć Smile