Elektroda.pl
Elektroda.pl
X
Mitronik
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

PIC16F876A Algorytm Goertzela nie pracuje.

lukashb 05 Maj 2011 23:28 3746 30
  • #1 05 Maj 2011 23:28
    lukashb
    Poziom 39  

    Witam! Sporo w sieci szukałem n/t tego algorytmu, głównie już gotowych przykładowych kodów, i znalazłem wkońcu prosty program do dekodowania tonów zajętości linii telefonicznej i sygnału dzwonienia czyli 440Hz i 480Hz i 480Hz i 620Hz. Projekt zawiera wszystko co trzeba, plik .h, .c. Kompilator w którym był pisany ów program do CCS PCWHD. Po skompilowaniu i wgraniu hexa do procesora programatorem JDM + WINPIC niechce dekodować tonów. Procesor działa, można zamigać diodą. Chciałbym aby ktoś bardziej biegły w C spojżał na kod i mniej więcej ocenił co może być nie tak i dlaczego. Oto kod:

    Code:

    #include "Goertzel.h"

    // Goertzel.c
    // 5/2005 - E. Kiser
    // The following code performs a sequential Goertzel looking for 3 frequencies of
    // 440-Hz and 480-Hz for a PSTN ringing signal, and 480-Hz and 620-Hz for a PSTN busy signal.

    #use fast_io(A)
    #use fast_io(B)
    #use fast_io(C)

    // The Threshold value shown below was set for an input signal with minimum amplitude
    // of 1 volt and a maximum amplitude of 4 volts centered around 2.5 volts.
    #define  N              80              // Transform bandwidth
    #define  THRESHOLD      10000           // Detector threshold
    #define  BURST          2               // Run-length burst threshold

    #define  LED1           43              // LED 1 on Port A3
    #define  LED2           45              // LED 2 on Port A5

    // Global variables
    static unsigned int     block_ready;
    static unsigned int     freq_select;

    static signed int16     y0;
    static signed int16     y1;
    static signed int16     y2;
    static unsigned int     x0;

    static unsigned int16   timer_reload;
    static unsigned int     sample_cntr;

    void main()
    {
       unsigned int16 cntr;
       static unsigned int16 mag;
       static unsigned int  maxes[10];

       output_a(0x00);
       output_b(0x00);
       output_c(0x10);

       set_tris_a(0x01);                   // setup PORT A as all outputs except AN0
       set_tris_b(0x87);                   // setup PORT B
       set_tris_c(0x00);                   // setup PORT C as all outputs





       setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);   // setup Timer 1 to use 5-MHz clock source

       setup_adc_ports(AN0);
       setup_adc(ADC_CLOCK_INTERNAL);
       set_adc_channel(0);

       enable_interrupts(INT_TIMER1);      // enable Timer 1 interrupts
       enable_interrupts(GLOBAL);

       output_high(LED1);         // turn off LED1
       output_high(LED2);         // turn off LED2
       
       block_ready=0;
       freq_select=0;
       sample_cntr=N;

       while(TRUE)
       {
          if (block_ready)
          {
             disable_interrupts(INT_TIMER1);     // block further interrupts until the block is completely processed

             // Perform the squared magnitude calculation...
             mag=(unsigned int16) (y1*y1) + (y2*y2);
             if (mag > THRESHOLD)
             {
                maxes[freq_select]++;      // if the magnitude is above the treshold, bump the run length counter
                if (maxes[freq_select] > BURST) maxes[freq_select]=BURST;      // apply a ceiling to the Burst counter
             }
             else
             {
                maxes[freq_select]=0;      // if the magnitude is below the threshold, reset the Burst run length counter
             }

             // Check for valid tones below:
             
             // Ringing signal...
             if ( (maxes[0] >= BURST) && (maxes[1] >= BURST) )
                output_low(LED1);    // turn on LED in response to Ringing signal...
             else
                output_high(LED1);   // if no signal, keep LED off

             // Busy signal...
             if ( (maxes[1] >= BURST) && (maxes[2] >= BURST) )
                output_low(LED2);    // turn on LED in response to Busy signal...
             else
                output_high(LED2);   // if no signal, keep LED off

             // Update various variables and prepare to process a new block of samples:
             block_ready=0;

             freq_select++;       // point to the next desired frequency
             if (freq_select >= 3) freq_select=0;   // wrap back around to the first desired frequency

             // The timer reload value is formed by taking the period of 4 times the frequency
             // of interest minus 15 uSec of interrupt routine overhead time.  This period
             // is then divided by the timer clock period (0.5 uSec) to obtain the number of
             // timer ticks.  The final reload value is obtained by subtracting the required
             // number of timer ticks from 0xFFFF.
             if (freq_select == 0) timer_reload=0xF531;      // 440 Hz
             if (freq_select == 1) timer_reload=0xF613;      // 480 Hz
             if (freq_select == 2) timer_reload=0xF869;      // 620 Hz

             y1=0;
             y2=0;
             sample_cntr=N;

             enable_interrupts(INT_TIMER1);      // re-enable background timer interrupts
          }
       }  // end of WHILE(TRUE)
    }

    // Each timer click = .2 uSec.  The timer interrupts on overflow, so subtract the
    // desired cycle time from 0xFFFF.
    // The desired period must have 15uSec subtracted to account for overhead
    #INT_TIMER1
    void sample_timer()
    {
       unsigned int16 adc_data;

       setup_timer_1(T1_DISABLED);
       set_timer1(timer_reload);           // reload timer to start next period
       setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

       adc_data=read_adc(ADC_READ_ONLY);   // get ADC reading

       y0=(adc_data >> 3) - y2;            // subtract out oldest sample from current sample
       // (ADC_DATA is scaled down by 8X to prevent overflow in the magnitude calculation)

       y2=y1;                              // update oldest sample...
       y1=y0;                              // update next to oldest sample...

       sample_cntr--;
       if (sample_cntr == 0)
          block_ready=1;

       read_adc(ADC_START_ONLY);           // start next conversion
    }

    Wydaje się być zrozumiałym. Czytając helpa dotyczącego ADC wydaje mi się, że jest wszystko dobrze skonfigurowane. Proby robiłem podając na AN0 (pin RA0) sygnał z karty muzycznej, potem przerobiłem program by wykrywał jeden ton tylko zamiast dwóch na raz (oryginalna wersja) i podawałem sygnał z generatora, niestety w żadnym z wypadków nie reaguje na tony. MCLR podłączone do + na stałe, bez rezystorów. Oto konfiguracja jaka jest w pliku .h
    Code:

    #include <16F876A.h>
    #device *=16
    #device ICD=TRUE
    #device adc=10
    #fuses NOWDT,HS, NOPUT, NOPROTECT, BROWNOUT, NOLVP, NOCPD, NOWRT, DEBUG
    #use delay(clock=20000000)

    Rezonator oczywiście 20MHz + kondensatory.
    Oto konfiguracja w Winpic:
    PIC16F876A Algorytm Goertzela nie pracuje.
    Wydaje się być poprawna.
    Hex załadowany do procesora, po zczytaniu i zapisaniu jest taki sam jak ten wgrywany - zapisuje i programuje w porządku jak pisałem. Proszę o pomoc bądź wskazówkę. Pozdrawiam

    0 29
  • Mitronik
  • Pomocny post
    #2 06 Maj 2011 10:50
    94075
    Użytkownik usunął konto  
  • #3 06 Maj 2011 12:52
    lukashb
    Poziom 39  

    Witam! Dzięki za odpowiedź. Wszystkie komentarze są autora, ale jeżeli mówisz, że prawdopodobnie chodzi na 8MHz to sprawdzę to. Dziwne jest jednak, że w pliku .H jest zadeklarowana częstotliwość 20MHz ( #use delay(clock=20000000) ). No nic, dziś potestuje choć przyznam, że o algorytmie Goertzela nie wiele w sieci na temat tego jak pisać itp, tylko pobieżne wskazówki. Głównie interesuje mnie parametr

    Code:

    #define  THRESHOLD      10000           // Detector threshold

    on mówi o wartości napięcia progowego. Skąd zatem autor wziął 1V minimum, 4 maksimum a amplituda 2,5V to napięcie "środkowe"? jak narazie mamy wartość 10000 która za bardzo nic mi nie mówi, a w sieci nie specjalnie mam coś na ten temat. Dzięki za pomoc. Pozdrawiam

    0
  • Mitronik
  • Pomocny post
    #4 06 Maj 2011 13:47
    94075
    Użytkownik usunął konto  
  • #5 06 Maj 2011 17:57
    lukashb
    Poziom 39  

    Wpadłem na pomysł, by sprawdzić czy przerwanie int_timer1 się uruchamia w ten sposób, że gdy jest w tej procedurze to zapala diodę. Niestety, dioda się nie zapala, chociaż jest wcześniej zapis

    Code:

    enable_interrupts(INT_TIMER1);      // enable Timer 1 interrupts
       enable_interrupts(GLOBAL);

    Przecież ten podprogram z ADC powinien "biegać" ciągle i tylko zatrzymywać się na czas wejścia do procedury sprawdzającej na If'ach czy się ton zgadza i przy wyjściu znów mamy odblokowanie powrót do procedury i tak w koło itp. Ciężki temat. Czy przypadkiem tu nie trzeba jeszcze jakoś "aktywować" ADC? odznaczyć jakiś haczyk bądź coś podobnego? tak jak np. w Atmedze32 by używać PORTC.x trzeba odhaczyć najpierw JTAG-a i być może coś tu jest. Nie znam PICów, moja przygoda z nimi trwa 3 dni, i moja lektura to forum CCS'a ale tam wszystko wszystkim pięknie działa z ADC a procedury wywołania tego są takie same. Trzeba by jakoś sprawdzić jak pisałeś co daje z siebie ADC ale sądzę, że nic. Mój pomysł to wysłanie zmiennej adc_data na RS232 i obejżenie co on wypluwa. Chyba, że jest jakiś prostszy sposób? bo znając życie zanim uruchomię RS232 to wieki zejdą ;) Dzięki za pomoc.

    Dodano po 1 [godziny] 4 [minuty]:

    Uruchomiłem RS232, podpinając adc_read pod funkcję wysyłającą nic mi nie wysyła. Wniosek jeden jak wyżej, nie startuje ADC, gdzieś program "staje" no bo nie widzę innej przyczyny. :cry:

    0
  • Pomocny post
    #6 06 Maj 2011 19:04
    94075
    Użytkownik usunął konto  
  • #7 07 Maj 2011 16:31
    lukashb
    Poziom 39  

    Witam! Po długich bojach wkońcu działa. Przyczyna? prozaiczna. W programatorze nie odhaczona opcja DEBUG. Aktualnie działa wszystko pięknie lecz mam mały problem z prędkością dekodowania. Mianowicie potrzeba mu ok. 100-200ms na zdekodowanie, moje pytanie jest następujące, jak podnieść tu częstotliwość próbkowania? zapewne jest trochę zamała i stąd ten efekt? Pozdrawiam

    0
  • Pomocny post
    #8 07 Maj 2011 23:29
    94075
    Użytkownik usunął konto  
  • #9 07 Maj 2011 23:48
    lukashb
    Poziom 39  

    Witam! Dzięki za kontynuację tematu.

    Cytat:

    -Jaki czas potrzebujesz?

    Będę chciał dekodować tony o czasach od 20ms do 100ms maksymalnie. Trochę niska granica, ale tak się złożyło.

    Cytat:

    -Czy wszystkie trzy częstotliwości są Ci potrzebne?
    -Czy będziesz później chciał ich mieć więcej?
    -Czy możesz sobie pozwolić na mniejszą precyzję łapania częstotliwości?

    Te trzy wypadają z obiegu, w ich miejsce wskakują inne. Będzie ich 11. Oddalone od siebie o ok. 80-100Hz każda. Pytanie tylko jak przelicza się wyniki z timera by odnaleźć właściwe częstotliwości? To nie takie proste bo nie wiemy zabardzo co autor w pewnych miejscach miał na myśli. np. 440Hz to wartość 0xF531 czyli 62769. Pewnie jakiś prosty myk autor znalazł na wartość timera i częstotliwość. Narazie tyle, jutro działam dalej. Pozdrawiam i dobrej nocy życzę.

    0
  • #10 07 Maj 2011 23:59
    94075
    Użytkownik usunął konto  
  • #11 08 Maj 2011 13:04
    lukashb
    Poziom 39  

    Witam!
    No fakt, jest ewidentnie. Ale coś mi nie chce wyjść za bardzo to liczenie.

    Cytat:

    The timer reload value is formed by taking the period of 4 times the frequency
    // of interest minus 15 uSec of interrupt routine overhead time. This period
    // is then divided by the timer clock period (0.5 uSec) to obtain the number of
    // timer ticks. The final reload value is obtained by subtracting the required

    Liczę okres z interesującej częstotliwości, odejmuję 15uS, to co wychodzi dzielę przez 0,5uS i to co wyjdzie mam odjąć od 65525 dla uzyskania wartości reload? zapewne tak jest. Lecz jak pisałem, nie specjalnie coś mi się to zgadza. Zatem policzmy dla 440Hz by sprawdzić czy wyjdzie 0xF531.
    Wzór na okres:
    T=1/F
    Liczymy.

    T=1/440=0,00227272727 sekundy.

    Odejmujemy 15uS
    0,00227272727 sek - 0,000015 sek = 0,00225772727 sek

    Dzielimy poprzez 0,5uS ( 5.0e-7)
    0,00225772727 sek / 5.0e-7 = 4515.45454

    A zatem odejmując od 65535 wartość 4515 wychodzi nam 61020 a nie jak autor zakładał 62769. W takim razie gdzie popełniam błąd? Czy coś przeoczyłem? czy "period 4 times of frequency" mam rozumieć jako to, że jest łapane 4 okresy częstotliwości? czy może mam wymnożyć coś przez 4? bo w pewnym momencie już się pogubiłem :( Pozdrawiam i dzięki.

    0
  • #12 08 Maj 2011 13:16
    94075
    Użytkownik usunął konto  
  • #13 08 Maj 2011 16:15
    lukashb
    Poziom 39  

    Ok, dzięki. Policzyłem sobie już tony. Ale jest problem z rozdzielczością (bandwidth?) ponieważ drugi ton reaguje na 1 jak i na 3, 3 ton na 2 i na 4 itp. Poprostu zbyt szeroko łapie dekoder. Chciałbym uzyskać ±30Hz od częstotliwości środkowej - czyli mojego tonu. Czy jest to do uzyskania? napewno jest, tylko kwestia kolejnych obliczeń i zmiany być może N jak i Bandwidth. Pozdrawiam i dzięki za cierpliwość.

    0
  • #14 10 Maj 2011 14:02
    lukashb
    Poziom 39  

    Witam!
    -> albertb, przepraszam, że zawracam Ci głowę, ale damy radę coś zmienić przy tym algorytmie? Jak się ustawi by było pasmo zawężone czyli bardziej dokładny pomiar, to wtedy pomiar trrwa długo ok. 200-300ms, jak się zrobi, że jest szybki to wtedy i owszem jest bardzo dobrze, bo już działa od ok. 10ms ale dokładność jest taka, że dla np. 1000Hz dekoduje się już od ± 300Hz co jest nie dopuszczalne. Moje pytanie, czy jest możlwość zmiany częstotliwości próbkowania i ew. przeliczenia nowych wyników? Bo chyba bez tego się nie obędzie. Pozdrawiam i proszę o pomoc.

    0
  • #15 10 Maj 2011 19:34
    94075
    Użytkownik usunął konto  
  • #16 10 Maj 2011 21:47
    lukashb
    Poziom 39  

    Dzięki za odzew. To fakt, podstawy są już dość rozbudowane. To swoista szkoła jazdy zwłaszcza, że C znałem tylko z nazwy, a tak to Pascal/BASCOM. Ale do rzeczy. Przeanalizowałem fragmenty i to fakt, autor wywalił całkowicie liczenie Coeffs upraszczając na maksa procedurę. Wprowadziłem pewne zmiany ale to tak pobieżnie. Oto co zrobiłem.

    Code:

    y0=coeffs * y1 - y2 + adc_data;
    y2=y1;                             
    y1=y0;

    Wiadomo, trzeba przedtem policzyć współczynnik Coeffs. Mam w związku z tym pytanie, czytając opis na Wikipedii co podałeś widzimy
    Code:

    coeff = 2*cos(2*PI*normalized_frequency);

    Rozumiem z tego, że "normalized_frequency" jest to moja poszukiwana usilnie częstotliwość próbkowania? jak tak to zapisałem to tak:
    Code:

    coeffs = 2*cos(2*pi*8000);

    Zdefiniowałem sobie oczywiście wcześniej Coeffs na zmienną double, pi jako 3.141592654 by nie zaciemniać kodu liczbami. Aktualnie pewnie trzeba poprawić ten fragment o ile się nie mylę
    Code:

    mag=(unsigned int16) (y1*y1) + (y2*y2);

    zgodnie z tym:
    Code:

    power = s_prev2*s_prev2 + s_prev*s_prev - coeff*s_prev*s_prev2;

    czyli:
    Code:

    mag=(unsigned int16) (y1*y1) + (y2*y2) - coeffs * y1*y2 ;

    Tylko wydaje mi się, że liczenie Coeffs z początku postu muszę wywalić z procedury przerwania a stworzyć kolejną i w pętli głównej zaraz po nawiasie Void main() { wywołać ją? zweryfikuj moje słowa, a ja kończę pisać (być może) błędnie rozumowane zagadnienie ;). Pozdrawiam

    Dodano po 13 [minuty]:

    Dodano
    Zmieniłem wszystko tak jak pisałem wyżej, program się kompiluje, ale wywala warningi:
    PIC16F876A Algorytm Goertzela nie pracuje.
    Czytałem, że to chodzi o math.h który muszę już używać i o przerwanie. Używam wiadomo do czego do liczenia Cosinusa w Coeffs, a ten jest używany w przerwaniu i liczeniu y0. Tylko nic nie mogę znaleść czy to przeszkodzi w pracy czy też nie? :?: :idea:

    0
  • #17 10 Maj 2011 23:19
    94075
    Użytkownik usunął konto  
  • #18 11 Maj 2011 12:29
    lukashb
    Poziom 39  

    Witam! Dzięki za odpowiedź. Dziś trochę przeglądałem sieć względem Goertzela i DTMF bo tego jest trochę więcej niż dla pojedyńczych tonów. Tam jest liczona Coeff dla każdego z tonu zgodnie z tym:

    Code:

    k=N x (Ftone/Fsample)

    Następnie w samym coeff jest to liczone tak:
    Code:

    coeff=2cos(2*PI*k/N).

    Wynika z tego, że nie wystarczy obliczyć raz coeff (chyba, że dla jednego tonu tylko) ale w pętli trzeba przeliczać dla każdego pokolei. Jednak nie zabardzo wiem, jak się odwołać do tonów co by po kolei podstawiał tony z freq_select(x). Najpewniej trzeba pętlę for. Czy mógłbyś mi pomóc tutaj lekko z tym? chodzi mi o już nie wielką przeróbkę tego względem tej pętli. Byłbym zobowiązany. Pozdrawiam

    0
  • #19 11 Maj 2011 12:35
    94075
    Użytkownik usunął konto  
  • #20 11 Maj 2011 14:47
    lukashb
    Poziom 39  

    Ok, to już coś wiem. Aktualnie przerobiłem podprogram od przerwania troszkę, wygląda tak:

    Code:

    void sample_timer()
    {
       unsigned int16 adc_data;
       unsigned int k;
       setup_timer_1(T1_DISABLED);
       set_timer1(timer_reload);           // reload timer to start next period
       setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

    k=N*(1124 / 8000);
    coeffs = 2*cos(2*pi*(k/N));
       adc_data=read_adc(ADC_READ_ONLY);   // get ADC reading
       y0=coeffs * y1 - y2 + adc_data;
       y2=y1;                              // update oldest sample...
       y1=y0;                              // update next to oldest sample...

       sample_cntr--;
       if (sample_cntr == 0)
          block_ready=1;

       read_adc(ADC_START_ONLY);           // start next conversion
    }

    teraz powinno wszystko (?) teoretycznie działać dla jednego tonu który wpisałem - 1124Hz. Pytanie, jak teraz sprawdzać czy dany ton się zgadza. Inaczej mówiąc, czy trzeba wszystko na nowo przeliczyć (jak narazie dla jednego tylko dla sprawdzenia) czy jest jak ma być? mówię o fragmencie:
    Code:

     if (freq_select == 0) timer_reload=0xFDD4;
            if (freq_select == 1) timer_reload=0xFBF2;     
            if (freq_select == 2) timer_reload=0xFC36;     
            if (freq_select == 3) timer_reload=0xFC76;     
            if (freq_select == 4) timer_reload=0xFCB2;     
            if (freq_select == 5) timer_reload=0xFCEA;     
            if (freq_select == 6) timer_reload=0xFD1F;
            if (freq_select == 7) timer_reload=0xFD50;     
            if (freq_select == 8) timer_reload=0xFD7F;     
            if (freq_select == 9) timer_reload=0xFDAA;
            if (freq_select == 10) timer_reload=0xFDFA;       // 620 Hz

    Ew. może całkowicie inaczej teraz się będzie sprawdzać czy ton się zgadza czy nie :?: Pozdrawiam

    0
  • #21 12 Maj 2011 07:26
    94075
    Użytkownik usunął konto  
  • #22 12 Maj 2011 21:36
    lukashb
    Poziom 39  

    Witaj! Już rozumiem!, chodzi o wyliczenie dla każdej z moich częstotliwości osobnych Y i Coeff, przyznam, że trochę mi wstyd, bo to teraz wydaje się oczywiste. Dziś kolejny dzień studiowania żródeł z innych stron i jak narazie program otrzymał:

    Code:

    #define  N              205 
    #define  MAX_BINS       11
    #DEFINE SAMPLING        8000

    To wiadomo ;). Następnie dałem tablicę z tonami:
    Code:

    const double freqs[MAX_BINS] = { 1124,1197,1275,1358,1446,1540,1640,1747,1860,1981,2110 }; //NASZE TONY

    Tu akurat zaczerpnąłem pomysł z innego źródła.
    W przerwaniu ADC mam takie coś:
    Code:


    #INT_TIMER1
    void sample_timer()
    {
       unsigned int16 adc_data;
       unsigned int k;
       unsigned int X;
       unsigned int I;
     
     
      setup_timer_1(T1_DISABLED);
       set_timer1(timer_reload);           // reload timer to start next period
       setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
       adc_data=read_adc(ADC_READ_ONLY); 
       
       
    for(X = 0; X < MAX_BINS; X++)
    {
    k=N*(FREQS[X]/SAMPLING);
    coeffs = 2*cos(2*pi*(k/N));
    }

    for ( i = 0; i < MAX_BINS; i++ )
                {
                   Y0 = *coeffS[i] * y1[i] - y2[i] + adc_data;
                   y2[i] = y1[i];
                   y1[i] = Y0;
                }
     // sample_cntr--;
      //if (sample_cntr == 0)
     // block_ready=1;

       read_adc(ADC_START_ONLY);     
    }

    Jest tam obliczane y i coeffs. Czy tak jest w miarę poprawnie?
    Zmienna coeffs jest pointer, inaczej program nie chciał się skompilować - rozumiem, że to nie robi problemów prócz tego, że trzeba dodać gwiazdkę wcześniej? Jak pisałem w C jestem świeży ale bardzo mi się podoba! :)

    0
  • #23 13 Maj 2011 00:04
    94075
    Użytkownik usunął konto  
  • #24 14 Maj 2011 15:53
    lukashb
    Poziom 39  

    Cytat:
    Idea OK, nad realizacją musisz popracować.
    1. Tak samo jak freqs możesz stablicować coefs, zamiast liczyć z każdym razem.
    Zgadza się, można to wyliczyć ręcznie i zapisać w tablicy jako stała - wtedy pozbędę się modułu math.h który jest specjalnie dla cosinusa. Ale to sprawa drugorzędna.
    Cytat:

    2. Czemu zakomentowałeś dekrementację sample_cntr ?

    Zakomentowałem ją narazie bowiem w pętli głównej main() i tak wszystko zostanie wyrzucone i zmienione. Chyba, że zostawić tak wszystko jak leciało a dodać tylko pętlę do magnitudy i reszta bez zmian?
    Cytat:

    3. Gdzieś niestety trzeba uwzględnić te 15us z orginału - zastanów się skąd się ono bierze.

    Właśnie nie wiem skąd ono się bierze zabardzo. Najpewniej bierze się z właściwości pracy samego timera i stąd potrzeba odjęcia tych 15uS od zakładanego okresu sygnału. Ale to tylko przypuszczenia.

    Dodano po 4 [godziny] 57 [minuty]:

    Właśnie dopiero teraz mogłem sklecić całość do siebie i o to co powstało. Prosiłbym o komentaż z Twojej strony i ew. podpowiedź i odpowiedź na pytanie:
    1. Czy trzeba przeliczać raz jeszcze wartości timer_reload? o ile w ogóle je trzeba przeliczać bo może jest jakiś inny sposób odwołania się do konkretnych tonów? ja widziałem także porównanie, jak magnituda[x] większa od poziomu progu to wtedy wykonaj program itp. Może tu także trzeba tak zrobić? czyli kolejna pętla for i porównywanie do treshold ?
    To by było tyle. Teraz cały kod.
    Code:

    #include "Goertzel.h"
    #include <math.h>
    // Goertzel.c


    #use fast_io(A)
    #use fast_io(B)
    #use fast_io(C)


               
    #define  THRESHOLD     5000         
    #define  BURST          2   


    #define  N              205 
    #define  MAX_BINS       11
    #DEFINE SAMPLING        8000

    #define  LED1           43              // LED 1 on Port A3
    #define  LED2           45              // LED 2 on Port A5

    static unsigned int     block_ready;
    static unsigned int     freq_select;

    const double freqs[MAX_BINS] = { 1124,1197,1275,1358,1446,1540,1640,1747,1860,1981,2110 }; //NASZE TONY
    static signed int16     y0;
    static signed int16     y1[MAX_BINS];
    static signed int16     y2[MAX_BINS];


    static unsigned int16   timer_reload;
    static unsigned int     sample_cntr;
    static double *coeffs;

    void main()
    {
      unsigned int16 z;
      static unsigned int16 *mag;
      static unsigned int  maxes[11];
         

       output_a(0x00);
       output_b(0x00);
       output_c(0x10);

       set_tris_a(0x01);                   // setup PORT A as all outputs except AN0
       set_tris_b(0x87);                   // setup PORT B
       set_tris_c(0x00);                   // setup PORT C as all outputs

       setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);   // setup Timer 1 to use 5-MHz clock source

       setup_adc_ports(AN0);
       setup_adc(ADC_CLOCK_INTERNAL);
       set_adc_channel(0);

       enable_interrupts(INT_TIMER1);      // enable Timer 1 interrupts
       enable_interrupts(GLOBAL);

       output_high(LED1);         // turn off LED1
       output_high(LED2);         // turn off LED2
       
       block_ready=0;
       freq_select=0;
       sample_cntr=N;
       
       while(TRUE)
       {
          if (block_ready)
          {
             disable_interrupts(INT_TIMER1);   
         
              for ( z=0; z<MAX_BINS; z++ )
             {
                *mag[z] =(unsigned int16) (y1[z] * y1[z]) + (y2[z] * y2[z]) - (*coeffs[z] * y1[z] * y2[z]); // PĘTLA DO OBLICZANIA MAG DLA RÓŻNYCH TONÓW
             }
           
            if (mag > THRESHOLD)
             {
                maxes[freq_select]++;   
                if (maxes[freq_select] > BURST) maxes[freq_select]=BURST;   
             }
             else
             {
                maxes[freq_select]=0;     
             }

                                          // \
             if  (maxes[1] >= BURST)     //  |
                output_low(LED1);        //  |
             else                        //  |
                output_high(LED1);        // |
                                          // | PEWNIE TRZEBA POPRAWIĆ.
                                          // |
             if (maxes[2] >= BURST)       // |
                output_low(LED2);         // |
             else                         // |
                output_high(LED2);        // |
                                          // /
           
             block_ready=0;

             freq_select++;     
             if (freq_select >= 11) freq_select=0;   

            if (freq_select == 0) timer_reload=0xFDD4;
            if (freq_select == 1) timer_reload=0xFBF2;     
            if (freq_select == 2) timer_reload=0xFC36;     
            if (freq_select == 3) timer_reload=0xFC76;     
            if (freq_select == 4) timer_reload=0xFCB2;      //JAK WYŻEJ. PEWNIE CAŁOŚĆ DO PRZELICZENIA, O ILE IDEA DALEJ TAKA SAMA.
            if (freq_select == 5) timer_reload=0xFCEA;     
            if (freq_select == 6) timer_reload=0xFD1F;
            if (freq_select == 7) timer_reload=0xFD50;     
            if (freq_select == 8) timer_reload=0xFD7F;     
            if (freq_select == 9) timer_reload=0xFDAA;
            if (freq_select == 10) timer_reload=0xFDFA;     
             
             for ( z = 0; z < MAX_BINS; z++ )
                {
                   
                   y2[z] = y1[z]=0;                       //PĘTLA DO ZEROWANIA SKŁADNIKÓW Y1 I Y2
                 
                }
             
             
             sample_cntr=N;
           
       
             enable_interrupts(INT_TIMER1);   
          }
       } 
    }

    #INT_TIMER1
    void sample_timer()
    {
       unsigned int16 adc_data;
       unsigned int k;
       unsigned int X;
       unsigned int I;
     
     
      setup_timer_1(T1_DISABLED);
       set_timer1(timer_reload);           
       setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
       adc_data=read_adc(ADC_READ_ONLY); 
       
       
    for(X = 0; X < MAX_BINS; X++)
    {
    k=N*(FREQS[X]/SAMPLING);
    coeffs = 2*cos(2*pi*(k/N));
    }

    for ( i = 0; i < MAX_BINS; i++ )
     {
     Y0 = *coeffS[i] * y1[i] - y2[i] + adc_data;
     y2[i] = y1[i];
     y1[i] = Y0;
     }
     sample_cntr--;
     if (sample_cntr == 0)
     
    block_ready=1;
       read_adc(ADC_START_ONLY);     
    }

    Oto efekt mojej pracy, trochę zaczerpnąłem pomysłu w innych źródłach - wydaje się być poprawne. Dzięki za pomoc i pozdrawiam

    0
  • #25 14 Maj 2011 18:02
    94075
    Użytkownik usunął konto  
  • #26 14 Maj 2011 22:02
    lukashb
    Poziom 39  

    No tak z tym Sample_center już jest jasne. Wynosi ono tyle ile N - zadeklarowane na początku programu. Z każdym przejściem pętli jest zmniejszana aż do 0, jak jest 0 to wtedy skok do głównej pętli i liczymy magnitude na podstawie policzonych wcześniej współczynników. Teraz wracając do timer_reload, jak to z tym ma być? ile ma wynosić aktualnie? Czy może poprostu tego nie dotykać? Jak sprawdzać dany ton to tak jak pisałem już, magnituda w funkcji każdego max_bins większa od poziomu progowego. Aktualnie stoję nad tym timerem, jaką wartość mu potrzeba załadować na start itp. Przyznam, że dużo już przeszedłem, bo i tak mnie poprowadziłeś elegancko, ale tu się wykładam :(. Jesteśmy na finiszu jak by nie było. Dzięki i pozdrawiam Łukasz :)

    0
  • #27 15 Maj 2011 11:48
    94075
    Użytkownik usunął konto  
  • #29 15 Maj 2011 22:26
    94075
    Użytkownik usunął konto  
  • #30 16 Maj 2011 14:07
    lukashb
    Poziom 39  

    No cóż. Wydaje się, że sam procesor jest w stanie próbkować tak szybko jak tylko może /f rezonatora/, a jak nam zależy na określonej częstotliwości to używamy timera i ładujemy do niego pewną wartość. Potem następuje inkrementacja od 0x0000 do tej wartości której chcemy i wartość zerujemy i znów od początku - od wielkości tej liczby zależy ile to przerwanie będzie się wykonywać - czas potrzebny do osiągnięcia rządanej zmiennej. Tak ja to widzę. Najpewniej tak to wygląda. Pozdrawiam

    0