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

[Rozwiązano] Odczyt danych z DHT11 przez Atmega 8 w C++: błędny odczyt CRC, temperatura i wilgotność wynoszą 0

koczis_ws 25 Lis 2021 21:47 1125 29
  • #1 19729700
    koczis_ws
    Poziom 27  
    Witam,
    Zapoznałem się z tym tematem: https://www.elektroda.pl/rtvforum/topic2564625.html
    Niestety jest zamknięty, więc musiałem otworzyć nowy.
    Szukałem wielu porad w tym temacie i ostatecznie napisałem program w BASCOmie i działa, aczkolwiek z pewnym problemem z częstym błędnym odczytem CRC.
    Teraz powoli przeprowadzam się na C i z podanego tematu ściągnąłem program. Trochę go przerobiłem (połączyłem moduły w jeden program bo nie mogłem sobie poradzić gdy były podzielone na 2). Ale niestety nie działa prawidłowo, zarówno temperatura jak i wilgotność jest 0.
    Nie mam jeszcze wyświetlacza, więc zapisuję dane do EEPROM i tam sobie je analizuję.
    Mój program jest taki:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #2 19729915
    gps79
    Poziom 35  
    Ustaw poprawnie F_CPU dla Twojego mikrokontrolera, następnie doprowadź do stanu, gdy zobaczysz coś na UART.
    Zapisywanie do EEPROM zostaw sobie na koniec. W tej postaci (zapisy co 1s) szybko wykończysz EEPROM.

    Z poniższymi poprawkami powinno działać:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #3 19730175
    koczis_ws
    Poziom 27  
    Dzięki, ale niestety nie działa :(. Przy kompilacji wysypuje cały worek błędów.
    A co do zapisu EEPROM to faktycznie zapomniałem o jej trwałości. Przerobiłem tak, że zapis jest na żądanie (przycisk). Nadal wpisy są zerowe.
  • #4 19730496
    mpier
    Poziom 29  
    Witam,
    całości nie przeczytałem, ale tak z grubsza to kilka błędów jest.

    Ustawiasz pin dht11 na wyjście i podajesz stan wysoki. Nie wiem jaki prąd pociągnie dht11 w takiej sytuacji, ale niepotrzebnie ryzykujesz uszkodzeniem atmegi albo czujnika. Jeśli nie wystarczy rezystor podciągający, albo masz bardzo długie przewody, to zastosuj zewnętrzny, ale nie podawaj na ten pin zasilania bezpośrednio.

    Wyrażenia typu "while(!(DHT11_PIN & (1<<DHT11_INPUTPIN)))" mogą zablokować cały program (poza przerwaniami) na dowolnie długo w przypadku uszkodzenia czujnika albo przewodów, a z tak pisanym programem nawet się o tym nie dowiesz.

    Nie musisz używać "define LED_ON", możesz napisać funkcję włączającą LED, np "void włącz_LED()". Jesteś pewien tego "#define F_CPU 9600000"?

    Napisałem Ci w poprzednim temacie, żebyś zaczął od migania ledem. Napisz program obsługujący przycisk i migający ledem, i dodawaj po kawałku całą resztę. Póki led miga i reaguje na przycisk, jest duża szansa, że program działa i coś robi. Kody błędów, czy nawet temperaturę możesz sobie wymigać, jeśli nie możesz podłączyć portu szeregowego.

    Pozdrawiam
  • #5 19730572
    koczis_ws
    Poziom 27  
    mpier - ja tego nie pisałem tylko połączyłem bibliotekę' dht11.c' i program 'lcd_manin.c' z linku z pierwszego postu i trochę go zmodyfikowałem ze względu na brak wyświetlacza (już zamówiłem i jedzie ). Ja tego wyświetlacza w docelowym projekcie nie potrzebuję, bo będzie włączał wentylator w łazience po przekroczeniu pewnej wilgotności. Nie analizowałem działania funkcji odczytu danych tylko zawierzyłem autorowi, który napisał, że działa.
    Mój program napisany w BASCOM na tym samym procku i tym samym czujniku działa, ale chciałem to napisać w tym podobno lepszym i tak chwalonym C choćby w celach poznawczych.
    Wpisałem 9600000 bo przy takim taktowaniu pracuje mój program.

    PS.
    Cyt: Póki led miga i reaguje na przycisk, jest duża szansa, że program działa i coś robi.
    Widać, że nie czytałeś całości bo coś takiego jest w pętli.
  • #6 19730711
    mpier
    Poziom 29  
    Masz przy atmedze kwarc 9,6MHz? Ten projekt "lcd" ma tylko w nazwie, spróbuj uruchomić go bez przerabiania i bez przenoszenia funkcji z jednego pliku do drugiego. Ewentualnie kompilator podpowie, jeśli coś będzie nie tak. Podłącz port szeregowy i sprawdź co wyjdzie.
    koczis_ws napisał:
    Mój program napisany w BASCOM na tym samym procku i tym samym czujniku działa, ale chciałem to napisać w tym podobno lepszym i tak chwalonym C choćby w celach poznawczych.
    To napisz, ale może jednak zacznij od migania ledem z poprzedniego wątku. Czego spodziewasz się po kopiowaniu przypadkowych kodów? Myślisz, że będą lepsze od bibliotek przygotowanych przez producenta bascoma?

    Czytasz informacje z kompilatora? Np.
    
    newavr-main.c:157:10: warning: variable 'temperature' set but not used [-Wunused-but-set-variable]
       int8_t temperature = 0;
              ^
    

    Zapisujesz dane z dht11 do zmiennych lokalnych, a do eeprom zapisujesz zera ze zmiennych globalnych, o takiej samej nazwie.
  • #7 19730764
    gps79
    Poziom 35  
    Dałem autorowi propozycję rozwiązania. Kod, który wkleiłem działa z niewielkimi modyfikacjami (inne dekodowanie bajtów odebranych z szyny szeregowej) na emulatorze arduino z podłączonym do DHT22.
    Autorze, jak się nauczysz kompilować kod, to weź ten mój i uruchom tak, jak pisałem w poprzednim poście. Przejrzyj też, co zmieniłem, bo było tam kilka błędów (timing, CRC, dekodowanie, podwójnie zadeklarowane zmienne), które poprawiłem.
  • #8 19730768
    mpier
    Poziom 29  
    Widzę, że zapisujesz w koło w jednym miejscu: "eeprom_write_byte(1, humidity+1)". Zwiększ adres po zapisie do eeprom, to będziesz miał więcej danych do analizy.

    Dodane:
    @gps79, tak, tylko te "print() i println()" mogą autora zmylić. Może "printf("pomiar: %d temperatura: %d wilgotność: %d%%\n", numer, temperature, humidity)"?
  • #9 19730800
    koczis_ws
    Poziom 27  
    mpier napisał:
    Zwiększ adres po zapisie do eeprom, to będziesz miał więcej danych do analizy.

    Dobry pomysł, spróbuję.
    gps79 napisał:
    Dałem autorowi propozycję rozwiązania. Kod, który wkleiłem działa z niewielkimi modyfikacjami (inne dekodowanie bajtów odebranych z szyny szeregowej) na emulatorze arduino z podłączonym do DHT22

    Ale tu jest Atmega8 C++ i czujnik DHT11
    mpier napisał:
    Zapisujesz dane z dht11 do zmiennych lokalnych, a do eeprom zapisujesz zera ze zmiennych globalnych, o takiej samej nazwie.

    Hmmm . . . . przeoczyłem :)
  • #10 19730865
    gps79
    Poziom 35  
    Autorze, proszę Cię. Uruchom ten mój kod. On jest specjalnie dla Ciebie, dla Twojego Atmega8 C++ dla Twojego DHT11.
  • #11 19731104
    koczis_ws
    Poziom 27  
    gps79 napisał:
    Autorze, proszę Cię. Uruchom ten mój kod. On jest specjalnie dla Ciebie, dla Twojego Atmega8 C++ dla Twojego DHT11.

    Próbowałem ale ilość błędów kompilacji mnie przerosła.
    Natomiast ruszyło gdy zmieniłem odczyt danych do zmiennych lokalnych (OOPS), ale czyta tylko wilgotność a temperatura zawsze jest FF
  • #12 19731146
    mpier
    Poziom 29  
    Spróbuj zamienić kolejność odczytu, teraz masz najpierw "humidity = dht11_gethumidity();" a dalej "temperature = dht11_gettemperature();". Zobacz co wyjdzie jak dasz najpierw odczyt temperatury. Ogólnie ten program jest zły.

    Podłączyłeś port szeregowy?
  • #13 19731158
    koczis_ws
    Poziom 27  
    mpier napisał:
    Ogólnie ten program jest zły.

    Nie ja go pisałem tylko niejaki : copyright (c) Davide Gironi, 2011 i podobno działa wyśmienicie.
    Nie czyta temperatury na wszystkich czujnikach jakie posiadam. A ciekawe dlaczego FF a nie 0 ?

    PS.
    Już wiem, jest definicja #define DHT11_ERROR 255

    Dodano po 24 [minuty]:

    No i się wyjaśniło. Jak zmieniłem kolejność to nie czytał wilgotności. Odczyty temperatury i wilgotności odbywają w kolejnych wywołaniach funkcji 'dht11_getdata'.
    A wiadomo, że czujnikowi musimy dać oddech jednosekundowy między kolejnymi wywołaniami. Dodanie _delay_ms(1000); między wywołaniami zlikwidowało problem i wszystko hula.
    mpier - ten program nie jest aż taki zły :D.
  • #14 19732628
    koczis_ws
    Poziom 27  
    Witam ponownie,
    Już praktycznie panuję nad tym programem, robię na nim różne eksperymenty "naukowe" :).
    Ale jednej rzeczy nie rozumiem i nie znalazłem nigdzie wytłumaczenia. Chodzi o ustawianie bitów przez przesunięcie bitowe w lewo. Tu fragment, który mnie niepokoi:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Wiem, że jest to przesunięcie o 4 pozycje , ale jak się to ma do definicji DHT11_INPUTPIN
    Będę bardzo wdzięczny za łopatologiczne wytłumaczenie.
  • #15 19732764
    mpier
    Poziom 29  
    Dobrze, że Cię niepokoi, przecież nie możesz ustawiać portu dht11 w stan wysoki. "(1<<DHT11_INPUTPIN)" to jest "(1<<PC4)", to jest "(1<<4)", to jest "16".
  • #16 19733245
    koczis_ws
    Poziom 27  
    No fajnie, ale na czym polega transformacja PC4 na 4 bo to , że przesunięcie o 4 daje 16 to ja wiem.
    A odnośnie ustawiania wyjścia w stan wysoki to z tego co wiem oryginalna wersja DHT11 może być zasilana przez wejście (ale nie musi). Odpowiedni impuls startowy (80 ms) ładuje wewnętrzny kondensator i zasila układ w czasie transmisji. I wtedy jest prawdziwe 1-wire. Podróby tego nie mają i wymagają zasilania. Dlatego piszą , że to jest prawie 1-wire.
    Ale myślę, że dla zachowania kopabitylności układ jest odporny na podanie stanu wysokiego na wejście. Co potwierdza fakt, że jeszcze żaden mi nie padł, ani nie uszkodził procka.
  • #17 19733532
    mpier
    Poziom 29  
    Ty tego nie programujesz w notatniku? Kliknij na to "PC4" i zobacz co tam jest. Pewnie będzie "#define PC4 4" w "iom8.h".

    Co innego zasilić przez wejście, a co innego podać na to wejście (właściwie to wyjście) zasilanie. Pin od przycisku też możesz ustawić na wyjście w stanie wysokim, zamiast na wejście z podciągnięciem, i to też będzie działało. Jak długo?
  • #18 19733864
    koczis_ws
    Poziom 27  
    Ale DHT11 podczas oczekiwania jest w stanie wejścia, a więc czyta linię a nie coś nadaje.

    Dodano po 13 [minuty]:

    mpier napisał:
    Pewnie będzie "#define PC4 4" w "iom8.h".


    Nie można było odrazu tak :)

    Ten przykład pokazuje upierdliwość programowania w C.
    Takie wielopoziomowe wyłuskiwanie informacji powoduje, że zakres wiedzy na temat programowania w tym języku jest niepotrzebnie rozbudowany. Takie programowanie nie wpływa na kod wynikowy a jedynie na czas kompilacji, który i tak jest szybki. Dlatego dla mnie bardziej czytelny jest zapis:
    PORTC =PORTC & 0b00001000 , któremu oczywiście można przypisać nazwę symboliczną np. OUT3_ON
    zamiast:
    PORTC |= (1<<DHT11_INPUTPIN);
    To jest moje zdanie oczywiście.
  • #19 19734365
    mpier
    Poziom 29  
    Pewnie tak, dzisiaj, żeby ustawić w rejestrze PORTB jedynkę na pozycji PB4 napisałbym tak: PORTB = (1 << PB4), ale gdybym pisał swój pierwszy program, to nie wiedziałbym, co to jest PB4 i PORTB i mruganie ledem na PB4 napisałbym tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Działa na atmega8 bez "wyłuskiwania informacji".
  • #21 19735071
    ex-or
    Poziom 28  
    koczis_ws napisał:
    oryginalna wersja DHT11 może być zasilana przez wejście (ale nie musi). Odpowiedni impuls startowy (80 ms) ładuje wewnętrzny kondensator i zasila układ w czasie transmisji. I wtedy jest prawdziwe 1-wire. Podróby tego nie mają i wymagają zasilania. Dlatego piszą , że to jest prawie 1-wire.

    Nie no, to bzdura jest. Skąd żeś to wytrzasnął?
  • #22 19735109
    koczis_ws
    Poziom 27  
    ex-or napisał:
    Skąd żeś to wytrzasnął?

    Z internetu

    Dodano po 7 [godziny] 21 [minuty]:

    mpier napisał:
    Ustawiasz pin dht11 na wyjście i podajesz stan wysoki. Nie wiem jaki prąd pociągnie dht11 w takiej sytuacji, ale niepotrzebnie ryzykujesz uszkodzeniem atmegi albo czujnika.


    Nie wiem o co chodzi ale bez tej sekwencji na początku i na końcu funkcji czytania czujnika wartości zwracane wynoszą zero:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #23 19736348
    mpier
    Poziom 29  
    Tak na szybko, to usuń oba "reset port" a "send request" zamień na:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    W razie potrzeby odkomentuj linie odpowiedzialne za podciągnięcie wejścia i dopisz odpowiednią na początku main().

    Możesz jeszcze spróbować przerobić potencjalnie nieskończone pętle "while(DHT11_PIN & (1<<DHT11_INPUTPIN));".
  • #24 19736643
    koczis_ws
    Poziom 27  
    To nie działa. Ale poniżej cytat z datasheet DHT11:
    Odczyt danych z DHT11 przez Atmega 8 w C++: błędny odczyt CRC, temperatura i wilgotność wynoszą 0

    Z tego wynika, że na poczętku potrzebne jest zbocze opadające dla zainicjowania czujnika. Czyli podanie stanu wysokiego w czasie oczekiwania na wyjście korespondujące z wejściem czujnika jest OK. Potem podajemy LOW na czas 18 ms po czym przełączamy się na nasłuch.
    Chyba , że się mylę ale nie sądzę jak mawiał mój znajomy :)
    Analizowałem bibliotekę dla Arduino i tam jest tak samo.
    Przecież czujnik niezainicjowany jest ustawiony jako wejście i podanie napięcia VCC mu nie szkodzi a i wyjście procesora nie jest przeciążone bo pobór prądu przez wejście jest b. mały (wysoka impedancja).
  • #25 19736746
    mpier
    Poziom 29  
    Co nie działa? Musiałbyś kod pokazać aktualny.

    Dalej nie wiem czemu ma służyć ustawianie wyjścia w stan wysoki. Po co to robić? Autor się pomylił i tyle.
  • #26 19736770
    koczis_ws
    Poziom 27  
    mpier napisał:
    czemu ma służyć ustawianie wyjścia w stan wysoki. Po co to robić?

    Po to żeby stworzyć opadające zbocze na linii sygnałowej dla zainicjowania czujnika. Bez tego odczyt danych nie jest prawidłowy. (oglądnij wykres z poprzedniego postu).
    A co nie działa? Twoja propozycja z #23
  • #27 19741258
    koczis_ws
    Poziom 27  
    Chyba będę potrzebował znowy pomocy :(
    Przyszedł wreszcie wyśietlacz (taki : https://botland.com.pl/wyswietlacze-alfanumer...ebieski-ze-zlaczami-justpi-5903351243131.html ). Podłączyłem go do mojego projektu, zainstalowałem odpowiednie biblioteki, ustawiłem kontrast i podświetlenie, dopisałem wyświetlanie testowego tekstu i niestety nic się nie wyświetla.

    Zdefiniowałe wyjścia w HD44780.h
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    ale nic z tego nie wychodzi.
    Jak mogę prawidłowo interpretować wyniki pomiaru temperarury?
  • #28 19742821
    mpier
    Poziom 29  
    Masz prawidłową komunikacją z DHT11 (bez dziwów jak w pierwej wiadomości), działający wyświetlacz pokazujący np. aktualny czas i dane z czujnika, i masz port szeregowy z informacjami "diagnostycznymi" typu bajty z czujnika i ewentualne błędy. Co nie działa? Wyświetlacz pokazuje głupoty, a na porcie szeregowym jest OK? Przed "konwersją", czy po?
  • #29 19742923
    koczis_ws
    Poziom 27  
    Kompilator czepia sie NAN i 1f. Jak wywaliłem NAN i 1f zmieniłem na 1 to na wyświetlaczu wyświetlał bzdury.
    Ale zrobiłem inaczej. Jeśli (b & 0x80) to do wartości temperatury dodaję 1 i przed nią na wyświetlaczu dodaję "-" i jest OK.
    Portu szeregowego narazie nie używam bo mam Win 10 i on nie chce współpracować z przejściówkami USB > RS232. Mam tekie 2, które współpracowały z Win 7 . Chyba będę musiał dokupić następny. Nie pomagaję wszelkie wskazówki i nowe drivery. Port niby jest widoczny w menadrzerze urządzeń, ale zero współpracy.
  • #30 19742992
    mpier
    Poziom 29  
    Nie wiem, kiedyś wystarczyło zrobić tak, ale teraz to pewnie zbyt proste:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dodano po 16 [minuty]:

    Możesz użyć wyświetlacza lcd testowo, 20 - 30 linii powinno spokojnie wystarczyć na podgląd danych z czujnika i ewentualne błędy, i pokazywanie co się aktualnie w programie dzieje.

Podsumowanie tematu

Dyskusja dotyczy problemów z odczytem danych z czujnika DHT11 przy użyciu mikrokontrolera Atmega 8 w języku C++. Użytkownik napotkał błędy związane z odczytem CRC oraz zerowe wartości temperatury i wilgotności. W odpowiedziach zasugerowano poprawki w kodzie, takie jak prawidłowe ustawienie F_CPU, zmiany w kolejności odczytu danych oraz dodanie opóźnienia między wywołaniami funkcji. Użytkownik zrealizował poprawki, co pozwoliło na uzyskanie poprawnych odczytów. W dalszej części dyskusji poruszono również kwestie związane z podłączeniem wyświetlacza LCD oraz problemami z komunikacją przez port szeregowy.
Podsumowanie wygenerowane przez model językowy.
REKLAMA