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

[ATmega8][C] Pobieranie napięcia przez przetwornik A/C

InkER_o 10 Gru 2008 21:24 1460 15
  • #1 10 Gru 2008 21:24
    InkER_o
    Poziom 11  

    Witam,
    czy pomógłby mi ktoś pomóc analizując poniższy program? Chcę aby dokonywał się odczyt napięcia z termopary. Niestety tak się nie dzieje. Przedstawiam w kodzie inicjalizację przetwornika, funkcję która ma odbywać się podczas przerwania oraz FRAGMENT int main().

    Code:

    ISR(TIMER0_OVF_vect)
    {
      uint16_t x,y;

      napiecie = ADCH;         // czytaj wartość z przetwornika ADC
      x=napiecie;                //przypisz odczyt. wart. do x
      y=(-0.057*(x^2) + 25.542*x -3.479)/100+25;//rownanie wyznaczajace charakterystyke
      temp_o=y;   //wartosc obliczona temperatury 
      LCD_Home();
      LCD_putstr_P(itoa(temp_o, temp,10));
    }

    void ADC_init(void)
    {
       ADMUX = 0;       // kanał 0 przetwornika ADC
       ADMUX |= _BV(REFS0);           // wybor zrodla napiecia
       ADMUX |= _BV(REFS1);             //          odniesienia
       ADMUX |= _BV(ADLAR);   // 8starszych bitów wyniku w rejestrze ADCH)
       ADCSRA = _BV(ADEN)|_BV(ADIE)|_BV(ADFR)|_BV(ADSC)|_BV(ADPS2)|_BV(ADPS1);
                          // włącz przetwornik ADC w trybie samobieżnym - ADEN
                          // uruchom generowanie przerwań, zezwolenie - ADIE
                          // częstotilwość taktowania F_ADC=F_CPU/64
                          // przy F_CPU=8MHz : F_ADC=125 kHz
    }

    void StartADC(void)
    {
    ADCSRA |= _BV(ADSC); // rozpoczecie przetwarzania
    while((ADCSRA & _BV(ADIF))==0) //(bit_is_set (ADCSRA,ADSC)) // Oczekiwanie na zakonczenie przetwarzania
    {};
    ADCSRA |= _BV(ADIF);
    ADCSRA &= ~_BV(ADSC);
    sei();
    }

    int main(void)
    {
    .
    .
    .
    ADC_init();      //inicjalizacja przetwornika

    do
    {
    .
    .
    .
    sei();
    StartADC();
    .

    }while(1);
    }



    Proszę administratorów o nie przenoszenie mojej wiadomości do kosza, jeżeli temat podobny już był. Próbowałam znaleźć posty o podobnej treści niestety po paru minutach wysiłków straciłam cierpliwość. Błąd ogólny
    Cytat:
    Could not obtain search results
    DEBUG MODE
    SQL Error : 2013 Lost connection to MySQL server during query

    pojawiający się po wciśnięciu "Szukaj" potrafi wyprowadzić z równowagi. Za wszelką pomoc z góry dziękuję.

    Skorygowałem tytuł - tagi.
    [zumek]

    0 15
  • #2 10 Gru 2008 21:46
    Freddie Chopin
    Specjalista - Mikrokontrolery
  • #3 10 Gru 2008 21:58
    kasaidolar
    Poziom 19  

    Chaos. Nie rozumiem tego programu - dlaczego w petli robisz pomiar adc a w przerwaniu od timera to odczytujesz? Napisz konkretnie co chcesz uzyskac. I w czym jest problem. Napisanie ze chcesz zrobic pomiar napiecia z termopary i ze nie dziala moze również swiadczyc ze nie masz zasilania procka ;)
    Napisz konkretnie co i jak.

    0
  • #4 10 Gru 2008 22:01
    InkER_o
    Poziom 11  

    Zatem zmienić na

    Code:
    SIGNAL(SIG_ADC){ }
    :?:
    Czytałam, że makro ISR(TIMER0_OVF_vect){} definiuje się w nowszych wersjach bibliotek. To jest odpowiednik makra SIGNAL.
    Czy w dalszym kodzie jest wszystko w porządku? Niestety nie uzyskuję wyniku pomiaru po zmianie.
    Wybaczcie, jestem początkująca.

    0
  • #5 10 Gru 2008 22:14
    Freddie Chopin
    Specjalista - Mikrokontrolery

    nie ISR na SIGNAL, tylko obslugujesz przerwanie TIMER0_OVF_vect - zgodnie z nazwa - przepelnienie timera 0...

    4\/3!!

    0
  • #6 10 Gru 2008 22:19
    kasaidolar
    Poziom 19  

    InkER-o - co chcesz uzyskac - co dokładnie program ma robic? Rozumiem ze ma mierzyc napiecie ale 8 bitow czy 10 bitow? Co jaki czas? Co program ma jeszcze robic? Chcesz zeby przetwornik robil przerwanie? Po co?
    Poniżej kilka przydatnych i działających funkcji:

    Code:

    void ADC_init(void)
    {
       
    // Wybranie wewnętrznego żródła napięcia odniesienia   
       ADMUX |= _BV(REFS0);      
       ADMUX |= _BV(REFS1);
    //   Wybranie sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)
       //ADMUX |= _BV(ADLAR); // To jest jak jest wyrowanie do lewej a jak tego nie ma to do prawej (ADCH i ADCL)      
    // Zezwolenie na konwersję   
       ADCSRA |= _BV(ADEN);      
    // Wybranie częstotliwości dla taktowania przetwornika  (1/8 częstotliwosci zegara kontrolera)
       ADCSRA |= _BV(ADPS0);    
       ADCSRA |= _BV(ADPS1);      
       
    }


    Code:

    void Pomiar(void)
    {   
          char ADC_L, ADC_H;
    ADCSRA|= _BV(ADSC);          //start pojedynczej konwersji
                while(bit_is_set(ADCSRA,ADSC)){};   
                ADC_L = ADCL;
                ADC_H = ADCH;
    }


    rozumiem ze ustawilas odpowiednio porty?

    0
  • #7 10 Gru 2008 22:36
    InkER_o
    Poziom 11  

    Ok, już rozumiem. Przyznaję, że zmodyfikowałam książkowe ISR(TIM0_OVF_vect){} na ISR(TIMER0_OVF_vect){}. Dlatego, że kompilator nie wiedział co to jest TIM0. Korzystam z gotowego pliku konfiguracyjnego do ATmegi: iom8.h i tam jest TIMER0 a nie TIM0. Nie wiem czy głupotę zrobiłam. A co tam możecie się śmiać:|

    Działanie programu:
    Robię coś w rodzaju termostatu. Chcę otrzymać na przetworniku napięcie, które będzie zamieniane na temperaturę, a temperatura wyświetlana na LCD. Napięcie ma być pobierane z termopary poprzez układ wzmacniający do portu ADC0. Wartość temperatury ma być co chwila odświeżana, czy tego nie robi się na przerwaniach..?
    Wszystkie porty są ustawione. Korzystam z programu symulacyjnego ISIS Professional. Tam tworząc schemat elegancko można wprowadzić plik .hex, zobaczyć czy porty są ustawione (stan 0 czy 1) oraz sprawdzić poprawność programu - jak na rzeczywistym urządzeniu. Oprócz tego program ma obsługiwać klawiaturę, ale to już mam opanowane.

    0
  • #8 10 Gru 2008 22:45
    Freddie Chopin
    Specjalista - Mikrokontrolery

    no robi sie to w przerwaniach, ale w odpowiednich... ty masz odczyt itp. w przerwaniu od timera, ktory nie wiadomo czy w ogole odpalasz. na pewno zas aktywujesz przerwanie od ADC, za to nigdzie nie widac funkcji obslugi tego przerwania.

    wniiosek:
    wystapienie tego przerwania konczy sie natychmiastowym resetem ukladu.

    P.S. nie dolacza sie naglowkow konkretnych ukladow - wystarczy dolaczyc io.h - on sam wybierze uklad i dolaczy co trzeba.

    4\/3!!

    0
  • #9 10 Gru 2008 22:54
    kasaidolar
    Poziom 19  

    Ok no to ja juz mniej wiecej rozumiem. Nie rozumiem troche o co chodzi Ci z tym Timerem - po co w ogole go uzywasz skoro nie odpalasz timera a odpalasz przerwanie od ADC - to jest zagadka.
    Najprosciej jest to zrobic tak:

    Code:

    #include <avr/io.h>
    #include <util/delay.h>

    void main (void)
    {
    char ADC_L, ADC_H;
    int ADC_pomiar;

       DDRC = 0x00;      // ustawienie portu na wejsciowy   
       PORTC= 0x00;

    // === USTAWIENIE ADC - inicjalizacja ===

    // Wybranie wewnętrznego żródła napięcia odniesienia   
       ADMUX |= _BV(REFS0);      
       ADMUX |= _BV(REFS1);
    //   Wybranie sposobu zapisu wyniku z wyrównaniem do lewej (osiem starszych bitów wyniku w rejestrze ADCH)
       //ADMUX |= _BV(ADLAR); // To jest jak jest wyrowanie do lewej a jak tego nie ma to do prawej (ADCH i ADCL)      
    // Zezwolenie na konwersję   
       ADCSRA |= _BV(ADEN);      
    // Wybranie częstotliwości dla taktowania przetwornika  (1/8 częstotliwosci zegara kontrolera)
       ADCSRA |= _BV(ADPS0);    
       ADCSRA |= _BV(ADPS1);


    while(1)
    {
    // === start ADC ===

             ADCSRA|= _BV(ADSC);          //start pojedynczej konwersji
                while(bit_is_set(ADCSRA,ADSC)){};   
                ADC_L = ADCL;
                ADC_H = ADCH;

    ADC_pomiar = ADC_H*255+ADC_L; // tu masz dana z adc 10 bitowa z ktora mozesz robic sobie co chcesz




    }
    }




    A ze tak zapytam jesli chodzi o Twoj program... to co wedlug Ciebie jest w zmiennej napiecie - chodzi mi o ten fragmet:
    Code:
      napiecie = ADCH;         // czytaj wartość z przetwornika ADC
    
      x=napiecie;                //przypisz odczyt. wart. do x
      y=(-0.057*(x^2) + 25.542*x -3.479)/100+25;//rownanie wyznaczajace charakterystyke
      temp_o=y;   //wartosc obliczona temperatury
      LCD_Home();
      LCD_putstr_P(itoa(temp_o, temp,10));


    bierzesz pod uwage napiecie referencyjne itd?

    0
  • #10 10 Gru 2008 23:06
    Freddie Chopin
    Specjalista - Mikrokontrolery
  • #11 10 Gru 2008 23:17
    snow
    Poziom 28  

    Cytat:
    ADC_pomiar = ADC_H*255+ADC_L;


    Prościej to:

    Code:
    ADC_pomiar=ADCW;

    0
  • #12 10 Gru 2008 23:24
    InkER_o
    Poziom 11  

    No edukacyjna, edukacyjna! :D Jednak porównuję ze swoim nie kopiując na ślepo. Ale dalej drążę temat jako kobieta.. wiadomo, wolniej łapiąca, itd. Ale to miło, że koledzy wyrozumiali:) Koniec wazeliniarstwa, pytanie brzmi: Żeby odczepić się od tego Timera, czy wystarczy na miejsce ISR(..){} wcisnąć SIGNAL(..){}?? czy w ogóle nie zapisywać tego w przerwaniu tylko wzorować się na przykładzie kolegi :arrow: kasaidolar.
    W zmiennej napięcie jest ustawione 8 starszych bitów wyniku. Chociaż może by lepiej ustawić tam całe ADC? Napięcie odniesienia jest ustawione jako stany wysokie w rejestrach REFS0 i REFS1 (jak w kodzie w pierwszym poście).

    0
  • #13 10 Gru 2008 23:37
    zumek
    Poziom 39  

    InkER_o w kodzie napisał:

    y=(-0.057*(x^2) + 25.542*x -3.479)/100+25;//rownanie wyznaczajace charakterystyke

    Bardzo mnie zaciekawił - zaznaczony na niebiesko - fragment powyższego wzoru :P
    Dlaczego negowany jest bit nr. 1, w zmiennej x :?:
    Bardziej by mi pasowało potęgowanie, choć głowy nie dam :|
    Piotrek

    0
  • #14 10 Gru 2008 23:41
    InkER_o
    Poziom 11  

    Wg mnie to jest potęgowanie, mylę się?
    Negacja to ~.

    0
  • #15 10 Gru 2008 23:44
    Freddie Chopin
    Specjalista - Mikrokontrolery

    InkER_o napisał:
    Koniec wazeliniarstwa, pytanie brzmi: Żeby odczepić się od tego Timera, czy wystarczy na miejsce ISR(..){} wcisnąć SIGNAL(..){}?? czy w ogóle nie zapisywać tego w przerwaniu tylko wzorować się na przykładzie kolegi :arrow: kasaidolar.

    nie nie nie nie nie... ISR czy SIGNAL to w tym rozumowaniu roznica jedynie kosmetyczna...

    chodzi o to, co masz wewnatrz nawiasow - obslugujesz przerwanie od timera 0, ktore nigdy nie wystapi, bo timer 0 nie zostal uruchomiony. wystapi za to przerwanie od ADC, ktorego obslugi nie masz napisanej - przez to wywolywana jest wewnetrzna funkcja bad_isr (albo default_isr), ktora resetuje procka. to nie jest kwestia czy robic to w przerwaniu, czy tak jak ktos ci gotowca podeslal - przerwania sa rozwiazaniem lepszym, ale i bardziej skomplikowanym, problematycznym itp. niemniej jednak u ciebie w kodzie obslugujesz nie to przerwanie co trzeba...

    w C nie ma operacji potegowania, ^ to operator XOR.

    4\/3!!

    0
  • #16 10 Gru 2008 23:49
    zumek
    Poziom 39  

    InkER_o napisał:
    Wg mnie to jest potęgowanie, mylę się?

    Tak , mylisz sie .
    InkER_o napisał:
    Negacja to ~.

    W takim razie, czym jest operacja Exclusive-OR(XOR), której użyłaś zamiast np. pow() lub w tym konkretnym przypadku zwykłego (x*x) :?:

    Piotrek

    0