+- 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)
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - DA_KAR - 19-10-201421:51
(19-10-2014 13:18)SQ6IYY napisał(a): Nek żyje Zlomek lub Zlomek żyje w celu ćwiczeń krok 10Hz i większe numerki(nosze okularki)
Też noszę okulary i powiększyłem numerki.
Tylko zabawa połowiczna bo nie mam enkodera i DDS-a
(nie zdążyły przyjść w piątek, może w poniedziałek).
Brak też stabilizatora 3,3V , połączyłem szeregowo
czerwoną diodę i dwie prostownicze, wyszło 3,2V. Działa!
Chętnie się jeszcze pobawię.
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 20-10-20149:57
Przygotowaliśmy już projekt do pracy z jednopasmowym transceiverem, i teraz w planach było zajęcie się sposobem wyświetlania danych. Aby zadbać o efekt końcowy skorzystamy z bliźniaczej do dotychczas używanej biblioteki obsługi LCD.
Jest to biblioteka graficzna, będzie nam łatwiej narysować s-metr i inne elementy graficzne naszej syntezy. Sposób użycia nowej bibllioteki, zasadniczo nie wiele się różni od tej bazowej.
Po pierwsze musimy podłączyć właściwą bibliotekę.
Zamiast:
Kod:
#include <LCD5110_Basic.h>
Mamy:
Kod:
#include <LCD5110_Graph.h>
Następnie inicjalizacja:
Kod:
LCD5110 myGLCD(7,6,5,3,4);
Noi samo uzycie też musi być wywoływane inaczej:
Kod:
myGLCD.setFont(SmallFont); //ustawiamy czcionkę
sprintf(buffor,"%08lu",step_value); //konwersja danych do wyświetlenia (ładujemy krok syntezy do stringa i na ekran)
myGLCD.print(buffor,CENTER,8); //wyświetlamy dane na lcd (8 oznacza drugi rząd)
myGLCD.update();
Na uwagę zwraca myGLCD.update(); jest to znacząca zmiana w bibliotece podstawowej nie musieliśmy tego uzywać.
Poniżej w załączeniu wersja ze zmienioną biblioteką, od tej chwili będziemy mogli łatwo rysować na naszym wyświetlaczu.
W następnym odcinku przedstawię implementację prostego wskaźnika S-Metr autorstwa Rysia SP6IFN za którego namową zmieniliśmy bibliotekę obsługi LCD.
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 20-10-201418:43
Dobra Panowie, no nie wytrzymam dłużej bo miałem chwilę dzisiaj rano i napisałem trochę kodu, tak to wygląda:
Po zmianie biblioteki do obsługi wyświetlacza LCD możemy rysować na nim linie okręgi kwadraty itd.
Prace zacząłem od zmiany sposobu wyświetlenia częstotliwości, następnie dodałem funkcję która rysuje stałe elementy wyświetlacza przy starcie procesora, a na koniec dodałem s-metr którego autorem jest Rysio SP6IFN.
Uwagę należy zwrócić na funkcję rysowania s-metra zbyt częste jej odpalenie, lub zbyt mocne rozbudowanie, może spowodować błędy w działaniu enkodera. Po prostu procesor będzie zajęty rysowaniem i nie zauważy ruchu enkodera, który nie jest obsługiwany w przerwaniach.
Ponizej kod po poprawkach, oczywiście każdy może dowolnie przerysować sobie wyświetlacz po swojemu. Wszystkie funkcje starałem się detalicznie opisać tak by nie było problemu z identyfikacją co jaka część kodu robi.
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 - 1.0.5
// SP6IFN - przejście na bibliotekę graficzną i parę zmian 1.0.5 s-metr
// S_____ -
//
//************************************************************************//
/* CHANGELOG (nowe na górze)
2014.10.20 - v.1.0.6 przepisany sposób wyświetlania danych (pozostał jeden znany bug do poprawki)
wyczyszczone komentarze, dodanie s-metra według pomysłu Rysia SP6IFN
2014.10.20 - v.1.0.5 wymiana biblioteki wyświetlacza LCD
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.
*/
//************************************************************************//
//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
long step_value = 100; //domyślny krok syntezy
int s_metr_port = A5; //wejście dla s-metra
const long s_metr_update_interval = 100; //interwał odświeżania s-metra w msec
//*****************************************************************************************************************************
//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
int enc_sum = 0; //zmienna pomocnicza do liczenia impulsów z enkodera
long s_metr_update_time = 0; //zmienna pomocnicza do przechowywania czasu następnego uruchomienia s-metra
//funkcja do obsługi wyświetlania zmiany częstotliwości
void show_frequency(){
long f_prefix = frequency/1000; //pierwsza część częstotliwości dużymi literkami
long f_sufix = frequency%1000; //obliczamy resztę z częstotliwości
sprintf(buffor,"%lu",f_prefix); //konwersja danych do wyświetlenia (ładujemy częstotliwość do stringa i na ekran)
myGLCD.setFont(MediumNumbers); //ustawiamy czcionkę dla dużych cyfr
myGLCD.print(buffor,13,10); //wyświetlamy duże cyfry na lcd
sprintf(buffor,".%03lu",f_sufix); //konwersja danych do wyświetlenia (ładujemy częstotliwość do stringa i na ekran)
myGLCD.setFont(SmallFont); //ustawiamy małą czcionkę
myGLCD.print(buffor,60,19); //wyświetlamy małe cyfry na lcd
myGLCD.update(); //wysyłamy dane do bufora wyświetlacza
}
//funkcja do wyświetlania aktualnego kroku syntezera za pomocą podkreślenie odpowiedniej cyfry
void show_step(){
myGLCD.clrLine(0,28,83,28); //czyszczę cała linię gdzie wyświetlam podkreślenie
myGLCD.clrLine(0,29,83,29); //czyszczę druga linię tak samo podkreśliniki są grube na dwa piksele
switch(step_value){ //przełącznik reaguje na bieżącą wartość kroku syntezy
case 100:
myGLCD.drawLine(69, 28, 82, 28); //pokreślam 100Hz
myGLCD.drawLine(69, 29, 82, 29); //pokreślam 100Hz
break;
case 1000:
myGLCD.drawLine(51, 28, 59, 28); //pokreślam 1kHz
myGLCD.drawLine(51, 29, 59, 29); //pokreślam 1kHz
break;
case 10000:
myGLCD.drawLine(39, 28, 47, 28); //pokreślam 10kHz
myGLCD.drawLine(39, 29, 47, 29); //pokreślam 10kHz
break;
case 100000:
myGLCD.drawLine(27, 28, 35, 28); //pokreślam 100kHz
myGLCD.drawLine(27, 29, 35, 29); //pokreślam 100kHz
break;
}
myGLCD.update(); //jak już ustaliliśmy co rysujemy to wysyłamy to do LCD
}
//funkcja ustawiająca 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_frequency_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); //wypluwanie na rs-232 częstotliwości generatora (debugowanie)
}
//wskaźnik s-metra by nie przeszkadzał w pracy enkodera zrobiony jest na pseudo współdzieleniu czasu.
//każdorazowe wykonanie tej funkcji przestawia czas następnego jej wykonania o czas podany w konfiguracji domyślnie 100msec
void show_smetr(){
if(millis() >= s_metr_update_time){ //sprawdzam czy już jest czas na wykonanie funkcji
myGLCD.clrLine(1, 45, 83, 45); //czyścimy stare wskazanie s-metra linia pierwsza
myGLCD.clrLine(1, 46, 83, 46); //czyścimy stare wskazanie s-metra linia druga
int s_value = analogRead(A5); //czytamy wartość z wejścia gdzie jest podpięty sygnał s-metra
int s_position = map(s_value,0,1023,1,83); //przeskalowuję zakres z wejścia analogowego na szerokość wyświetlacza
myGLCD.drawLine(1, 45, s_position, 45); //rysuję nową linię wskazania s metra
myGLCD.drawLine(1, 46, s_position, 46); //rysuję nową linię wskazania s metra
myGLCD.update(); //wysyłam dane do bufora wyświetlacza
s_metr_update_time = millis() + s_metr_update_interval; //ustawiam czas kolejnego wykonania tej funkcji
}
}
//tutaj rysujemy domyślne elementy ekranu będziemy to robić raz,
//tak by nie przerysowywać całego ekranu podczas pracy syntezy
void show_template(){
myGLCD.setFont(TinyFont); //najmniejsza czcionka
myGLCD.print("S1.3.5.7.9.+20.40.60.", CENTER, 38); //opis dla s-metra
myGLCD.drawRect(0, 44, 83, 47); //rysujemy prostokąt dla s-metra podając koordynaty narożników
myGLCD.update(); //i wypluwamy to na lcd
}
// setup funkcja odpalana przy starcie
void setup(){
pinMode(s_metr_port,INPUT);
Serial.begin(9600); //uruchamiam port szeregowy w celach diagnostycznych
myGLCD.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
show_template(); //pokazujemy domyślne stałe elementy LCD
}
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
show_smetr();
}
//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);
}
*/
Ciekaw jestem waszych postępów w pracach. Może macie jakieś poprawki zmiany itp.
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SP9MRN - 20-10-201419:57
Złomek wygląda super. ;-)
Proponuję tylko odwrócić kolejność ustawiania kroku, bo naturalnym jest coraz dokładniejsze wstrajanie się w stację - czyli krok powinien się zmniejszać a nie zwiększać.
I jeszcze jedno - ponieważ smeter zabiera trochę czasu procesora, to dobrze jest go trochę zoptymalizować. Doczytałem kiedyś, że map() jest jedną z paskudniejszych funkcji arduino. Jeżeli nie najwolniejszą.
Dlaczego? - bo żeby zrobić mapowanie to mnoży i dzieli. a arduino tak naprawdę, to szybko potrafi dzielić wyłącznie przez 2
Zatem lepiej zrezygnować z paru pikseli, zostawić ich 80 i zastosować szybkie przesunięcie zamiast mapowania:
(>>7 to przesunięcie liczby binarnej o 7 pozycji czyli tak naprawdę podzielenie przez 128)
old:
int s_position = map(s_value,0,1023,1,83);
new:
int_position = (s_value*10)>>7
czyli w przetłumaczonej na ludzki język wersji (uawga tylko dla ludzi nie dla procesora):
int_position = (s_value*10)/128 - to tak żeby sobie sprawdzić :-)
zwykle jest tak, że przy atmegowej dokładności przetwornika analogowo cyfrowego możemy sobie pozwolić na zaokrąglenia
Teraz, jak jeszcze kodu jest mało to nie ma większej wagi, ale jak się funkcji namnoży, to skracanie rzeczy dziejących się "stale" może mieć znaczenie.
MAc
mrn
PS
mam nadzieję, że się gdzieś nie walnąłem :-)
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 20-10-201420:58
Co racja to racja, mówisz i masz... poprawka w załączeniu
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SP6IFN - 20-10-201422:23
No i właśnie na tym to polega, co dwie głowy to nie jedna. Właśnie czegoś nowego się dowiedziałem.
Rysio!
PS.cytat: mam nadzieję, że się gdzieś nie walnąłem :-)...koniec cyt.
A jednak.......ale po poprawce i tak nie działa, nie rysuje linii....no bo jak ma to zrobić.
Ryszard, chyba dałeś wersję 6 ponownie, bo nie widzę zmian.
PS2. No, teraz chodzi...i kod krótszy.
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 20-10-201422:39
Niewątpliwie ">>" zajmuje mniej czasu procesora ale z drugiej strony póki co się mieścimy a dla celów szkoleniowych czystszy zapis jest lepszy. Więc na razie zostanie.
Jeśli chodzi o map, by inni mieli pojęcie jak działa to jest tak, taki zapis:
Kod:
int out = map(input,0,1023,0,50);
jest równoważny temu:
Kod:
int out = (50 * input) / 1023;
Czyli map realizuje dwie operacje, dodatkowym problemem funkcji map jest obcinanie reszty z tego dzielenia, zamiast zaokrąglania.
Więc wartość 5,9 zostanie pokazana jako 5.
Takich niuansów można znaleźć więcej zachęcam do czytania na ten temat.
Grunt to się dobrze bawić No to teraz czekamy na rozwój sytuacji u kolegów
P.S. Wadliwy plik podmieniony
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SP6IFN - 20-10-201422:49
Tak mi przyszło jeszcze na myśl, że w obecnym zapisie bardzo łatwo można niejako "zmienić czułość miernika". Wystarczy zmienić odpowiednio jedną z liczb w obecnym zapisie.
Rysio!
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SQ9MDD - 20-10-201422:57
Jasne że można, można też doprowadzić sygnał liniowy i przemapować go w krzywej kilku punktowej. Albo zaprojektować krzywą dowolnie dopasowaną do charakterystyki sygnału.
Taki example znalazłem dla czujnika temperatury NTC 10K :
int temp_raw = analogRead(pomiar_temp_input)-238; //odczyt danych z czujnika
int temp = pgm_read_word(&temps[temp_raw]); //kalibracja miernika temp (rezystancyjny 10K)
int a = temp/10;
int b = temp%10;
Serial.print(a);
Serial.print(".");
Serial.print(b);
Posługując się czymś takim można zaprojektować i wpisać w program krzywą konwersji napięcia na skalę na przykład w db.
RE: Fork-Heńka... czyli jak sobie poradzić z DDS za pomocą ARDUINO - SP9MRN - 20-10-201423:35
przemapować do pokazywania to połowa zabawy :-) Można bowiem przemapować i z wyjścia pwm napędzić nim ARW o własnej fikuśnej charakterystyce :-)
(no, ale do tego to naprawdę trzeba szybko).
Rysiek, nie mam teraz ardu podpiętego - mógłbyś zobaczyć czy się coś w ramie w istotny sposób zmienia przy map i shifcie?