SOYER Maj 18, 2019 Autor tematu Udostępnij Maj 18, 2019 Też pomyślałem o programowym wygładzeniu tego wykresu. Z innej beczki, co to za czujnik? Był w komplecie jako zewnętrzny temperatury do mojego pieca... : Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Maj 18, 2019 Udostępnij Maj 18, 2019 Na 99% to półprzewodnikowy czujnik rezystancyjny czyli popularny termistor, np. z serii KTY: https://www.tme.eu/Document/1807f69966f297e1da1dafa767320e88/KTY81.pdf Zmierz go omomierzem a potem chuchnij albo przyłóż palec. Większość (oprócz pewnych specjalnych) termistorów ma ujemny współczynnik temperaturowy (tzw. tempco) więc rezystancja powinna spadać. Możesz z tego i z jakiegoś opornika zrobić zwykły dzielnik i mierzyć napięcie. Niestety termistory nie są zbyt liniowe (jak np. sygnał z wyjścia TMP36) - znając dokładnie typ można używać wzoru z podanymi przez producenta współczynnikami, zajrzeć do tabelki w datasheet albo zwyczajnie zdjąć ch-kę w kilku punktach (np. 0, +25 i +100 stopni), dziwną krzywą aproksymować prostymi a potem interpolować. Czasem nawet spora nieliniowość w ogóle nie ma znaczenia, bo robisz np. termostat. Wtedy bierzesz potencjometr i komparator napiecia, ustawiasz jakiś próg przełączania i ważne jest jedynie to, by jutro i za miesiąc termistor w tej samej temperaturze miał taka samą rezystancję, nie jest ważne jaką konkretnie. 2 Cytuj Link do komentarza Share on other sites More sharing options...
SOYER Maj 18, 2019 Autor tematu Udostępnij Maj 18, 2019 Czy z termistorami też występują podobne problemy jak mam z TMP36, czy to "łatwiejsze" w implementacji czujniki temperatury? Cytuj Link do komentarza Share on other sites More sharing options...
Popularny post marek1707 Maj 18, 2019 Popularny post Udostępnij Maj 18, 2019 I tak i nie. Oba elementy są "analogowe" w swojej istocie więc problemy będą podobne. Czujnik TMP36 jest zespołem wielu tranzystorów a źródłem sygnału jest w nim tzw. bandgap czyli sprytny układ bazujący na fizyce złącza półprzewodnikowego. To z definicji jest liniowe więc dalej to już jakiś wzmacniacz by odseparować "jądro" pomiarowe od linii wyjściowej i tyle. Układ wyjściowy TMP ma niską impedancję wyjściową więc napięcie niewiele zależy od obciążenia czyli od pobieranego prądu - możesz podłączyć do tego np. magnetoelektryczny ustrój pomiarowy i mieć oldskulowy termometr wychyłowy. To oczywiście słaby przykład, ale generalnie ważne jest, by źródła sygnałów były w miarę niezależne od obciążeń. Niestety wzmacniacze są czułe na obciążenia pojemnościowe więc nie można do wyjścia TMP36 podłączyć bezpośrednio kondensatora by tłumić zakłócenia. Musi być po drodze opornik separujący, dopiero te dwa elementy tworzą filtr low-pass. Do tego, mimo dobrego PSRR (czyli współczynnika tłumienia zmian zasilania) czyli tego, że napięcie wyjściowe niewiele zależy od poziomu zasilania czujnika dla prądu stałego, zwykle bardzo on słabnie ze wzrostem częstotlwości. To z kolei oznacza, że szybkie zakłócenia na linii zasilania będa przenikać do wyjścia. I po to dajesz kondensator przy pinach Vcc/GND czujnika - żeby napięcie zasilania chipu nie mogło się szybko zmieniać. Z tych powodów TMP36 nie można traktować jak prostego elementu. W środku jest skomplikowany i trzeba się z nim trochę pocackać. Za to dostajesz doskonałą liniowość, łatwy do wykorzystania sygnał napięciowy i niewielkie błędy początkowe. W zasadzie można bez żadnej kalibracji robić na tym seryjnie termometry o dokładności 2-3 stopni w środku zakresu a to zupełnie wystarcza do większości popularnych zastosowań. Termistory to tanie elementy pasywne. Zmieniają jedynie swoja rezystancję z temperaturą i to wg skomplikowanego wzoru. Dalej to już Twoja inwencja jako projektanta. Robiąc dzielnik tworzysz źródło napięcia, którego sygnał wyjściowy zależy od temperatury (cieszymy się) ale także od a) napięcia zasilania (to bardzo źle) i b) tego co podłączysz dalej (to raczej też nie za dobrze). Takiego źródła nie możesz podłączyć nawet do długiego kabla, bo będzie jeszcze gorzej niż z TMP36. Nie dość, że do dzielnika dotrze inne napięcie zasilania niż wysłałeś (co TMP36 skutecznie ignoruje), to jeszcze bardzo słabo steruje ono obciążeniami. Musisz podłączyć coś co nie pobiera w ogóle prądu - wejście wzmacniacza lub wysokoomowe wejście przetwornika A/C. Za to możesz do takiego dzielnika od razu zapiąć kondensator robiąc filtr dolnoprzepustowy. TMP36 itp układy są wygodne, gdy musisz zadbać (i pomierzyć) np. profil termiczny swojego urządzenia. Mając np. dużą płytę z przetwornicami, stabilizatorami, procesorami, pamięciami itd itp rozmieszczasz w krytycznych punktach szereg takich czujników, podłączasz je do przetwornika A/C (i tak go masz bo to skomplikowany układ, prawda?) i możesz nadzorować i logować temperatury pracy poszczególnych bloków w różnych warunkach eksploatacji i testów. Robisz takich płyt 100 i w każdej wyniki są podobne z dokładnością do 2 stopni. To wygodne, bo skalowanie pomiarów temperatury w odróżnieniu od np. pomiarów napięć czy prądów jest megadrogie i upierdliwe. No, ale płacisz za to w cenie czujnika. Z kolei termistor daje mnóstwo możliwości aplikacyjnych. Może służyć jako element kompensacji termicznej w analogowych układach pomiarowych, w generatorach, wzmacniaczach itp, może być prostym czujnikiem poziomu alarmowego (komparator napięcia, pamiętasz?). Samodzielnie niewiele potrafi - tak jak każdy prosty element, ale z uwagi na cenę i uniwersalność jest wciąż stosowany. Decyzje zależą od wielu czynników: od pożadanych dokłądności, powtarzalności, kosztów produkcji, testowania i kalibracji, serwisu, zastosowania urządzenia itd itp. Wniosek: Moim zdaniem nie ma wyraźnego zwycięzcy. Każdy element trzeba umieć wykorzystać i zastosować, ten który akurat optymalnie pasuje 🙂 2 1 Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Produkcja i montaż PCB - wybierz sprawdzone PCBWay! • Darmowe płytki dla studentów i projektów non-profit • Tylko 5$ za 10 prototypów PCB w 24 godziny • Usługa projektowania PCB na zlecenie • Montaż PCB od 30$ + bezpłatna dostawa i szablony • Darmowe narzędzie do podglądu plików Gerber Zobacz również » Film z fabryki PCBWay
SOYER Maj 19, 2019 Autor tematu Udostępnij Maj 19, 2019 Hej, co spróbowałem zrobić to programowe uśrednienie pomiarów. 10 próbek, każda co 10ms. Chodzi tak od paru godzin. Odczyty zdecydowanie stabilniejsze. Skoki o 1 stopień. W tym tygodniu spróbuję podłączyć te fizyczne filtrowanie... 1 Cytuj Link do komentarza Share on other sites More sharing options...
marek1707 Maj 19, 2019 Udostępnij Maj 19, 2019 Tak mi przyszło do głowy, że jeśli masz zasilanie 5V to Twój ADC ma LSB ważący ok. 5mV (5V/1024). A z kolei 1 stopień Celsjusza to na wyjściu TMP36 zmiana napięcia o 10mV. Przetwornik w AVR jest taki sobie i plus/minus 2LSB to zupełnie normalny rozrzut w środowisku gdzie nie przyłożyłeś się do filtrowania zasilań i referencji przetwornika. Tak więc może pokaż kod, bo z wykresu widzę, że zaczynasz opierać się rozdzielczość jakiejś arytmetyki - nie ma wyników pośrednich tylko całkowite liczby stopni. A jeśli w swoich obliczeniach masz na wyjściu 1 LSB = 1 stopień C, to z definicji pomiarów będziesz miał skoki o 1. Jeśli chcesz mieć wykresy gładsze w tej skali, to musisz zacząć liczyć więcej miejsc po przecinku i nie gubić ich w arytmetyce, by nie tracić rozdzielczości. 1 Cytuj Link do komentarza Share on other sites More sharing options...
SOYER Maj 19, 2019 Autor tematu Udostępnij Maj 19, 2019 (edytowany) Masz rację, używam floata tylko do przeliczenia napięcia, potem już same int-y. Więc mówisz, że powinienem liczyć wszystko na floatach, a tylko wynikową zmienną mieć w pełnych stopniach(dokładniej mi nie potrzebne). Takie przeliczanie zrobi różnicę? Zresztą sprawdzę, to tylko zmiana rodzaju zmiennych... Dotychczasowy kod: void term_grzejniki_maxmin_reset(){ int sumaGrzejniki = 0; int tempGrzejniki [9]; for(int i=0; i<10; i++){ int odczyt = analogRead(grzejniki); //odczytanie wartości z czujnika float VOLT = (odczyt * 5.0) / 1024.0; //przeliczenie odczytanej wartości na napięcie w woltach (dla podłączenia pod 5 V) tempGrzejniki[i] = (VOLT - 0.5) * 100; sumaGrzejniki += tempGrzejniki[i]; delay(10); } temp_grzejniki = sumaGrzejniki/10; sumaGrzejniki = 0; DateTime now = czas.now(); if (temp_grzejniki > temp_grzejniki_max) { temp_grzejniki_max = temp_grzejniki; dzien_temp_grzejniki_max = now.day(); miesiac_temp_grzejniki_max = now.month(); rok_temp_grzejniki_max = now.year(); } if (temp_grzejniki < temp_grzejniki_min) { temp_grzejniki_min = temp_grzejniki; dzien_temp_grzejniki_min = now.day(); miesiac_temp_grzejniki_min = now.month(); rok_temp_grzejniki_min = now.year(); } } Edytowano Maj 19, 2019 przez SOYER Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Maj 19, 2019 Udostępnij Maj 19, 2019 21 minut temu, SOYER napisał: Więc mówisz, że powinienem liczyć wszystko na floatach, Więcej miejsc po przecinku to niekoniecznie float. Możesz za jednostkę przyjąć np. 1/10 stopnia. Pamiętaj, że każde działanie arytmetyczne na liczbach ograniczonej precyzji może powodować błąd, a błędy mogą się skumulować. Jeśli precyzja będzie wystarczająca, kumulacja będzie niedostrzegalna. To tak, jak w przetwarzaniu dźwięku - wewnętrznie maszyneria chodzi co najmniej w 24 bitach (te tańsze), a na wyjściu dostajesz teoretycznie 16 (teoretycznie, bo np. przetworniki w CD maja nieco mniej). Czy jak programy księgowe, dla których jednostką jest 1/10 grosza, a wyniki przedstawiają po zaokrągleniu. 1 Cytuj Link do komentarza Share on other sites More sharing options...
SOYER Maj 19, 2019 Autor tematu Udostępnij Maj 19, 2019 (edytowany) Chodzi o taką zmianę: float VOLT = (odczyt * 5.0) / 2048.0; tempGrzejniki[i] = (VOLT - 0.5) * 200; Choć chyba raczej int sumaGrzejniki = 0; int tempGrzejniki [9]; for(int i=0; i<10; i++){ int odczyt = analogRead(grzejniki); float VOLT = (odczyt * 5.0) / 1024.0; tempGrzejniki = (VOLT - 0.5) * 10; sumaGrzejniki += tempGrzejniki; delay(10); } temp_grzejniki = sumaGrzejniki; sumaGrzejniki = 0; Edytowano Maj 19, 2019 przez SOYER Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Maj 20, 2019 Udostępnij Maj 20, 2019 (edytowany) Hm... a jeszcze takie dziwne pytanie... Tablica "tempGrzejniki" została zadeklarowana jako int[9]; Pomijając fakt, że w ostatniej wersji chyba o tym zapomniałeś... co się stanie, jeśli zmienna "i" przyjmie wartość 9? A w ogóle po kiego grzyba Ci tabela, której nie wykorzystujesz? Zamiast przeliczać za każdym razem zrób sobie po prostu średnią odczytu wartości z konwertera a przelicz na samym końcu, coś w stylu: int i, odczyt; for (i=odczyt=0; i<10;i++) { odczyt += analogRead(cośtam); delay(chwilkę); } float VOLT = (odczyt * 5.0 / 10240.0); // czy jakoś tak Na samych intach też można (trochę większy błąd, ale i tak mniejszy niż rozdzielczość termometru): int centiVolt = (odczyt * 2) / 41; int temperatura_czegośtam = centiVolt - 50; Jeśli mi się przecinek gdzieś nie przesunął to powinieneś dostać rozsądny wynik. Aha - zmienna centiVolt wcale nie jest nikomu do szczęścia potrzebna, wystarczy przecież: temperatura = (odczyt * 2) / 41 - 50; Edytowano Maj 20, 2019 przez ethanak 1 Cytuj Link do komentarza Share on other sites More sharing options...
SOYER Maj 20, 2019 Autor tematu Udostępnij Maj 20, 2019 (edytowany) int sumaGrzejniki = 0; int tempGrzejniki [9]; for(int i=0; i<10; i++){ int odczyt = analogRead(grzejniki); float VOLT = (odczyt * 5.0) / 1024.0; tempGrzejniki[i] = (VOLT - 0.5) * 10; sumaGrzejniki += tempGrzejniki[i]; delay(10); } temp_grzejniki = sumaGrzejniki; sumaGrzejniki = 0; Oto mi chodziło, tak to jest jak telefonem piszę program... Rozumiem, że lepiej, prościej i szybciej dla procka, tablica zbędna i połowa linijek kodu odpadła:): for(int i=0; i<10; i++){ float odczyt += analogRead(grzejniki); delay(10); } float VOLT = (odczyt * 5.0) / 10240.0; temp_grzejniki = (VOLT - 0.5) * 100; odczyt = 0; Jednak skoro najpierw dzielimy przez 10240 a potem mnożymy razy 100 to po skróceniu faktycznie może być: for(int i=0; i<10; i++){ float odczyt += analogRead(grzejniki); delay(10); } temp_grzejniki = (odczyt *2)/41-50 odczyt = 0; Dzięki. Edytowano Maj 20, 2019 przez SOYER Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Maj 20, 2019 Udostępnij Maj 20, 2019 to nie ma prawa działać. deklarujesz zmienną "odczyt" w bloku - poza blokiem już jej nie będzie. Ale rozumiem, że to przeoczenie i "float odczyt" jest nieco wyżej. Bo jeśli są tu i tu to są wtedy dwie różne zmienne i podstawienie czegoś do zmiennej "odczyt" w bloku spowoduje, że nic nie spowoduje :). Po co odczyt to float jeśli wynik w najgorszym razie to 14 bitów inta (czyli zmieści się z zapasem w int16_t)? Żeby procek się nie nudził? Dlaczego zmienna odczyt zerowana jest po podsumowaniu a nie przed? Tak przy okazji - sprawdziłeś jaka będzie różnica między Twoimi (no, powiedzmy że znalezionymi na stronie traktującej o termometrze) dwiema linijkami na floatach a moją jedną na intach? Tak przy okazji w pętli powinno być trochę inaczej (chociaż tak jak jest też zadziała) - niestety od rana jakieś telefony i w sumie nie zdążyłem klepnąć "wyślij" po edycji: for (i=odczyt=0; i<10;i++) { if (i) delay(chwilkę); odczyt += analogRead(cośtam); } Drobiazg - ale chwilkę krócej się wykonuje 🙂 Cytuj Link do komentarza Share on other sites More sharing options...
SOYER Maj 20, 2019 Autor tematu Udostępnij Maj 20, 2019 (edytowany) int odczyt; for(int i=0; i<10; i++){ odczyt += analogRead(grzejniki); delay(10); } temp_grzejniki = (odczyt *2)/41-50; odczyt = 0; Tego ostatniego Twojego drobiazgu nie rozumiem: 24 minuty temu, ethanak napisał: for (i=odczyt=0; i<10;i++) { if (i) delay(chwilkę); odczyt += analogRead(cośtam); } Drobiazg - ale chwilkę krócej się wykonuje 🙂 Edytowano Maj 20, 2019 przez SOYER Cytuj Link do komentarza Share on other sites More sharing options...
ethanak Maj 20, 2019 Udostępnij Maj 20, 2019 Ponawiam pytanie: dlaczego zmienna "odczyt" jest float a nie int? I dlaczego nie jest zerowana przed wejściem do pętli? Co do drobiazgu: w Twojej pętli niepotrzebnie wykonywał się delay(10) po ostatnim odczycie (tzn. pomijając czas konwersji A/D czas wykonania pętli to 100msec). W mojej wykonuje się tylko pomiędzy pomiarami - konkretniej przed każdym pomiarem z wyjątkiem pierwszego (czyli czas wykonania to 90 msec). 1 1 Cytuj Link do komentarza Share on other sites More sharing options...
SOYER Maj 20, 2019 Autor tematu Udostępnij Maj 20, 2019 (edytowany) int odczyt; odczyt = 0; for(int i=0; i<10; i++){ if (i) delay(10); odczyt += analogRead(grzejniki); } temp_grzejniki = (odczyt *2)/41-50; Drobiazg do mnie przemawia teraz, racja. Jednak co za róznica czy odczyt=0 jest przed pętlą czy po zakończeniu obliczeń? Chodziło ci tylko o ZERO przy pierwszej pętli? int odczyt = 0; for(int i=0; i<10; i++){ if (i) delay(10); odczyt += analogRead(grzejniki); } temp_grzejniki = (odczyt *2)/41-50; odczyt = 0; Edytowano Maj 20, 2019 przez SOYER Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
Dołącz do dyskusji, napisz odpowiedź!
Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!