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

Atmega16 DS18b20 Wyś. 4xLED LCD Prawie gotowiec

alarmowanie 04 Lut 2010 17:30 2748 11
  • #1 04 Lut 2010 17:30
    alarmowanie
    Poziom 9  

    Witam panowie od razu podkreślę że jeszcze uczę się bascoma więc proszę nie krzyczeć i nie usuwać tego postu do kosza
    Siedzę już nad tym 3 dzień i efekt mojej pracy nie najgorszy ale mam parę pytań po pewnych rzeczy nie rozumiem i nie mogę rozwiązać.
    Więc tak założeniem był pomiar temperatury przez ds18b20 wyświetlenie je na LCD i 4 wyświetlaczach 7 segmentowych LED oraz komunikacja z PC ale to później.
    Starałem się by kod był czytelny i dobrze opisany zerknijcie na niego i doradźcie jak go odchudzić i jak usunąć problem z pulsującym wyświetlaczem LCD, jak zakończę pracę wrzucę gotowy kod zapewne się komuś przyda





    Poprawiłem obliczenia pojedynczej cyfry lecz w zaznaczonej linijce wykrzyknikami pojawia się błąd i nie wiem dlaczego zmienna Znak jest zdeklarowana w ten sposób:

    Dim Znak as Bit

    a pojawia się komunikat:

    error:105 StoreBit error [0]


    Code:

     S = I / 16                                               ' podzielenie odczytu z 1wire /16 dlaczego




    !!!!!!!!!!!!!!!!!!!!!!!   If I < 0 then Znak = 1 else Znak = 0 end if !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!





       I = Abs(I)                                                  'teraz I jest dodatnie

       tempWord = I                                                'zapamiętanie I








    Code:


    $regfile = "m16def.dat"                                     ' dyrektywa procesora
    $crystal = 8000000                                          '  taktowanie


    Config Lcd = 16 * 2

    Config Lcdpin = Pin , Rs = Portd.2 , E = Portd.3 , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7       'konfiguracja wyświetlacza LCD

    Config 1wire = Portc.7                                      ' termometr ds18b20

    Config Timer0 = Timer , Prescale = 256                      'konfiguracja Timer0 jako timer z podziałem preskalera przez 256





    config portb = output                                       'konfiguracja segmentów
    config portc.1 = output                                     'konfiguracja wyświetlacza 1 jako wyjścia
    config portc.2 = output                                     'konfiguracja wyświetlacza 2 jako wyjścia
    config portc.3 = output                                     'konfiguracja wyświetlacza 3 jako wyjścia
    config portc.4 = output                                     'konfiguracja wyświetlacza 4 jako wyjścia

    W1 alias portc.1                                            'przypisanie nazwy
    W2 alias portc.2                                            'przypisanie nazwy
    W3 alias portc.3                                            'przypisanie nazwy
    W4 alias portc.4                                            'przypisanie nazwy





    Dim I As Integer                                            'zmienne do odczytu temp.
    Dim S As Single                                             'zmienna z temperaturą przed konwersją                                             '
    Dim T As String * 4                                         'zmienna z temperaturą po konwersji gotowa do wyświetlenia na LCD

    Dim tempWord as Word
    Dim Znak as Bit


    Dim A as Byte                                               'Zmienna 1 cyfry
    Dim A1 as Long
    Dim B as Byte                                               'zmienna 2 cyfry
    Dim B1 as Single
    Dim B2 as Long
    Dim C as Byte                                               'zmienna 3 cyfry
    Dim C1 as Single
    Dim D as Byte                                               'zmienna 4 cyfry
    Dim D1 as Byte
    Dim D2 as Byte

    Dim Nr_wysw As Byte                                         'zmienna określająca numer zapalonego wyświetlacza






    Enable Interrupts                                           'odblokowanie globalnego systemu przerwań
    Enable Timer0                                               'odblokowanie przerwania od przepełnienia Timer0
    Load Timer0 , 125                                           'załadowanie do licznika wartości początkowej 131, bo 256 - 125 = 131

    On Timer0 Mult_wysw                                         'przerwanie od przepełnienia Timer0‚ skok nastąpi do podprogramu Mult_wysw






    Do                                                          ' rozpoczęcie pętli głównego programu

       1wreset                                                  'reset 1wire
       1wwrite &HCC                                             'CC to rozkaz adresowy SKIP ROM pominięcie wyboru układu jeżeli mamy tylko 1 czujnik
       1wwrite &H44                                             '44 to start konwersji temperatury

       Waitms 750                                               ' opuźnienie

       1wreset                                                  'ponowny reset 1wire
       1wwrite &HCC                                             'CC to rozkaz adresowy SKIP ROM pominięcie wyboru układu jeżeli mamy tylko 1 czujnik
       1wwrite &HBE                                             'rozkaz funkcyjny polecenie odczytu DS18B20
       I = 1wread(2)                                            'zapisanie do zmiennej I 2 bajty pomiaru


       S = I / 16                                               ' podzielenie odczytu z 1wire /16 dlaczego

       If I < 0 then Znak = 1 else Znak = 0 end if

       I = Abs(I)                                                  'teraz I jest dodatnie

       tempWord = I                                                'zapamiętanie I

       Shift I , right , 4                                         'pozbycie się czterech bitów ułamkowych teraz I jest z zakresu 0-125  przesunięcie o 4 w prawo to to samo co dzielenie całkowite przez 16

       A = I

       A = A \ 100                                                 ' cyfra setki

       I = I Mod 100                                               ' I zawiera resztę z dzielenia przez 100

       B = I

       B = B \ 10                                                  ' cyfra dziesiątki

       I = I Mod 10                                                ' I zawiera resztę z dzielenia przez 10

       C = I                                                       ' cyfra jednostki

       I = tempWord                                                ' I znowu zawiera dodatnią liczbę

       Shift I, left, 12

       Shift I , right , 12                                        ' I zawiera tylko część po przecinku

       I = I*625

       I = I\1000

       D = I                                                       ' cyfra po przecinku


       T = Fusing(s , "###.#")                                  ' zmiana maski wyświetlania odczytu właściwej już tęperatury

       Locate 1 , 1                                             'ustawienie pozycji wyświetlania wartości (linia , odstęp)

       Lcd "Temp:" ; T ; Chr(0) ; "C"                           'wyświetlanie tęperatury

    Loop                                                        'Zakończenie pętli
    end                                                         'Zakończenie programu









    Mult_wysw:                                                  'podprogramu obsługi przerwania od przepełnienia Timer0 w którym odbywa się multipleksowanie

     Load Timer0 , 125                                          'załadowanie do licznika wartości początkowej

     Set W1                                                     'wygaszenie wyświetlacza 1
     Set W2                                                     'wygaszenie wyświetlacza 2
     Set W3                                                     'wygaszenie wyświetlacza 3
     Set W4                                                     'wygaszenie wyświetlacza 4

     Select Case Nr_wysw                                        'w zależności od wartości Nr_wysw, wykonaj:

      Case 0:                                                   'gdy Nr_wysw = 0, to
      PortB = Lookup(A , Cyfry)                                 'wywołanie procedury pobierającej z tablicy kod znaku dla wartości A
       Reset W1                                                 'włączenie wyświetlacza 1

      Case 1:                                                   'gdy Nr_wysw = 1, to
      PortB = Lookup(B , Cyfry)                                 'wywołanie procedury pobierającej z tablicy kod znaku dla wartości B
       Reset W2                                                 'włączenie wyświetlacza 2

      Case 2:                                                   'gdy Nr_wysw = 2, to
      PortB = Lookup(C , Cyfry)                                 'wywołanie procedury pobierającej z tablicy kod znaku dla wartości C
       Reset W3                                                 'włączenie wyświetlacza 3

         Case 3:                                                'gdy Nr_wysw = 3, to
      PortB = Lookup(D , Cyfry)                                 'wywołanie procedury pobierającej z tablicy kod znaku dla wartości D
       Reset W4                                                 'włączenie wyświetlacza 4

     End Select                                                 'koniec instrukcji wyboru


     Incr Nr_wysw                                               'zwiększenie o jeden wartości Nr_wysw

     If Nr_wysw = 4 Then                                        'jeśli wartość Nr_wysw osiągnie 4, to
      Nr_wysw = 0                                               'zeruj wartość Nr_wysw

     End If                                                     'koniec warunku IF
     Return                                                     'powrót z podprogramu przerwania


    Cyfry:
    Data &B11000000 , &B11111001 , &B10100100 , &B10110000 , &B10011001 , &B10010010 , &B10000010 , &B11111000 , &B10000000 , &B10010000

    0 11
  • #2 04 Lut 2010 17:55
    daniel6662
    Poziom 20  

    Jeżeli chcesz aby wyświetlacz LED(bo chyba o ten chodzi) nie migotał to musisz kod jego obsługi napisać w przerwaniu przepełnienia któregoś z liczników(np. timer0). Wiele przykładów sterowania LED-ami znajdziesz w googlach wpisując "multipleksowe sterowanie wyświetlaczem LED w bascomie"
    pozdrawiam

    0
  • #3 04 Lut 2010 18:43
    Krauser
    Poziom 26  

    Zapoznaj się z kartą katalogową DS18B20, bo wysłanie CC to pominięcie wyboru układu, czyli nie trzeba podawać adresu układu z którym nawiązujemy komunikację, 44 to start konwersji temperatury. Po kolejnym resecie ponownie CC i BE co powoduje, że DS18B20 zaczyna wysyłać dane ze swojej pamięci. Temperatura jest zapisana na pierwszych 2 bajtach stąd 2 w funkcji 1wread. Zmienna I ma również rozmiar 2 bajty.
    Wyświetlacz LED miga bo odczyt temperatury i wyświetlanie na LCD zajmuje na tyle dużo czasu, że oko jest to w stanie zauważyć. Wyświetlanie LED musisz przerobić.

    Dodano po 31 [minuty]:

    Code:
    if A = 0 then Cyfra1 = &B11000000 else 
    to coś dziwnie wygląda nie ma nigdzie endif i można to zrobić dużo prościej. Cały kod przetworzenie cyfry do wyświetlania można wyrzucić i dalej by to było tak:
    Code:

    portb = lookup(A, Cyfry)
    '...

    portb = lookup(B, Cyfry)
    '....

    za End kody cyfr kolejno
    Code:

    Cyfry:
    Data &B11000000, &B11111001, &B10100100, &B10110000, &B10011001, &B10010010, &B10000010, &B11111000, &B10000000, &B10010000

    0
  • #4 04 Lut 2010 23:04
    alarmowanie
    Poziom 9  

    Poprawiłem troszeczkę kod dołożyłem przerwania teraz już wyświetlacz Led jasno świeci tylko że co ok 1s przeskakuje na jakieś inne znaki i powraca do odczytanej temperatury oraz wydaje mi się że teraz jest wolniejsza reakcja czujnika za zmianę temperatury??

    0
  • #5 05 Lut 2010 15:32
    alarmowanie
    Poziom 9  

    No nie mogę nie wiem jak sobie poradzić z tymi przerwaniami macie może jakiś pomysł??
    Próbowałem już różnie to konfigurować i nic :(

    0
  • #6 05 Lut 2010 18:59
    Krauser
    Poziom 26  

    Program wygląda dużo lepiej.

    Code:
    I = 1wread(2)
    pobiera dwa bajty w których znajduje się temperatura. Polecam zajrzeć do karty katalogowej DS18B20 str.4. W I znajdzie się liczba 16 bitowa, gdzie pierwsze 4 bity to znak, następne 8 bitów to część przed przecinkiem, a cztery ostatnie to to co po przecinku. Liczby ujemne są w kodzie U2.
    Code:
    S = I / 16

    Powyższe działanie wykonywane jest dlatego, żeby uzyskać liczbę w formacie zmiennoprzecinkowym, bo I jest liczba całkowitą ze znakiem. Przykład:
    I=0191(Hex)=401(Dec)
    S=I/16=401/16=25,0625 - wynik w stopniach
    Myślę, że do otrzymania poszczególnych cyfr powinieneś jednak operować na zmiennej I. Mógłbyś wtedy używać zmiennych całkowitych. Nie analizowałem tego fragmentu. Upewnij się, że A, B, C, D nigdy nie jest większe niż 9. Można też dodać warunek, który to sprawdzi. I co gdy temperatura będzie ujemna. Proponuje prostszy sposób.
    Code:

    Dim tempWord as Word
    Dim Znak as Bit
    '....
    'po S=I/16
    If I<0 then Znak=1 else Znak=0 end if
    I= Abs(I) 'teraz I jest dodatnie
    tempWord = I 'zapamiętanie I
    Shift I, right, 4   'pozbycie się czterech bitów ułamkowych teraz I jest z zakresu 0-125
    ' przesunięcie o 4 w prawo to to samo co dzielenie całkowite przez 16
    A = I
    A = A\100 ' cyfra setki
    I = I Mod 100 ' I zawiera resztę z dzielenia przez 100
    B = I
    B = B\10 ' cyfra dziesiątki
    I = I Mod 10 ' I zawiera resztę z dzielenia przez 10
    C = I ' cyfra jednostki
    I = tempWord ' I znowu zawiera dodatnią liczbę
    Shift I, left, 12
    Shift I, right, 12 ' I zawiera tylko część po przecinku
    I = I*625
    I = I\1000
    D = I ' cyfra po przecinku

    Dodatkowo Call Pobr_znaku(A) jest niepotrzebne, bo od razu można użyć PortB = Lookup(A , Cyfry). Load Timer0, 125 ładuje taka liczbę do rejestru by Timer0 zliczył 125 impulsów do przepełnienia/przerwania

    0
  • #7 05 Lut 2010 20:29
    alarmowanie
    Poziom 9  

    Poprawiłem obliczenia pojedynczej cyfry lecz w zaznaczonej linijce w pierwszym okienku z fragmentem kodu wykrzyknikami, pojawia się błąd i nie wiem dlaczego zmienna Znak jest zdeklarowana w ten sposób:

    Dim Znak as Bit

    a pojawia się komunikat:

    error:105 StoreBit error [0]

    A co z tymi przerwaniami bo do końca nie mogę tego złapać są tak jak powinny być nie musi czasem przed komunikacją z ds-em być disable interrupts a po komunikacje znowu enable interrupts znowu w innym przykładzie widziałem z w miejscu gdzie znajduje się podprogram przerwań także na początku było disable interrupts i na końcu enable interrupts a także nie było w nim załadowania timera a tak na marginesie dlaczego timer ładuje się 2 razy

    0
  • #8 05 Lut 2010 20:53
    daniel6662
    Poziom 20  

    z tym ładowaniem timera to jest tak że timer startuje od wartości 0 i liczy sobie w górę, aż doliczy do 255 wtedy jest zerowany i zostaje wywołane przerwanie, natomiast instrukcja load timer0, x wpisuje do timera wartość wg wzoru: 256 - x dzięki czemu timer musi zliczyć tylko x impulsów żeby nastąpiło przepełnienie(oraz w tym wypadku przerwanie), tylko w tym problem że wartość timera jest zerowana po przepełnieniu dla tego na początku przerwania timer jest ponownie ładowany. Ładowanie timera na początku kodu jest tylko po to aby przepełnienie było od początku w równych odstępach czasu, można z tego zrezygnować tylko wtedy pierwsze przepełnienie(wywołanie przerwania) odbędzie się po 255 impulsach a nie po 125 jak w twoim przypadku
    pozdrawiam.

    0
  • #9 05 Lut 2010 21:21
    alarmowanie
    Poziom 9  

    Aha no ok to jak teraz dobrać odpowiednią ilość impulsów raz żeby na siebie nie nachodziły 2 i żeby to działało to jest uzależnione jeden impuls to 1 polecenie a że tak się jeszcze głupio zapytam ja pracuje teraz nad tym żeby wyświetlacz LED pracował multipleksowo w przerwaniach czyli jak się przepełni licznik to wykona się podprogram multipleksacji czy tak??

    inventco.eu - proszę poprawić pisownię. Regulamin p.15 - inaczej kosz.

    0
  • #10 05 Lut 2010 23:09
    daniel6662
    Poziom 20  

    LCD multipleksowo? nie bardzo rozumiem ponieważ multipleksowo sterowana jest sama matryca a za to odpowiada sterownik wyswietlacza(take czarne coś na płytce wyświetacza:)) a co do przepełniania licznika to możesz sobie policzyć częstotliwość występowania przerwania ze wzoru:
    częstotliwość= crystal/prescaler/x
    gdzie crystal to częstotliwość oscylatora, w twoim przykładzie jest 8000000
    prescaler to dzielnik częstotliwości timera ustawiany w linijce Config Timer0 = Timer , Prescale = 256 czyli u ciebie 256
    x jest to wartość wpisywana do licznika w twoim przykładzie 125
    czyli tak 8000000/256/125=250 tzn że przepełnienie jest wykonywane 250 razy na sekunde, czyli na przepełnienie licznika trzeba czekać 32000 cykle zegarowe czyli mniejwięcej 32000 pojedyńczych instrukcji z tą różnicą żę chodzi tu o instrukcje asemblera ale to i tak niema mowy o nachodzeniu na siebie:)
    druga sprawa to to że może nie zdajesz sobie sprawy z tego że bascom napoczątku każdej procedury obsługi przerwania niejawnie blokuje wszystkie przerwania tj dodaje linijke distable interrupts a na koniec procedury dodaje enable interrupts a tak prosciej mówiąc w trakcie wykonywania przerwania nie zostaną wykonane żadne inne przerwania, więc napewno nie nachodzą na siebie:)
    wracając do obsługi lcd w przerwaniu to sprubuj przepisać linijki:

    Code:

    Locate 1 , 1
    Lcd "Temp:" ; T ; Chr(0) ; "C"

    i wpisz je przed końcem przerwania tzn między "end if" a "return"
    pozdrawiam

    0
  • #11 07 Lut 2010 10:23
    Krauser
    Poziom 26  

    Wracając do

    Code:
    If I < 0 then Znak = 1 else Znak = 0 end if

    to po pierwsze zgodnie ze składnią Bascoma powinno być:
    -gdy w jednej linii
    Code:
    If I < 0 then Znak = 1 else Znak = 0

    lub gdy kolejno-liniowo
    Code:
    If I < 0 then 
    
       Znak = 1
    else
       Znak = 0
    end if

    mój błąd.
    Po drugie zaproponowałem dodanie tego bitu do przechowywania znaku temperatury. Jest zima więc możesz to łatwo sprawdzić, że na LCD wynik będzie z minusem, a na wyświetlaczu LED fizycznie tego minusa nie ma. Dlatego można dodać jedną płaską diodę i zapalać ją w zależności od stanu tego bitu.

    0
  • #12 08 Lut 2010 15:10
    alarmowanie
    Poziom 9  

    Dobra panowie bardzo wam dziękuje za aktywną pomoc lecz i tak nie udało mi się tego opanować dalej co jakiś czas wyświetlacz LED mignie więc decyduję się na takie rozwiązanie że wezmę Atmegę 8 która będzie sobie multipleksować wyświetlaczem LED a atmega 16 będzie czytać 3 temperatury obsługiwać lcd oraz zajmować się sterowaniem takimi urządzeniami jak pompa wody Co czy elektrozawory i oczywiście wysyłaniem przez uart wartości temperatury do atmegi 8 jeszcze raz dzięki bardzo zamykam temat

    0