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

DS18B20 [BASCOM] - bez komend wait - jest rozwiązanie!

woszu 19 Paź 2009 20:24 3847 16
  • #1 7149357
    woszu
    Poziom 15  
    Witam.
    Napisałem obsługę 2 termometrów DS18B20 w Bascomie. Wszystko ładnie działa, ale...

    W procedurze trzeba chwile poczekać po odczytaniu danych z termometrów.
    Wygląda to tak:
    
    1wreset
    1wwrite &H55
    1wverify Dsid1(1)   
    1wwrite &HBE
    I1 = 1wread(2)
    1wreset
    1wwrite &H55
    1wverify Dsid2(1) 
    1wwrite &HBE
    I2 = 1wread(2)
    1wreset
    1wwrite &HCC
    1wwrite &H44
    Wait 1
    Tzewn = I2 / 16
    Twewn = I1 / 16
    Tw = Fusing(twewn , "#.#")
    Tz = Fusing(tzewn , "#.#")
    


    Jednak w gotowym programie nie mogę sobie pozwolić na czekanie 1s, więc zrobiłem tak, że w przerwaniu od zegara (co 1s) ustawiam zmienną, i wykorzystuję ją zamiast wait 1

    
    if sek = 0 then 
        1wreset
        1wwrite &H55
        1wverify Dsid1(1)   
        1wwrite &HBE
        I1 = 1wread(2)
        1wreset
        1wwrite &H55
        1wverify Dsid2(1) 
        1wwrite &HBE
        I2 = 1wread(2)
        1wreset
        1wwrite &HCC
        1wwrite &H44
    end if
    if sek = 1 then
        Tzewn = I2 / 16
        Twewn = I1 / 16
        Tw = Fusing(twewn , "#.#")
        Tz = Fusing(tzewn , "#.#")
    end if
    


    Niestety tak nie działa. Co prawda wyświetla temperaturę, ale tylko z jednego czujnika. Drugi pokazuje 85 stopni.... Czy nie obejdzie się bez tego wait 1? Procek nie może w tym czasie robić innych operacji?
  • #2 7149647
    wader_669
    Poziom 28  
    poczytaj moze note i helpa do bascoma. Totalnie w zlym miejscu wstawiles waita. Oczywiscie na przerwaniu tez jest zle.
    Pomiedzy komenda startu pomiaru a ponownym resetem i odczytaniu danych powinien byc wait.

    Juz nie mowiac, ze masz 2 bardzo podobne fragmenty kodu mozna by to rozwiazac w petli for
  • #3 7149681
    janbernat
    Poziom 38  
    A co robi to przerwanie od zegara?
  • #4 7150243
    dawid512
    Poziom 32  
    Po pierwsze to Ds bez opóźnienia (typowe 750ms) nie wyrobi z konwersją temp.
    Po drugie WYWAL i to szybko obsługę DS-a w przerwaniu. Rozumiem twój pomysł z opóźnieniem ale w przerwaniu zmieniaj tylko stan flagi a samą obsługę DS-a wstaw do pętli głównej.
  • #5 7150856
    woszu
    Poziom 15  
    dawid512 - a co ja napisałem? W przerwaniu ustawiam właśnie tylko tą zmienną (flagę). Obsługę termometru mam w pętli głównej.

    wader_669 - czyli to opóźnienie powinno być tak ?
    
    1wreset
    1wwrite &H55
    1wverify Dsid1(1)   
    1wwrite &HBE
    I1 = 1wread(2)
    1wreset
    1wwrite &H55
    1wverify Dsid2(1)
    1wwrite &HBE
    I2 = 1wread(2)
    waitms 750
    1wreset
    1wwrite &HCC
    1wwrite &H44
    Tzewn = I2 / 16
    Twewn = I1 / 16
    Tw = Fusing(twewn , "#.#")
    Tz = Fusing(tzewn , "#.#") 
    


    Jeżeli nie to mnie popraw proszę. Ale pomijając ten fakt, czy umieszczenie tej flagi (zmienianej co 1s) w tym miejscu rozwiąże problem? Bo głównie chodzi mi o to, czy da się obsłużyć DS-a bez używania komendy wait, bo jak wspomniałem, program musi być cały czas "w ruchu". Nie mogę też wykorzystać żadnego timera, bo wszystkie trzy zajęte. Jedyne co mam do dyspozycji to to przerwanie od zegara co 1s.


    Zaprogramowałem z tym opóźnieniem przed konwersją i dalej mi nie działa z tą flagą. Wyświetla tylko temperaturę z jednego czujnika, a na drugim 85 stopni...
  • #6 7154060
    woszu
    Poziom 15  
    Witam ponownie.
    Rozwiązałem problem.
    Poniżej przedstawiam kompletny program do obsługi dwóch czujników DS18B20 bez używania komendy waitms 750. Procek w tym czasie może robić co chce :)
    Program oczywiście łatwo można dostosować do dowolnej liczby czujników.

    
    '''''''''''''''''''''''''''''opis wejść'''''''''''''''''''''''''''''
    'temperatura      -> Portc.0
    'przerw od zegara -> Porte.7 (INT7)
    'LCD D4           -> Portc.1
    'LCD D5           -> Portc.2
    'LCD D6           -> Portc.3
    'LCD D7           -> Portc.4
    'LCD E            -> Portc.5
    'LCD Rs           -> Portc.6
    '''''''''''''''''''''''''''''''początek''''''''''''''''''''''''''''''''''''''''
    $regfile = "m64def.dat"
    $crystal = 16000000
    
    ''''''''''''''''''''''''''''konfiguracja LCD'''''''''''''''''''''''''''''''''''
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.1 , Db5 = Portc.2 , Db6 = Portc.3 , Db7 = Portc.4 , E = Portc.5 , Rs = Portc.6
    Cursor Off : Cls
    
    ''''''''''''''''''''''''''konfiguracja portów i przerwań''''''''''''''''''''''''''''''''''
    Config Portc = &B01111110
    Config Porte = &B00000000
    Config 1wire = Portc.0
    Enable Interrupts
    Eimsk = &B10000000                                          'enable int7
    Eifr = &B10000000
    Eicrb = &B00000000
    Eicrb = &B10000000                                          'int7 faling
    On Int7 Sekunda
    
    '''''''''''''''''''''''''deklaracja zmiennych''''''''''''''''''''''''''''''''''
    Dim Dsid1(8) As Byte
    Dim Dsid2(8) As Byte
    Dim Sek As Byte
    Dim I1 As Integer
    Dim I2 As Integer
    Dim Twewn As Single
    Dim Tzewn As Single
    Dim Tz As String * 5
    Dim Tw As String * 5
    
    Deflcdchar 0 , 8 , 20 , 11 , 4 , 4 , 4 , 3 , 32             'znak stopnia Celsjusza
    
    Cls
    Dsid1(1) = 1wsearchfirst()                                  'Znajdź pierwszy czujnik podpięty do portu
    Dsid2(1) = 1wsearchnext()                                   'Znajdź kolejny czujnik podpięty do portu
    '''''''''''''''''''''''''pętla główna''''''''''''''''''''''''''''''''''
    Do
        If Sek > 3 Then Sek = 0                           'zerowanie zmiennej, aby nie zwiększała się w nieskończoność
    
        If Sek = 1 Then                                         'odczytywanie czasu co 1 sekunde
           Sek = 2                                              'zmiana wartości zmiennej, aby na razie tutaj nie wchodził
           1wreset
           1wwrite &H55
           1wverify Dsid1(1)                            'wysyłamy adres pierwszego czujnika
           1wwrite &HBE
           I1 = 1wread(2)
        '---------------------------------
           1wreset
           1wwrite &H55
           1wverify Dsid2(1)                            'wysylam adres drugiego czujnika
           1wwrite &HBE
           I2 = 1wread(2)
       End If
       If Sek = 3 Then                                          'wyswietlanie czasu co 2 sekunde  (zeby nie dawac waitms750)
           1wreset
           1wwrite &HCC                                      'konwersja temp dla wszystkich dsow
           1wwrite &H44
           Tzewn = I1 / 16
           Twewn = I2 / 16
           Tw = Fusing(twewn , "#.#")
           Tz = Fusing(tzewn , "#.#")
           Sek = 0                                              'zerowanie zmiennej po konwersji temp, aby program mógł w kolejnej sekundzie wejść do czytania danych z DS-ów
       End If
       Locate 1 , 1
       Lcd "Tw: " ; Tw ; Chr(0) ; "          "
       Locate 2 , 1
       Lcd "Tz: " ; Tz ; Chr(0) ; "          "
    
    Loop
    
    '''''''''''''''''''''''sekunda - przerwanie od zegara''''''''''''''''''''''''''
    Sekunda:
       Incr Sek
    Return
    
    End
    
  • #7 7155002
    wader_669
    Poziom 28  
    cos mi sie nadal nie zgadza z tym odczytem
    https://www.elektroda.pl/rtvforum/topic1419156.html
    tu masz link do kodu z komentami poczytaj je i jeszcze raz sie zastanow

    Dodano po 3 [minuty]:

    moim zdaniem nadal masz odczytywanie czyli 1wread(2) odrazu po nadani komendy czytania temp.
    Nie pamietam dokladnie jak to sie robilo (dawno temu to byla jak sie bawilem 1 wire). Poczytaj helpa i dokumentacje tych czujnikow
  • #8 7155275
    woszu
    Poziom 15  
    Wader, w większości programów które znalazłem, nawet to czekanie waitms 750 było na końcu tak jak miałem wcześniej. Może i coś jest nie tak z tym kodem, ale nie będę się zastanawiał co, skoro działa bez żadnego przesuwania bajtów, itp. Nawet nie robię żadnej specjalnej obsługi wyświetlania temperatur ujemnych, a jakoś je wyświetla :)
  • #9 7155739
    mirekk36
    Poziom 42  
    woszu -> proponuję - zastanów się nad tym dokładnie - bo na razie - przypadkiem ci działa - ale sam się zdziwisz gdy zaczną ci wskakiwać jakieś temperatury z kosmosu....

    twój pierwszy przykład był całkowicie zły bo- generalnie robiłeś to tak:

    Cytat:
    1. wysyłasz adresz czujnika nr.1
    2. weryfikujesz czujnik nr.1
    3. odczytujesz temperaturę z czujnika nr.1

    4. wysyłasz adresz czujnika nr.1
    5. weryfikujesz czujnik nr.2
    6. odczytujesz temperaturę z czujnika nr.2

    7. wysyłasz rozkaz dokonania konwersji dla wszystkich czujników !!!

    8. tu bez sensu czekasz 1 sekundę czy tam 750ms


    dzięki temu po pierwszym przebiegu takiej pętli po włączeniu - zawsze pokazuje ci się na moment prawdopodobnie temperatura 85st (czyli tak jak po resecie czujnika) a później zakładając, że są na krótkim kablu - temperatury już zaczynają ci się pojawiać bo dochodzi do sytuacji, że (podam przykład już na 1 czujniku)

    Cytat:
    1. odczytujesz temperaturę
    2. dajesz rozkaz pomiaru
    3. czekasz 750ms


    czyli jest w dalszej części programu już "prawie" tak jak powinno się to robić czyli:

    Cytat:
    początek pętli:

    1. dajesz rozkaz odczytu do czujników
    2. czekasz 750ms - to jest po to żeby czujniki zdążyły wykonać tę operację a nie "tak sobie"
    3. odczytujesz dopiero wtedy temperaturę po konwersji

    4. dokonujesz przeliczeń dododnych do wyświetlenia na jakimś wyświetlaczu

    koniec pętli


    tak więc postaraj się zapamiętać o co tu chodzi i skąd się bierze to oczekiwanie 750ms i do czego ono jest . A jeśli piszesz wyżej , że w większości programów to oczekiwanie 750ms było na końcu - to korzystałeś akurat z najgorszych przykładów i stąd twoje początkowe niepowodzenia. Fajnie, że doszedłeś na swoje potrzeby jak rozwiązać to bez żadnych Wait'ów - bo właśnie zawsze tak to się mniej więcej powinno robić

    reasumując ten wątek - mierząc temperaturę z kilku czujników powinno być ładnie tak:

    Cytat:
    1. wysyłasz rozkaz pomiaru do wszystkich czujników

    2. czekasz w dowolny sposób aż czujniki dokonają w swoich wnętrzach pomiarów - minimum 750ms dla rozdzielczości 12bitów

    3. wysyłasz adres 1go czujnika
    4. weryfikujesz go
    5. sprawdzasz CRC (choć to można pominąć na krótkich kablach często)
    6. odczytujesz z niego ładną temperaturkę

    7. wysyłasz adres 2go czujnika
    8. weryfikujesz go
    9. sprawdzasz CRC (choć to można pominąć na krótkich kablach często)
    10. odczytujesz z niego ładną temperaturkę

    11. przeliczasz i wyświetlasz temperatury na wyświetlaczu

    4.

    ..... druga sprawa to, że musisz wziąć pod uwagę - tak mi sie wydaje - fakt, że kiedyś któryś czujnik może się uszkodzić już nie ważne z jakich powodów. A wtedy twoja koncepcja

    Cls 
    Dsid1(1) = 1wsearchfirst()                                  'Znajdź pierwszy czujnik podpięty do portu 
    Dsid2(1) = 1wsearchnext()                                   'Znajdź kolejny czujnik podpięty do portu 
    '''''''''''''''''''''''''pętla główna'''''''''''''''''''''''''''''''''' 
    Do 


    może wziąć w łeb - bo może dojść do zmiany kolejności czujników w programie. One są sortowane wg ich numerów ID. Więc może się zdarzyć, że nowy czujnik (ten wymieniony) wskoczy na pierwsze miejsce) a wtedy np jeśli masz pomiar temperatury wewnątrz i na zewnątrz - to nagle wszystko się zamieni na wyświetlaczu ;) - czyli wewnątrz będziesz miał temperaturę na zewnątrz i odwrotnie dla drugiego czujnika

    pogłówkuj więc jeszcze nad sposobem , który będzie umożliwiał czy to za pomocą MENU, czy za pomocą innego mechanizmu nawet poprzez zapisanie w EEPROM na sztywno ich numerów - ale utrzymanie tej zgodności. Bo gdy urządzonko popracuje rok czy dwa lata a później będziesz ot po prostu musiał wymienić czujnik to przyjdzie ci albo - zmienić kod programu (a zapewne już dawno zaginie) - albo fizycznie powyrywać czujniki ze swoich dotychczasowych miejsc i je pozamieniać ;)

    oczywiście nie jest to jakiś kosmiczny problem - ale lepiej zwracaj uwagę - jak coś się powinno robić a nie na cudze programy, które są źle napisane (bo takich w necie bywa sporo albo najwięcej)
  • #10 7155770
    woszu
    Poziom 15  
    dzięki za porady, postaram się pozmieniać żeby było tak jak należy.
  • #11 7155934
    Marianekk
    Poziom 13  
    mirekk36, a czy mógłbyś wrzucić prawidłowy kod obsługi dwóch czujników? Bo faktycznie większość przykładów z forum nie wygląda na dobrze napisaną wg Twoich uwag.
  • #12 7155953
    mirekk36
    Poziom 42  
    Ciężko mi wrzucić prawidłowy kod bo już dosyć dawno nie piszę nic w Bascomie.....

    ale wystarczy że w tej kolejności jak podałem zastosujesz dokładnie te polecenia jakie opisał powyżej autor - to ci zadziała prawidłowo

    warto też skorzystać z dowolnych rozwiązań, które eliminują polecenia Wait czy Waitms

    a druga sprawa - to ja nie potwierdziłbym, że większość przedstawionych przykładów jest źle napisanych - wg mnie jest odwrotnie - tylko trza poszukać - bo rzeczywiście jest ich tysiące ;)

    Dodano po 3 [minuty]:

    poza tym warto samemu próbować i dać jakiś wkład własny (tzn wiele prób w celu osiągnięcia pełnego sukcesu) tylko to pozwoli ci się tak na prawdę nauczyć danego tematu i zdobyć w nim doświadczenie

    ja niedawno od samego początku do końca przebrnąłem temat obsługi 1wire tych czujników. Fakt zajęło mi to troszkę czasu tym bardziej, że cały czas dopiero uczę się C. Ale dzięki temu w końcu powstał fajny projekcik ;)

    https://www.elektroda.pl/rtvforum/topic1430008.html

    ale to samo można osiągnąć w Bascomie - tylko trzeba chcieć się tym "pobawić"
  • #13 7156084
    woszu
    Poziom 15  
    Ja wzorowałem się na tym temacie (dla 4 czujników):
    https://www.elektroda.pl/rtvforum/topic811706.html

    Tam właśnie jest to wait po konwersji, a reszta tak jak mam. 9 stron tematu i nikt nie pisał że źle:) I temu podobnych tematów jest na elektrodzie sporo.
    Skoro są źle pisane, to skąd wziąć te poprawne, jak ktoś nie siedzi głęboko w temacie 1-wire?
    Ja wiem że najlepiej próbować samemu, ale gorzej gdy nie ma na to czasu i trzeba wstawić kawałek gotowego kodu.
  • #14 7156119
    mirekk36
    Poziom 42  
    woszu napisał:

    Ja wiem że najlepiej próbować samemu, ale gorzej gdy nie ma na to czasu i trzeba wstawić kawałek gotowego kodu.


    no tak - sam pamiętam jak kiedyś uczyłem się Bascoma - pewnie, że warto czasem wystartować nawet na jakimkolwiek kawałku czyjegoś kodu, żeby cokolwiek ruszyło - ale później warto zacząć to analizować dokładniej.

    Fakt w tym kodzie też autor postu zrobił Wait w nieciekwaym miejscu ;) .... tzn już mówiłem - wtedy problem objawi się tylko przy pierwszym odpaleniu i pokażą się na początku temperatury 85st C.... no ale o tym już autor nie wspomniał - bo po co skoro dalej jakoś działa

    mnie to bardzo przeszkadzało - w czasie gdy zaczynałem przygodę z DS'ami w Bascomie

    dlatego chcąc nie chcąc - zacząłem temat "macać" od podstaw

    tak więc - chyba jasnym wydaje się schemat, że (tak jak już pisałem powyżej):

    Cytat:
    1. Wysyłamy polecenie konwersji do jednego lub wielu czujników

    2. czekamy minimum tyle ms ile w nocie PDF jest napisane w zależności od trybu pracy czujnika (jeśli 12bit to min 750ms)

    3. gdy już jesteśmy pewni, że czujniki dokonały wewnątrz pomiaru to odczytujemy temperaturę i tu już bez żadnego czekania - transformujemy ją do potrzeb swojego wyświetlacza


    teraz jaśniej?
  • #15 7156189
    woszu
    Poziom 15  
    Czyli ta kolejność powinna być taka?

    
    1wreset
    1wwrite &HCC
    1wwrite &H44
    Waitms 750
    
    1wreset    
    1wwrite &H55       
    1wverify Dsid1(1)   
    1wwrite &HBE
    I1 = 1wread(2)
    
    1wreset
    1wwrite &H55
    1wverify Dsid2(1)
    1wwrite &HBE
    I2 = 1wread(2)
    
    Tzewn = I2 / 16
    Twewn = I1 / 16
    Tw = Fusing(twewn , "#.#")
    Tz = Fusing(tzewn , "#.#") 
    
  • Pomocny post
    #16 7156215
    mirekk36
    Poziom 42  
    oooooo to chodzi ;)

    to taki szkielet - ale na podstawie tego sam wiesz już jak sobie poradzić z tym tyle że bez Wait'a

    dodam jeszcze, że sam fragment:

    1wreset 
    1wwrite &HCC 
    1wwrite &H44 
    Waitms 750 


    warto zapuścić jeszcze przed wejściem wtedy w pętlę główną żeby już mieć gotową pierwszą zmierzoną temperaturę w czujnikach po resecie - gdyby przypadkiem najpierw trafiło ci się polecenie odczytu

    ale generalnie o to chodzi
  • #17 7156239
    woszu
    Poziom 15  
    Ok. zrozumiałem:) Po prostu wcześniej źle pojmowałem pojęcie konwersji (1write &H44) :)

    Czyli podsumowując ten cały kod powinno chyba być tak:

    
    '''''''''''''''''''''''''''''opis wejść'''''''''''''''''''''''''''''
    'temperatura      -> Portc.0
    'przerw od zegara -> Porte.7 (INT7)
    'LCD D4           -> Portc.1
    'LCD D5           -> Portc.2
    'LCD D6           -> Portc.3
    'LCD D7           -> Portc.4
    'LCD E            -> Portc.5
    'LCD Rs           -> Portc.6
    '''''''''''''''''''''''''''''''początek''''''''''''''''''''''''''''''''''''''''
    $regfile = "m64def.dat"
    $crystal = 16000000
    
    ''''''''''''''''''''''''''''konfiguracja LCD'''''''''''''''''''''''''''''''''''
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.1 , Db5 = Portc.2 , Db6 = Portc.3 , Db7 = Portc.4 , E = Portc.5 , Rs = Portc.6
    Cursor Off : Cls
    
    ''''''''''''''''''''''''''konfiguracja portów i przerwań''''''''''''''''''''''''''''''''''
    Config Portc = &B01111110
    Config Porte = &B00000000
    Config 1wire = Portc.0
    Enable Interrupts
    Eimsk = &B10000000                                         'enable int7
    Eifr = &B10000000
    Eicrb = &B00000000
    Eicrb = &B10000000                                          'int7 faling
    On Int7 Sekunda
    
    '''''''''''''''''''''''''deklaracja zmiennych''''''''''''''''''''''''''''''''''
    Dim Dsid1(8) As Byte
    Dim Dsid2(8) As Byte
    Dim Sek As Byte
    Dim I1 As Integer
    Dim I2 As Integer
    Dim Twewn As Single
    Dim Tzewn As Single
    Dim Tz As String * 5
    Dim Tw As String * 5
    
    Deflcdchar 0 , 8 , 20 , 11 , 4 , 4 , 4 , 3 , 32          'znak stopnia Celsjusza
    
    Cls
    Dsid1(1) = 1wsearchfirst()                                  'Znajdź pierwszy czujnik podpięty do portu
    Dsid2(1) = 1wsearchnext()                                 'Znajdź kolejny czujnik podpięty do portu
    
    
    1wreset
    1wwrite &HCC                                                   'konwersja temp dla wszystkich dsow
    1wwrite &H44  
    
    
    '''''''''''''''''''''''''pętla główna''''''''''''''''''''''''''''''''''
    Do
        If Sek > 3 Then Sek = 0                           'zerowanie zmiennej, aby nie zwiększała się w nieskończoność
    
        If Sek = 1 Then                                      'odczytywanie czasu co 1 sekunde
           Sek = 2                             'zmiana wartości zmiennej, aby na razie tutaj nie wchodził
           1wreset
           1wwrite &HCC                                      'konwersja temp dla wszystkich dsow
           1wwrite &H44     
       End If
       If Sek = 3 Then             'wyswietlanie czasu co 2 sekunde  (zeby nie dawac waitms750)
           1wreset
           1wwrite &H55
           1wverify Dsid1(1)                            'wysyłamy adres pierwszego czujnika
           1wwrite &HBE
           I1 = 1wread(2)
        '---------------------------------
           1wreset
           1wwrite &H55
           1wverify Dsid2(1)                            'wysylam adres drugiego czujnika
           1wwrite &HBE
           I2 = 1wread(2)
           Tzewn = I1 / 16
           Twewn = I2 / 16
           Tw = Fusing(twewn , "#.#")
           Tz = Fusing(tzewn , "#.#")
           Sek = 0                 'zerowanie zmiennej po konwersji temp, aby program mógł w kolejnej sekundzie wejść do czytania danych z DS-ów
       End If
       Locate 1 , 1
       Lcd "Tw: " ; Tw ; Chr(0) ; "          "
       Locate 2 , 1
       Lcd "Tz: " ; Tz ; Chr(0) ; "          "
    
    Loop
    
    '''''''''''''''''''''''sekunda - przerwanie od zegara''''''''''''''''''''''''''
    Sekunda:
       Incr Sek
    Return
    
    End 
    
REKLAMA