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

ds18b20 - Obsługa 1wire - diagnoza funkcji odbierania pisania

13 Lip 2015 21:12 1287 23
  • Poziom 15  
    Cześć.

    Wielokrotnie już elektroda ratowała mnie pomocną ręką, mam nadzieje, że i tak dziś będzie. Staram sie napisać własną obsługę dla ds18b20 dla atmega8. Sporządziłem wstępny kod "biblioteki" (gdy zacznie działać zrefaktoryzuje kod celem jej uogólnienia). Jak narazie jedyna funkcja która mi działa to reset i presence pulse. Dalej w zasadzie odczytuje same zera. Wrzucam kod moich funkcji i ich wykorzystanie w głównej pętli programu. Wydaje mi sie, że kod implementuje szczeliny odczytu i zapisu jak mówi dokumentacja. Byłbym wdzięczny za analize mojego kodu i komentarz. Nie sugerowałem się gotowcami - jest to moja praca wynikająca z interpretacjii noty czujnika.

    Kod bilbioteki:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    pętla programu

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Czujnik podłączony 3 pinami według noty do nóżki PB0. Z góry dzięki za pomoc i poświęcony czas.
  • MetalworkMetalwork
  • Pomocny post
    Poziom 40  
    Musisz operować rejestrem DDR ustawiając stany na linii. Inaczej ustawiasz bardzo silny stan wysoki na linii i być może DS nie jest w stanie zewrzeć takiej linii do masy a nawet możesz uszkodzić uC i DSa. W funkcji read() chyba pomyliłeś delaya ms z us. Jeszcze co do typów zmiennych - pracujesz na procesorze 8-mio bitowym dla którego optymalnym typem jest (unsigned) char. Więc jeśli nie musisz to nie używaj zmiennych int.
  • MetalworkMetalwork
  • Pomocny post
    Poziom 18  
    Zapis lub czytanie bitu "1", ma się odbyć w czasie do 15us.


    Cytat:
    _delay_ms(1); //conajmniej 1us na sygnal do do termometru, że ma nadawać
    w tej lini prawidłowy jest tylko komentarz :)
  • Poziom 15  
    @excray

    Serdeczne dzięki za poświęcony czas na analize kodu. Rozumiem co do lini DDR - steruje tym, czy nóżka jest wjściem czy wyjściem, natomiast pullup podciąga mi do stanu wysokiego zawsze - gdy ds coś mówi to zwiera do masy wywierając stan niski na ten czas. W takim razie prócz sterowania rejestrem DDR rozumiem, że wyłączyć wewnętrzny rezystor zwierający do VCC czy go włączyć ??

    Co do typów - czy uint8_t nie jest równe z unsigned char ??

    Dzięki za odpowiedź !
  • Pomocny post
    Poziom 40  
    Na PORTx ustawiasz jednorazowo 0 i nie zmieniasz a DDRem sterujesz: wejście - stan wysoki zapewniony przez zewnętrzny rezystor podciągający. Wyjście - stan niski wymuszony przez 0 na PORTx.
    lukas_gab napisał:
    Co do typów - czy uint8_t nie jest równe z unsigned char ??

    Jest. Ale int już nie jest.
  • Poziom 15  
    slx napisał:
    Zapis lub czytanie bitu "1", ma się odbyć w czasie do 15us.


    Cytat:
    _delay_ms(1); //conajmniej 1us na sygnal do do termometru, że ma nadawać
    w tej lini prawidłowy jest tylko komentarz :)


    Hmmm, a nie jest tak, że przy zapisie 0 ds próbkuje typowo 15 us a maksymalnie do 45 us, po czym trzeba zwolnić, żeby podciągnąć do VCC, natomiast przy zapisie 1 znów maksymalnie próbkuje do 45us, a trzymać stan wysoki mozna do nieskończoności ?? Patrze na wykres przejść stanów ze strony 16 noty.

    Co do błędu ms <-> us macie rację, poprawie to i przerobię kod na sterowanie kierunkiem, tylko potrzbuję info co zrobić z wewnętrznymi pullupami, oraz co z tym czasem próbkowania, bo nie wiem, czy ja mam racje czy jednak źle rozumiem note i kolega ma racje.

    Dzięki za zainteresowanie !

    Dodano po 2 [minuty]:

    excray napisał:
    Na PORTx ustawiasz jednorazowo 0 i nie zmieniasz a DDRem sterujesz: wejście - stan wysoki zapewniony przez zewnętrzny rezystor podciągający. Wyjście - stan niski wymuszony przez 0 na PORTx.
    lukas_gab napisał:
    Co do typów - czy uint8_t nie jest równe z unsigned char ??

    Jest. Ale int już nie jest.


    Ok, to kwestia pullupa rozwiązana, dziękuję bardzo ! Co do int w zmiennych iteracyjnych - macie racje, naleciałość od pisania dla PC.

    Teraz została kwestia czasów przejść i ich interpetacji, a na pewno przerobię kod sterujący stanami.
  • Poziom 40  
    lukas_gab napisał:
    tylko potrzbuję info co zrobić z wewnętrznymi pullupami,

    Kolego a co masz niby robić z wewnętrznymi pullupami skoro PORT masz ustawiony na 0? Spójrz do DSa i zobacz czy w ogóle możliwe jest uruchomienie podciągania w momencie gdy port jest wyzerowany.
  • Poziom 15  
    excray napisał:
    lukas_gab napisał:
    tylko potrzbuję info co zrobić z wewnętrznymi pullupami,

    Kolego a co masz niby robić z wewnętrznymi pullupami skoro PORT masz ustawiony na 0? Spójrz do DSa i zobacz czy w ogóle możliwe jest uruchomienie podciągania w momencie gdy port jest wyzerowany.


    Wybacz, ale pisząc to nie widziałem poprzedniej odpowiedzi. Gdy ją zobaczyłem dodałem komentarz - jednak chyba teraz Ty go nie zobaczyłeś ;) Kwestia pullupów jest zrozumiała i rozwiązana. Dzięki za sugestie !
  • Pomocny post
    Poziom 40  
    Funkcje write1 i write0 sa bardzo podobne i wykorzystywane tylko przez SendByte. Lepiej byłoby Ci je wrzucić do środka funkcji SendByte oszczędzając w ten sposób miejsca i czasu. W funkcji reset_pulse masz na początku bardzo długi delay - 250ms. Moim zdaniem do usunięcia. Ponadto w funkcji reset_pulse zanim ustawisz stan niski mógłbyś dodatkowo sprawdzić czy linia jest w stanie wysokim - wykrycie ewentualnego zwarcia na linii.
  • Poziom 15  
    Dzieki za podpowiedzi. Przerobiłem kod wedłóg waszych sugestii i .. przestała działac funkcja inicjująca ds18b20. Przeanalizowałem DS i kod i by łem pewien, ze jest dobrze. No to sprawdziłem miernikiem i widziałem, że nigdy nie było stanu wysokiego - wiem, że miernik, zwłaszcza kiepski wolniej reaguje, ale mam na niego porpawkę i mniej więcej wiem, do jakiego momntu wykryje wzrost napięcia i wychodzilo mi, że jest to za mało - jak sie nie ma analizatora to trzeba opierać sie na takich znachorskich metodach. W tym momencie mnie olśniło ! Komunikuje się z Rpi i właśnie nim programuje atmege i w związku z tym zasilam to przez 3,3 V!. Oczywiście pullup 4,7KOhm to za dużo, więc zredukowałem do 2,2KOhm i reset i presence pulse zaczęło działać ok. Teraz mam problem chyba z zapisem lub odczytem. Obecnie zawsze po sekwencji jak w pierwszym poście dostaję temp. -0.1 *. Zerkniecie raz jeszcze i może coś się wam rzuci ?? Dzieki wielkie z góry !

    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Moderator Mikrokontrolery Projektowanie
    Po kolei:
    - w reset_pulse wysyłasz coś przez USART, wysłanie tego trochę trwa, w zależności od bitrate może trwać całkiem długo, co rujnuje timingi...
    - w write - początkiem nowej ramki jest krótki impuls ujemny. Może on trwać 1-2 us, to wystarczy. Więc jeśli nadajesz 0 to zrób 0 przez cały czas trwania ramki (prawie 60 us), a jeśli jeden, to po 1-2 us impulsu startowego zmień stan od razu na 1, a nie czekaj kolejnych kilkanaście us.
    - unikaj na AVR operacji typu 1<<i - moga być piekielnie kosztowne.
    A na koniec - zapomnij o 1-wire na delay, jak się przeniesiesz na ARMa też to będziesz robił na delay? Do tego celu używa się USART (lub jak woli kol. BlueDraco - timera).
    A na koniec - użyj symulatora z Atmel Studio, wraz z zapisem stanu portu będziesz dokładnie wiedział ile trwają twoje timingi i gdzie potencjalnie jest problem.
  • Poziom 15  
    tmf napisał:
    Po kolei:
    - w reset_pulse wysyłasz coś przez USART, wysłanie tego trochę trwa, w zależności od bitrate może trwać całkiem długo, co rujnuje timingi...
    - w write - początkiem nowej ramki jest krótki impuls ujemny. Może on trwać 1-2 us, to wystarczy. Więc jeśli nadajesz 0 to zrób 0 przez cały czas trwania ramki (prawie 60 us), a jeśli jeden, to po 1-2 us impulsu startowego zmień stan od razu na 1, a nie czekaj kolejnych kilkanaście us.
    - unikaj na AVR operacji typu 1<<i - moga być piekielnie kosztowne.
    A na koniec - zapomnij o 1-wire na delay, jak się przeniesiesz na ARMa też to będziesz robił na delay? Do tego celu używa się USART (lub jak woli kol. BlueDraco - timera).
    A na koniec - użyj symulatora z Atmel Studio, wraz z zapisem stanu portu będziesz dokładnie wiedział ile trwają twoje timingi i gdzie potencjalnie jest problem.


    1 - faktycznie zaraz sprawdzę,czy to pomoze
    2 - to juz sam zauwazylem, wlasnie testuje
    3 -a czym sie różnic 1<<i od 1<<PB0 ??
    4 -USART do 1 wire ?? możesz przbliżyć bo nie mam pojęcia o czym piszesz.
    5 - avrstudio dostępne jest na linuxa ?
  • Poziom 38  
    Cytat:
    5 - avrstudio dostępne jest na linuxa ?

    Atmelstudio nie. Ale może akurat pod Wine działa, nie sprawdzałem osobiście, bo jednak na linuksie mam Eclipse. AVR studio - szczerze tutaj nie wiem, bo miałem to tylko w wersji 4 i z pewnością w tym przypadku Eclipse tak czy siak było wystarczające na Linuksie.
    Cytat:
    4 -USART do 1 wire ?? możesz przbliżyć bo nie mam pojęcia o czym piszesz.

    To przeczytaj kolego choćby odpowiedni dokument atmela temu poświęcony. W przybliżeniu - odpowiednio manipulując baud rate i zawartością bufora zapisu/odczytu uart można zrealizować pół-sprzętową obsługe I2C ze znacznie zmniejszonym narzutem na czas procesora względem bit bang (i podejrzewam nieco wygodniej niż rozwiązanie z timerem).
    Cytat:
    3 -a czym sie różnic 1<<i od 1<<PB0 ??

    Tym samym co przesunięcie 1 o stałą (czyli coś co sam preprocesor wyliczy i podstawi konkretną wartość już przy kompilacji), a przesunięcie 1 o zmienną. Dwie różne rzeczy. Ja w takiej sytuacji wysyłam najstarszy bit i przesuwam całą wartość wysyłaną zawsze o 1 bit (czyli w drugim przebiegu wysyłam 7 bit, który stał się 8, w trzecim przebiegu wysyłam 6 bit, który stał się najpierw 7, a później 8 ... itd). Chyba nawet daje to wtedy najprostszy kod.
  • Poziom 15  
    Po zmianie według sugestii nic sie nie zmieniło... Nawet porozwijałem pętle :

    Kod: c
    Zaloguj się, aby zobaczyć kod


    kod odczytujący to :

    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Poziom 38  
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Dodam, że to kosztuje cię trochę KB kodu, sporo pamięci i sporo cykli, gdy wystarczy użyć, albo notyfikacji stałoprzecinkowej (fixed point) // nota bene u mnie mimo --fixed-point-enable najzwyczajniej NIE DZIAŁA (kompilator pluje się o nierozpoznany typ _Accum), albo rozbić wynik na część całkowitoliczbową i ułamkową (bo przecinek się nie przesuwa) i łączyć dopiero przy wyświetlaniu albo tworzeniu stringa w buforze.
  • Poziom 15  
    tronics napisał:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Dodam, że to kosztuje cię trochę KB kodu, sporo pamięci i sporo cykli, gdy wystarczy użyć, albo notyfikacji stałoprzecinkowej (fixed point) // nota bene u mnie mimo --fixed-point-enable najzwyczajniej NIE DZIAŁA (kompilator pluje się o nierozpoznany typ _Accum), albo rozbić wynik na część całkowitoliczbową i ułamkową (bo przecinek się nie przesuwa) i łączyć dopiero przy wyświetlaniu albo tworzeniu stringa w buforze.


    Wiem. To tylko w celach debugu dla wygody. Zmienię to w finalnej aplikacji jednak obecnie nie ma to wpływu na obsługę ds18b20
  • Poziom 38  
    W Atmelstudio są bodajże 2 przykłady podejścia do obsługi 1-wire (właśnie wymieniony bitbanging oraz uart-style). Są to przykładowe projekty z obsługą DS18x20 i wyświetlacza na KS0108. Jeśli kolega ma chęć poznać mechanikę 1wire na uart to taki przykładowy kod będzie wystarczająco dobry, żeby podstawy zrozumieć. A jeśli chodzi o ten konkretny przypadek - niestety nie mam już swoich plików do obsługi 1wire - wiem, że napotkałem na ten sam problem wtedy. Dodam tylko, że rezultat -0.1°C to iirc same jedynki. Dostawałem go także przy DS18B20@FT232RL jeśli DS miał słaby styk na Vcc przy 3 żyłowym podpięciu.
  • Poziom 15  
    Hmm faktycznie są to same jedyneczki ... W takim razie mam 3 możliwości.

    1 DS18B20 nie nadaje i pullup trzyma cały czas stan Hi.
    2 DS18B20 nadaje, ale nie umiem odczytać bitu/bajtu prawidłowo
    3 Niepoprawnie nadaje sygnał rozkazu.

    Żeby wyeliminować punkt 2, z założeniem, że DS jest sprawny więc 1 odpada i że nadaje prawidłowo, będę po wysłaniu rozkazu próbkował bo bicie i sprawdzę, czy dorwę na długości całej pamięci 9 bajtów jakiś stan Lo. Jak tak to okaże się, że dobrze odbieram bit a potem to się zobaczy gdzie utknę ...

    Spróbuję dorwać jakiś symulator na linuxa, i chyba na drugim komputerze zainstaluje visual avr, skoro są tam fajne przykłady i może porównam mój kod i kod atmela. Odezwę sie wieczorem.
  • Poziom 38  
    W zasadzie się pomyliłem, przykładowe kody są z ASF głównie dla platform rozwojowych, przykłady o jakich pisałem pochodzą z książek kolego tmf (Tomasz Francuz). Nie wiem czy jest "legalne" ściągnięcie bez nabycia książki ... jakby co ftp helionu.
  • Moderator Mikrokontrolery Projektowanie
    tronics napisał:
    Nie wiem czy jest "legalne" ściągnięcie bez nabycia książki ... jakby co ftp helionu.

    Tomek zawsze namawia do pobierania, a według prawa można to robić bez problemu, byle ich nie rozpowszechniać bez ich zgody :)
  • Poziom 15  
    Cześć. Dzięki za podpowiedzi ! Już dorwałem kody Tomka i je przeanalizuje. Jak wspomniałem reset i presence pulse działa jak talala. Co do reszty - zauważyłem, że mój kody odbiera jakieś stany niskie w szczelinach read, ale narazie nie wiem jak to wygląda w czasie. Z dostępnych kodów w sieci, jedno moje arduino uno przerobiłem na trywialny analizator stanów logicznych, jednak problemem jest to, że przy rozdzielczości 1us mieszczę raptem troszkę ponad 1000 próbek co jest niewystarczające niestety.

    Przeglądnę kod Tomka (z którego z kolei równy gość, że zachęca do analizy kodów mimo, że nie zakupiłem książki). Porównam jego kod z moimi wypocinami. Ostatecznie posiadam jeszcze spartana 3 który pomięsci wielokrotnie więcej niż takie arduino ( ma on prócz bramek w fpga z których można porobić rejestry kość chyba 256 mb dram), więc może dorwę jakiś kod analizatora napisanego w vhdl, lub przypomnę sobie wiedzę z poprzedniego semestru i postaram sie napisać coś co będzie rejestrować kwant czasu i stan pinu... zawsze zostaje zakup jakiegoś klona saele z chin ...
  • Poziom 20  
    W Twoim przykladowym kodzie nie tylko są już bieżące problemy z zachowaniem czasu prawidłowych okien komunikacyjnych (jesli nie używasz uarta) ale wystąpią też inne przyszłe problemy z powodu popularnej implementacji "na skróty" jaką realizujesz.
    Pierwsza uwaga: jaki masz pullup'a na linii? Nie widzę w Twoim kodzie zapewnienia "silnej 1" najpóźniej 10us po rozkazie 0x44 (inicjacja konwersji). Zapewnienie "silnej 1" poprzez wstawianie na stałe silniejszego pullup'a niż zalecany 4.7k to proszenie się o późniejsze problemy opisane w wątku obok p.t. "Wiele czujników DS18B20 (Parasite Mode) [...]".
    Druga uwaga: dlaczego nie sprawdzasz CRC? Zdarzy Ci się w przyszłości implementacja komunikacji w środowisku z silnymi zakloceniami, bez CRC będziesz miał duże problemy z prawidłową interpretacją odczytanych danych z czujnika.
    Trzecia uwaga, o której już wspomniał jeden z szanownych przedpiśców: używasz delay'e, które blokują mcu. Będziesz miał z tym problem gdy użyjesz swojej biblioteki w jakimś bardziej zaawansowanym projekcie z wieloma innymi funkcjami oprócz odczytu temp. Zaprojektuj kod aby spelnił paradygmat maszyny stanów, uwolnisz mcu od blokujących go opóźnień.
  • Poziom 15  
    Silne 1 zapewniam przez rezystor połączony z linią danych i linią vcc. Co do sum crc - nie ma ich w tym kodzie podobnie jak wielu innych rzeczy - skoro miałem probem chociaż z odbiorem bajtu innego niż stałe "1" nie było mowy o liczeniu crc. Finalna aplikacja posiadać będzie sprawdzanie sum. Nie rozumiem, dlaczego mam problemy z zachowaniem czasu okien ?? tmf także używa w swoim kodzie delay - w zasadzie mimo, że pracowałem sam mamy podobny kod z tą różnicą, że tmf sprawdza wiecej błędów niż ja (jeszcze) oraz używa konstrukcji ATOMIC_BLOCK.UARTA nie mogę użyć, ponieważ wpinam sie nim w sieć z komputerem i innymi MCU. Co do delay i maszyny stanów - moim zdaniem to zupełnie co innego. Jeżeli zaimplementuje maszynę, a użyję delay na jedno wyjdzie. Jak już to powinienem zaimplementować nieblokujące funkcje czekania, ale to zakrawa o karuzelowanie "procesami", mniejsza, bo bezczynność MCU nie jest moim problemem, system jaki projektuje to rozproszona sieć MCU i będe się o to martwił jak obsłużę peryferia.

    Co do tematu - każdy kto w jakiś sposób pomógł mi i dołączył się do wykrycia kolejnego błędu - dałem znacznik "pomógł".

    Ostatecznie po wprowadzeniu waszych sugestii - czyli refaktoryzacja kodu, sterowanie jedynie wejsciem/wyjsciem bez wew. podciągnięcia Ostatecznie zostało jedno - w funkcji zapisu bitu nie zwalniałem magistrali po wysłaniu sygnału 0. Gdy to popawiłem wszystko zaczęło śmigać.
  • Poziom 20  
    lukas_gab napisał:
    Co do delay i maszyny stanów - moim zdaniem to zupełnie co innego. Jeżeli zaimplementuje maszynę, a użyję delay na jedno wyjdzie.


    Nie po to implementuje się maszynę stanów aby i tak używać delay, to jakiś nonsens.