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

[AVR][C]problem przeliczania wartości z ADC

ziggi86 10 Wrz 2009 20:09 3959 24
  • #1 7003486
    ziggi86
    Poziom 13  
    Witam

    Mam następujący problem z którym niestety nie mogę sobie poradzić, już trochę siedzę i nic...

    Do pomiaru temperatury użyłem czujnika pt100 podłączony do wzmacniacza różnicowego, i całość do przetwornika ADC (fragment schematu w załączniku). Pomiar stało prądowy, napięcie zasalania czujnika to 4.096V (przy prądzie ~1,2 mA) zewnętrzne źródło napięcia odniesienia.

    I teraz tak... wziąłem się za kalibracje całego urządzenia, pierw podpoiłem opornik 100 ohm a następnie 150 ohm i sprawdziłem odczyt na przetworniku(dla 100 Ohm jest 304, dla 150 ohm 455 co dopowiada temperaturze 0 stopni C i 131 stopni C według tabeli rezystancji pt100 w zależności od temperatury...- wszystko w małym przybliżeniu) Potem policzyłem sobie równanie prostej opisującej tą zależność, jak wiadomo pt100 jest liniowym czujnikiem co niby ułatwia sprawę ale nie do końca bo tu pojawia się problem...

    Wzór prostej to y[deg C]=(131/151)x-263.73 gdzie x to odczyt z przetwornika, i teraz pytanie jak to zaimplementować w C na atmedze 8? problem jest w tym że nie za bardzo uC nie radzi sobie z liczbami zmienno przeciekowymi i ułamkami, dlatego też jeśli dam np aby podzielił 131/151 w celu uzyskania współczynnika przy x to dostane 0 co jest bez sensu... podobnie z wartościami po przecinku...

    Myślałem aby zmienić trochę formę zapisu całą temperaturę przemnożyć przez 100 tak aby móc otrzymać wartości po przecinku jednak pojawia się znowu problem ponieważ liczby przekraczają już wartości unsigned int :)

    Nie wiem jak to inaczej ugryźć ale na pewno da się to zrobić dużo prościej;)


    Napięcie odniesienia jest trochę bez sensu dobrane ponieważ lepiej było by gdyby korzystać z 2.048 V co daje większą rozdzielczość... ale popełniłem błąd przy zamawianiu części i czekam teraz na poprawne źródło odniesienia :>


    Z góry dziękuje za wszelką pomoc.



    [AVR][C]problem przeliczania wartości z ADC
  • #2 7003539
    __Maciek__
    Poziom 20  
    IMHO źródło napięcia odniesienia nie stanowi tu problemu. Wystarczy zmienić wzmocnienie wzmacniacza operacyjnego. ( wg. mnie to nawet wyższe napięcie może być korzystne. // potencjalnie mniejszy stosunek szumów do sygnału użytecznego, ale tu wiele zależy od układu i jego otoczenia. // )

    Jeśli chodzi zaś o obliczenia, to ja stosowałem bez większych problemów liczby zmiennoprzecinkowe w atmedze8 . ( Kwestia co jeszcze mikrokontroler ma robić, i czy wystarczy zasobów. )
  • #3 7003584
    Freddie Chopin
    Specjalista - Mikrokontrolery
    y[deg C] = (131/151)x-263.73
    100 * y[deg C] = 100 * ((131/151)x-263.73)
    100 * y[deg C] = (100 * 131 / 151) * x - 26373
    100 * y[deg C] = 13100 * x / 151 - 26373
    y[deg C] = (13100 * x / 151 - 26373) / 100

    błąd będzie marginalny

    Przedewszystkim nie stosuj zmiennych "standardowych", tylko dodaj nagłówek <stdint.h>, a z niego stosuj zmienne typu [u]int{8|16|32|64}_t

    W twoim przypadku - uint32_t, czyli zmienna 32-bitowa.

    
    uint8_t y,
    uint16_t x;
    
    x = getAdc();
    
    y = (uint8_t)(((13100ul * ((uint32_t)x)) / 151ul - 26373ul) / 100ul);
    


    4\/3!!
  • #4 7003633
    Warhard
    Poziom 12  
    Witam kolego.

    Wychodząc ze wzoru y[deg C]=(131/151)x-263.73

    Zrealizował bym tak algorytm

    y[deg C]=((131*x)/151)*100-(263,73*100) to spokojnie zrealizujesz na 32-bitowej zmiennej

    Pozdrawiam Warhard
  • #6 7003861
    ziggi86
    Poziom 13  
    ok, w pełni się z Wami zgadzam , tylko że mam kilka wątpliwości...

    Bo też tak robiłem tylko że czy nie pojawia się problem przy obliczaniu większych wartości wykraczających poza uin16_t ? bo np jeśli mamy 13100*304 to znacząco wychodzi poza zakres uint16_t więc nie wiem na ile ma to wpływ na szybkość działania programu + sam program ponieważ liczmy na dużo większych zmiennych niż przewiduje sama funkcja...czy nie jest to problem?


    Poza tym korzystam z inttypes.h ale to i są te same deklaracje zmiennych, tylko że nie do końca rozumiem zapisu " ul " przy liczbach, i nie do końca jestem pewien czy rozumiem też zapis (uint32_t)x ... bo to oznacza że kompilator ma dokonać działania na 32 bitowej zmiennej bez znaku czyli np

    Cytat:
    (13100ul * ((uint32_t)x)


    oznacza ze x i 13100 ma wymnorzyć i i traktować jako 32 bitową zmienną, wtedy wykluczało by to problem który przytoczyłem powyżej... :)
  • Pomocny post
    #7 7003930
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Tworzysz problem na siłę. Skoro zmienna 16-bitowa nie starcza, to należy użyć 32-bitowej. Nie ma magicznego sposobu, żeby to liczyć na 8-bitach i trwało to 3 cykle...

    ul oznacza Unsigned Long, czyli dla AVRa pewnie to samo co uint32_t.

    (typ_zmiennej)jakas_zmienna to rzutowanie - sugerujesz kompilatorowi, że zmienna nie ma wcale typu A, tylko typ B. Zwykle wywołuje to konwersję z typu A do B.

    4\/3!!
  • #8 7005446
    Jerzy_W
    Poziom 14  
    Witam!

    Można to zrobić bez dzielenia:

    Y=131/151*x - 264

    131/151=56856/65536

    Y=56856*x/65536 - 264

    65536= 2 do 16-tej, czyli po mnożeniu trzeba "odciąć" dwa najmłodsze bajty.
  • #9 7011471
    peterrrm
    Poziom 14  
    Witam

    Czy mógłby mi ktoś wyjaśnić dlaczego wynik tego dzielenia zawsze jest wyświetlany jako 0?
    
    #include <stdint.h>
    #include <avr/io.h>
    #include <inttypes.h>
    #include <util/delay.h>
    #include <hd44780.c>
    char buffer_n[7];
    
    int main(void)
    {
    
    
    while(1)
    {
    LCD_Initalize();
    LCD_Clear(); 
    
    uint16_t	 a=2.0;
    uint16_t b=6.0;
    uint16_t c;
    c=a/b;
    
    
    utoa(c, buffer_n, 10);
    
    LCD_GoTo(0,1);
    LCD_WriteText(buffer_n);
    
    }
    return 0;
    }
  • #10 7011476
    Konto nie istnieje
    Poziom 1  
  • #11 7012163
    peterrrm
    Poziom 14  
    Ok zgadzam się, ale jeśli zadeklaruje zmienne jako float albo double czyli zmiennoprzecinkowe wówczas na wyświetlaczu nic się nie pojawia...
  • #12 7014022
    Konto nie istnieje
    Poziom 1  
  • #13 7014247
    OldSkull
    Poziom 28  
    Mając coś takiego: y[deg C]=(131/151)x-263.73; nie ma problemu:
    100y = 13100/151 * x - 26373;
    100y = 87*x - x/4 + x/201 - 26373;
    Problemu nie będzie. Dokładność będzie całkiem dobra. Jedynym problemem może być przekroczenie 753 (dla uint16). Można w takim wypadku:

    x -= 304;
    100y = 87*x - x/4 + x/201;

    Albo lepiej:
    if (x>700)
    {
    x -= 304;
    y100 = 87*x - x/4 + x/201;
    }
    else
    y100 = 87*x - x/4 + x/201 - 26373;
  • #14 7015106
    peterrrm
    Poziom 14  
    Więc pytam o "nie" ? czy ktoś wie dlaczego przy takiej deklaracji program nie działa poprawnie?
  • #16 7015499
    peterrrm
    Poziom 14  
    Chodzi mi o kod wyżej. Jeśli zmienne są zadeklarowane tak:

    double a=2;
    double b=6;
    double c;

    lub

    float a=2;
    float b=6;
    float c;

    program nie działa, w ogóle nic sie nie wyświetla na wyświetlaczu. A ponieważ chce wykonywać dzielenie nie mogą byćzadeklarowane jako int.
  • #18 7015611
    Freddie Chopin
    Specjalista - Mikrokontrolery
    A zanim napiszesz kolejny post pisząc "teraz na wyświetlaczu mam znaki zapytania" zerknij do dokumentacji avr-libc pod kątem liczb zmiennoprzecinkowych. Naprawdę nie trzeba pisać na forum, żeby się czegoś dowiedzieć - wystarczy poczytać dokumentację.

    4\/3!!
  • #19 7016035
    peterrrm
    Poziom 14  
    Zwracam się tutaj z prośbą o pomoc jeśli ktoś nie ma ochoty pomóc to niech nie komentuje a tym którzy pomagają dziękuje.
  • #20 7016117
    Freddie Chopin
    Specjalista - Mikrokontrolery
    No to masz problem. Sprawa jest prosta - jeśli zapytasz o "znaki zapytania" to każdy może zgłosić twojego posta do moderatora, ponieważ ten temat BYŁ już poruszany i to nie raz. Jest nawet poruszony w przyklejonym temacie o zaczynaniu z WinAVR. Informację o tym można też znaleźć w google. Niestety jakoś tak się składa, że chyba nikomu się tego nie chce szukać czytać...

    Pozatym - te sprawy SĄ poruszone w dokumentacji, nie wiem więc czemu żądasz dodatkowej odpowiedzi na forum? Że co? Masz jakieś specjalne prawa, że nie musisz czytać dokumentacji i mamy ją przeczytać za ciebie? Jakbym na forum spytał się ile jest 7 * 8 to co? Też mogę sobie napisać, że "proszę o pomoc, jak ktoś nie ma ochoty pomóc to niech siedzi cicho"?

    Posiadasz wszystkie informacje które są potrzebne do uruchomienia tego, czyli dokumentację oraz wiedzę o tym, że coś w niej jest na temat liczb zmiennoprzecinkowych. Wiesz też, że coś jest w temacie przyklejonym. Mało? To może to:

    Cytat:

    14. Przed napisaniem nowego tematu każdy użytkownik jest zobowiązany do zapoznania się z zawartością danego działu oraz zawartych w nim ogłoszeń (niebieskie tematy). Powinien również użyć lokalnej wyszukiwarki w celu upewnienia się, czy temat nie był już poruszany na forum (link szukaj u góry strony).
    ...
    16. Za podstawowe przesłanie w działalności na forum uznaje się bezinteresowność, własną inicjatywę i przedsiębiorczość użytkowników. Nie będą akceptowane wszelkie formy lenistwa, i roszczeniowego charakteru prezentowane przez użytkowników.


    Wszystko na ten temat. W razie wątpliwości zastanów się tym czym różni się "pomoc" od "podania rozwiązania na talerzu" (niekiedy zwanego "wyręczaniem").

    4\/3!!
  • #21 7021598
    peterrrm
    Poziom 14  
    Dziękuje GrEG0 za naprowadzenie na prawidłowe rozwiązanie, natomiast bardzo przepraszam, że poruszyłem wielkie ego Pana Freddie Chopin. A dla ludzi któży dopiero zaczynają z avr i mają podobny problem podaje kod który działa prawidłowo:
    #include <stdint.h> 
    #include <avr/io.h> 
    #include <inttypes.h> 
    #include <util/delay.h> 
    #include <hd44780.c> 
    char buffer_n[7]; 
    
    int main(void) 
    { 
    
    
    while(1) 
    { 
    LCD_Initalize(); 
    LCD_Clear(); 
    
    double   a=2.0; 
    double b=6.0; 
    double c; 
    c=a/b; 
    
    
    dtostrf(c, 5,4,buffer_n);// Konwersja liczby double  do asci 
    
    LCD_GoTo(0,1); 
    LCD_WriteText(buffer_n); 
    
    } 
    return 0; 
    }

    pozdrawiam
  • #22 7021654
    Freddie Chopin
    Specjalista - Mikrokontrolery
    peterrrm napisał:
    bardzo przepraszam, że poruszyłem wielkie ego Pana Freddie Chopin.

    ha! jest dokładnie odwrotnie - to pewnie ja powinienem przeprosić, że poruszyłem twoje wielkie ego. Przecież tobie - jako początkującemu w temacie i na forum - wszystko należy się na talerzu!

    Cytat:
    A dla ludzi któży dopiero zaczynają z avr i mają podobny problem...

    ... są tematy przyklejone i kursy w necie. Korona by ci z głowy spadła gdybyś przejrzał?

    4\/3!!
  • #23 7021734
    peterrrm
    Poziom 14  
    Jak widać przejrzałem. A zwroty typu "Ci" , "Tobie" pisze się z dużej litery- uwaga na przyszłość, zresztą tego uczą juz w podstawówce ale widocznie niektórzy wtedy nie chcieli uczyć się od mądrzejszych....
  • #24 7021766
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Duża literkę mam zarezerwowaną dla tych, którzy zasługują na mój szacunek - proste [; Tacy którzy argumentują wszystko "moim ego" i uważają, że "należy im się", nie zaliczają się do tej grupy - sorry.

    Jak już jesteśmy w temacie szkół, to chciałbym zauważyć, że uczą tam też samodzielnego zdobywania wiedzy. Dla niektórych - jak widać - szczytem samodzielności jest spytanie na forum [; Szanujemy ich.

    4\/3!!
  • #25 7021954
    peterrrm
    Poziom 14  
    To się zdecyduj na coś, bo sam się gubisz. Najpierw piszesz, że nie zasługuje na Twój szacunek a potem zmieniasz jednak zdanie i juz szanujesz... żałosne, tak samo żałosne jak ta cała dyskusja, więc nie mam zamiaru jej dalej ciągnąć. A szanuje się każdego nawet wroga.
REKLAMA