logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Rozwiązano] Niemożność stabilizacji wartości ADC przy pomiarze temperatury z czujnikiem TMP36 i Atmega32A-PU

antoniv10 15 Sty 2021 00:15 1185 26
  • #1 19184494
    antoniv10
    Poziom 3  
    Cześć, próbuje zrobić termometr z wykorzystanie czujnika TMP36 i Atmega32A-PU. Pin AREF przez kondensator ceramiczny 100nF mam podpięty do masy, pin AVCC przez kondensator 100nF do +5V. Dodatkowo na szynach zasilania mam po jednej parze kondensatorów ceramicznych, także 100nF i elektrolitycznych 470uF. Pin Vout czujnika podpięty jest do ADC5. Na pinach ADC6, ADC4 czujnik podpięty jest do zasilania. Mój problem polega na tym, że wartość ADC jest niestabilna. Głównie tyczy to się cyfr jedności (kiedy , np. wartość ADC wynosi 256 to cały czas skacze ona z 256 na 257, potem znowu 256 itd...) . Przekłada się to negatywnie na odczytaną przeze mnie wartość temperatury, ponieważ wartości po przecinku cały czas się zmieniają, np. skacząc w kółko z 21.2 na 21.5. Czytałem trochę o zmniejszaniu zakłóceń i dowiedziałem się, że sąsiadujące piny z pinem, na którym mierzymy ADC trzeba ustawić jako wyjście i podciągnąć wewnętrzny rezystor (ale co to tego ostatniego nie mam pewności). Zrobiłem tak i faktycznie wartości wydają się minimalnie bardziej stabilne. Nie wiem tylko, czy to co zrobiłem jest poprawne ze względu na to, że na ADC6, ADC4 podpięte zasilanie czujnika. Możliwe, że to przypadek, ale wartości po przecinku to tylko liczby 5, 2, 7. Co jeszcze zrobić, żeby ADC i temperatura były stabilne? Jakie zmiany powinienem wprowadzić w moim układzie? Jeszcze jedno pytanie dlaczego jak odepnę czujnik to dalej wyświetla się wartość ADC, która się cały czas zmienia? Może to być związane z tym, że na sąsiednich pinach dalej jest wpięte zasilanie czujnika?

    Kod na którym działa mikrokontroler. Wynik wyświetlany jest na LCD 2x16:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #2 19184585
    piterek-23
    Poziom 33  
    1. zmień kondensator na zasilaniu uC z 470uF na mniejszy np 20uF
    2. jak masz podłączony pin AVCC?
    3. dlaczego zasilasz czujnik z pinów uC, a nie podłączysz pod zasilanie?
    4. usredniaj odczyty - przykładowo zbierasz 32-64 odczyty, dzielisz przez ilość i masz średnią
    5. narysuj schemat swojego urządzenia
  • Pomocny post
    #3 19184590
    rb401
    Poziom 39  
    antoniv10 napisał:
    kiedy , np. wartość ADC wynosi 256 to cały czas skacze ona z 256 na 257, potem znowu 256 itd...


    To że przetwornik dla pewnych napięć skacze o swoją jednostkę nie jest jakieś tragiczne bo to oznacza że zakłócenia mają amplitudę mniejszą niż jego rozdzielczość. Sedno problemu jest w tym że ADC ma akurat rozdzielczość 2,5mV a TMP ma 10mV/stopień i jeśli chcesz mieć na wyświetlaczu dziesiąte stopnia to może to faktycznie wyglądać nieelegancko. Choć metrologicznie jest poprawne działanie. Ale cały ten problem to kwestia rozdzielczości użytego przetwornika i tego nie przeskoczysz bez wymiany go na typ o większej rozdzielczości.

    Można trochę z tym zawalczyć filtrując napięcie z TMP, bo to przebieg wolnozmienny. Przykładowo dodając układ RC, tzn. połączyć Vout do pinu ATmega poprzez opornik kilka kiloomów a między masę a wejście ADC (jak najbliżej ATmega) dać kondensator np. 100nF lub więcej. Ale i tak nie uchroni to przed przeskokami a jedynie może zawęzić przedziały w których występują.

    Można na etapie wyświetlania dołożyć histerezę. Czyli zapamiętywać poprzedni pomiar (z ADC) i jeśli nie różni się od bieżącego o więcej niż jedną jednostkę to wyświetlać ten zapamiętany.

    Ale moim zdaniem najskuteczniej będzie pójść w kierunku, który zasygnalizował tu wyżej kolega piterek-23, czyli filtrację cyfrową.
    Jeśli potrzebujesz odczyty co pół sekundy, to możesz np. same odczyty z ADC robić dużo częściej np. sto razy na sekundę, zbierać do bufora a wartość uśrednioną wyświetlać co pół sekundy. Jeśli charakter zakłóceń ma własności szumu losowego, to nawet poprawi Ci to rozdzielczość pomiaru.
  • #4 19184906
    tmf
    VIP Zasłużony dla elektroda
    antoniv10 napisał:
    Mój problem polega na tym, że wartość ADC jest niestabilna. Głównie tyczy to się cyfr jedności (kiedy , np. wartość ADC wynosi 256 to cały czas skacze ona z 256 na 257,

    Jeśli problemem jest przeskok o jednostkę to znaczy, że nie ma problemu. Masz idealne odczyty. Teraz po stronie programu musisz zrobić jakąś filtrację. Czyli np. uśredniać odczyty z jakiegoś okresu, np. sekundy. Średnia będzie znacznie bardziej stabilna, możesz np. wyświetlać dominantę wartości odczytanych w jakimś czasie itd. Od strony elektronicznej już nic więcej nie zrobisz.
  • #5 19185534
    antoniv10
    Poziom 3  
    Co do uśredniania temperatury, w próbowałem to robić tak jak poniżej, ale nie działa. Ten odczyt powinienem robić np. W przerwaniu timera, np. co sekundę? To co robię poniżej ma w ogóle jakiś sens?
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #6 19186274
    mpier
    Poziom 29  
    Nie ma sensu. Próbowałeś poszukać na forum? Dane zbierane co jakiś czas:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    W razie potrzeby liczysz średnią i masz aktualną wartość do dalszych obliczeń. Oczywiście są inne filtry.
  • #7 19186457
    antoniv10
    Poziom 3  
    Czyli średnią mam obliczyć z ADC, a nie samej temperatury?
  • #8 19186485
    tmf
    VIP Zasłużony dla elektroda
    antoniv10 napisał:
    Czyli średnią mam obliczyć z ADC, a nie samej temperatury?

    Matematycznie, pomijając błędy zaokrągleń to przecież to samo. Prościej akumulować wyniki z ADC i z ich średniej liczyć temperaturę - mniej obliczeń.
  • Pomocny post
    #9 19186612
    BlueDraco
    Specjalista - Mikrokontrolery
    FILTRUJ, nie uśredniaj! Ludziska, czy Wy naprawdę uśredniacie pomiary zamiast je filtrować, że tak wszyscy jak jeden mąż rekomendujecie delikwentowi to głupie uśrednianie? Filtrowanie jest szybsze, prostsze i nie wymaga przechowywania iluś tam próbek. W dodatku jeszcze może podnosić rozdzielczość przetwarzania, jeśli jest taka potrzeba.
  • #10 19186622
    antoniv10
    Poziom 3  
    Wzorując się na tym poście napisałem kod tak jak poniżej. Wynik wydaje się stabilniejszy, ale liczby po przecinku dalej skaczą. To dobre rozwiązanie? A tak btw to wydaje mi się, że lepszym rozwiązanie będzie tutaj uśrednianie temperatury, bo tak jak wspominałem na ADC dostaję tylko wartość po przecinku 0, 2, 5, 7, 9.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #11 19186660
    BlueDraco
    Specjalista - Mikrokontrolery
    Nie dość, że usiłujesz uśredniać, to, o ile rozumiem kod, uśredniasz oddzielnie część całkowitą i ułamkową (mam nadzieję, że się mylę). To musi dawać interesujące wyniki, np. kiedy pomiar oscyluje pomiędzy 0,9 i 1,0. Wesołe, ale jak to się ma do rzeczywistości? Na ADC nie dostajesz nic po przecinku, bo nie ma przecinka. Filtruj wartość ADC, a potem konwertuj na temperaturę.
  • #12 19186822
    mpier
    Poziom 29  
    @antoniv10, pokazałem Ci działający kod, a Ty dalej kombinujesz. Ty nie masz liczyć średniej z pomiarów.

    Co to jest FIR ze współczynnikami równymi 1?
  • #13 19186840
    antoniv10
    Poziom 3  
    mpier napisał:
    [b] Ty nie masz liczyć średniej z pomiarów.

    Nie rozumiem, to z czego mam liczyć tą średnią?
  • #14 19186885
    mpier
    Poziom 29  
    Masz liczyć średnią z "tablica". Cała funkcja, np. average_adc_read() to będą te dwie linie, plus oczywiście start nowego pomiaru. W average_adc() musisz tylko zwrócić średnią z tej tablicy. Pierwszą funkcję uruchamiasz na początku while a drugą kiedy potrzebujesz.
  • #15 19186907
    antoniv10
    Poziom 3  
    Zrobiłem tak jak poniżej. Na LCD pokazują mi się ujemne temperatury.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #16 19186932
    mpier
    Poziom 29  
    To teraz dla odmiany zrób dokładnie jak Ci napisałem w poście nr. 6. average_adc zapisująca tablice:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Druga funkcja, average_adc_read zwraca średnią z "tablica" i to jest wartość do obliczeń.
  • #17 19187474
    BlueDraco
    Specjalista - Mikrokontrolery
    @antoniv10:
    Ta linia kodu jest błędna i zapewne niepotrzebna:
    DDRA &= ~(1 << PA5) | ~(1 << PA6) | ~(1 << PA4);
    Dlaczego używasz operacji logicznych do zapisu rejestrów ADC?

    @mpier:
    Odczyty ADC są liczbami bez znaku - błędny typ zbędnej tablicy. To samo dotyczy zmiennej licznik - za długa i niepotrzebnie ze znakiem.
  • #18 19188115
    antoniv10
    Poziom 3  
    Ta druga funkcja ma wyglądać tak jak poniżej? I na początku głównej pętli najpierw wypisuję wywołuje funkcji "average_adc" , a to zmiennej przechowującej ADC zapisuję wartość zwracaną przez "average_adc_read"?

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #19 19188751
    Wirnick
    Poziom 30  
    Po 1; zaśmiecasz inne fora, by uzyskać pomoc bez nauki programowania C, bez książek oczekując gotowca.
    Po 2 ; Gdy dodasz 6 elementów uint16_t tablicy przekraczasz zakres i kompilator traktuje to jako int. Dlatego LCD wskazuje głupoty(wartości ujemne i obcięte do liczby 15bitowej). 16ty bit jest znakiem liczby.
  • #20 19189182
    antoniv10
    Poziom 3  
    Wirnick napisał:
    Po 1; zaśmiecasz inne fora, by uzyskać pomoc bez nauki programowania C, bez książek oczekując gotowca.
    Po 2 ; Gdy dodasz 6 elementów uint16_t tablicy przekraczasz zakres i kompilator traktuje to jako int. Dlatego LCD wskazuje głupoty(wartości ujemne i obcięte do liczby 15bitowej). 16ty bit jest znakiem liczby.


    Chodzi o to, że nie wiem kiedy mam użyć funkcji "average_adc_read", gdy zrobię coś takiego

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Wartość ADC najpierw z ujemnej rośnie i potem w miarę stabilnie utrzymuje się na jednym poziomie. Jednak to uśrednianie chyba nie działa mi poprawnie, bo przy zmianie temperatury liczby, po przecinku dalej przeskakują pomiędzy 0, 2, 5, 7, 9. Próbowałem też robić tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wywołując funkcję, która ma zwrócić uśrednioną wartość ADC w funkcji "average_adc", tutaj znowu pokazuje mi się ciągle temperatura -50 . Pozmieniałem też typy odpowiednich zmiennych na uint64_t. Nie wiem po prostu jak to jeszcze inaczej rozwiązać.
  • #21 19189885
    BlueDraco
    Specjalista - Mikrokontrolery
    Proponuję mniej magii, a więcej arytmetyki na kartce papieru. Odczyt ADC na zabytkowym ATmega ma 10 bitów - to znaczy, że w zmiennej typu uint16_t możesz ich zsumować 64 bez przekraczania zakresu. Nie trzeba ani 32-, ani 64- bitowych zmiennych - to po pierwsze.
    Po drugie: nie potrzebujesz uśredniać, tylko filtrować filtrem dolnoprzepustowym. Co niby miałoby dać uśrednianie? Wartość radośnie skaczącą tyle razy rzadziej, ile wynosi liczba uśrednianych próbek?

    filtr = filtr - (filtr >> SF) + ADC;
    gdzie wartość SF dobierasz doświadczalnie, pewnie z zakresu 2..6, zacząłbym od np. 3.

    Mając tak zrobiony filtr możesz do obróbki wziąć wartość (filtr >> SF), ale być może lepiej będzie przyjąć, że zmienna filtr zawiera (10 + SF) bitowy wynik przetwarzania - tak, jakbyś miał przetwornik o większej liczbie bitów - i odpowiednio zmienić współczynniki we wzorach, pamiętając jednak o tym, żeby nie "uciąć" górnych bitów danej podczas obiczeń (czyli albo zacząć od dzielenia, albo wykonywać przekształcanie na typie 32-bitowym).
  • #22 19190105
    mpier
    Poziom 29  
    @BlueDraco, u mnie na telefonie "int" jest trzy razy krótszy od "uint8_t". Napisz jak możesz, ale tak w wersji dla osoby piszącej pierwszy program w życiu (może drugi), co to jest to "filtrowanie filtrem dolnoprzepustowym".

    Autor pisze program na chybił trafił, pyta dlaczego średnia z kilku liczb ujemnych daje liczbę ujemną i dlaczego pisanie poza tablicą psuje mu program, a Ty jako rozwiązanie proponujesz oversampling adc. Prosta średnia krocząca jat w tym przypadku całkiem ok, nawet jeśli wykładnicza będzie łatwiejsza w obsłudze i nawet jeśli jakakolwiek inna metoda da lepsze wyniki.

    Dodano po 4 [minuty]:

    BlueDraco napisał:
    filtr = filtr - (filtr >> SF) + ADC;
    ?
  • #23 19190821
    _lazor_
    Moderator Projektowanie
    Jeśli ktoś myśli poważnie o programowaniu w przyszłości to douczenie się o filtrach nie powinno być problemem, taki rodzaj zawodu, że prędkość uczenia się jest bardzo istotna. Tutaj dorzucę pomoc co do filtrów:

    http://t-filter.engineerjs.com/

    Jeśli ktoś nie myśli poważnie o karierze programisty i to w sumie DSP, to niech zostanie przy uśrednianiu.
  • #24 19191121
    BlueDraco
    Specjalista - Mikrokontrolery
    Taaaak. Przecież każdy może programować mikrokontrolery. Nie trzeba w tym celu znać podstaw arytmetyki ani logiki, że o architekturze komputerów nie wspomnę. Każdy też może mierzyć mikrokontrolerem sygnały bez elementarnej wiedzy na temat sygnałów i ich przetwarzania. W ogóle każdy może zrobić wszystko, np. windę, bez znajomości mechaniki i automatyki, wystarczy Arduino, Google i pomocne forum. A że winda spadnie? No trudno. Najważniejsze że każdy może, i koniecznie trzeba każdego w tym przekonaniu utwierdzać.
    A że złożoność obliczeniowa średniej jest większa niż filtru? A kto powiedział, że ten, kto pisze program ma wiedzieć, co to jest złożoność obliczeniowa, albo jaki jest skutek użycia uint64_t albo float na AVR zamiast uint16_t? Najważniejsze, żeby mierzyć temperaturę, i żeby wynik się dobrze wyświetlał, przynajmniej wtedy, kiedy jest parzysty, bo przecież nieparzysty nie będzie się zdarzał zbyt często, nie? ;)
  • #25 19191157
    _lazor_
    Moderator Projektowanie
    @BlueDraco Nie wszyscy będą w tym stopniu się zagłębiać, po wysypie popularności arduino, esp i innych dziwactw nie uważam by hobbyści, chcieli rozwijać swoją wiedzę tylko chcą szybkich efektów, za co ich winić nie można - nie są i nie będą inżynierami oprogramowania. Tak prosiłbym by brać na to poprawkę i pozwolić ludziom być nie profesjonalnymi.

    Oczywiście w pracy nie ma że boli, ale na forum można trochę popuścić wymagania ;)
  • #26 19191969
    BlueDraco
    Specjalista - Mikrokontrolery
    święta racja :)
    Wkurza mnie nie to, że ktoś czegoś nie wie, tylko to, że nie chce wiedzieć, a jednocześnie chce koniecznie robić to, co tej wiedzy wymaga. Ja jako kształcony informatyk z podstawową znajomością elektroniki w pewnym momencie z "musu" i potrzeby wgryzłem się w elektronikę na tyle, żeby świadomie projektować proste układy wzmacniające, przełączające, a nawet nie całkiem proste zasilające, z czego obecnie na co dzień korzystam, a nawet niekiedy uczę tego innych - ale najpierw było grzebanie w książkach i kartach katalogowych, a potem rysowanie schematów, szukanie błędów i ich poprawianie.
  • #27 19194040
    antoniv10
    Poziom 3  
    Chyba będę cały układ jeszcze dodatkowo filtrował, bo wyniki i tak są stabilne, a zobaczyłem, że nie mam dławika i mogę dodać kondensatory.

Podsumowanie tematu

Użytkownik zmaga się z niestabilnością wartości ADC podczas pomiaru temperatury za pomocą czujnika TMP36 i mikrokontrolera Atmega32A-PU. Problemy dotyczą skoków wartości ADC, co wpływa na odczyty temperatury. W odpowiedziach zasugerowano kilka rozwiązań, w tym zmniejszenie pojemności kondensatorów na zasilaniu, uśrednianie odczytów ADC, a także zastosowanie filtrów dolnoprzepustowych. Użytkownik próbował implementować uśrednianie, ale napotkał trudności z poprawnym obliczaniem średniej oraz z błędnymi wartościami temperatury. Wskazano również na konieczność poprawy kodu oraz na błędy w typach zmiennych, co prowadziło do nieprawidłowych wyników.
Podsumowanie wygenerowane przez model językowy.
REKLAMA