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

[ATmega32][Bascom] Zegarek na PCF8583 i nastawianie czasu

polprzewodnikowy 09 Mar 2010 18:31 3763 11
REKLAMA
  • #1 7806240
    polprzewodnikowy
    Poziom 26  
    Witam.
    Napisałem taki program w bascomie do obsługi RTC PCF8583. Chcę abym mógł go nastawiać z pilota. Niestety ale nie wychodzi mi to za bardzo (po wciśnięciu klawisza pojawia się tylko kursor i program dalej nie chce iść). Pod Int0 podłączyłem przerwanie od PCF'a a pod Int1 odbiornik Rc5. Odmierzanie czasu jest poprawne. Tutaj kod:

    $regfile = "m32def.dat"
    $crystal = 16000000
    Enable Interrupts
    Enable Int0
    Enable Int1
    On Int0 Odczyt_czasu
    On Int1 Menu
    Dim Sekunda As Byte , Minuta As Byte , Godzina As Byte
    Dim Ustaw_h As Byte , Ustaw_m As Byte , Ustaw_s As Byte
    Dim Command As Byte , Addres As Byte
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Rs = Portc.2 , E = Portc.3 , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6 , Db7 = Portc.7
    Config Sda = Portc.1
    Config Scl = Portc.0
    Config Int1 = Low Level
    Config Rc5 = Pind.3
    Ustaw_h = 1
    Ustaw_m = 1
    Ustaw_s = 1
    Cls
    
    Do
    Loop
    End
    
    Odczyt_czasu:
       I2cinit
       I2cstart
       I2cwbyte 162
       I2cwbyte 2
       I2cstart
       I2cwbyte 163
       I2crbyte Sekunda , Ack
       I2crbyte Minuta , Ack
       I2crbyte Godzina , Nack
       I2cstop
       Godzina = Makedec(godzina)
       Minuta = Makedec(minuta)
       Sekunda = Makedec(sekunda)
       Locate 1 , 1
       Lcd Godzina ; ":" ; Minuta ; ":" ; Sekunda ; "                "
    Return
    
    Menu:
    Disable Int0
    Disable Int1
    Cls
    Do
    Getrc5(command , Addres)
    Command = Command And &B01111111
    If Command = 1 Then Incr Ustaw_h
    If Command = 2 Then Decr Ustaw_h
    If Ustaw_h > 23 Then Ustaw_h = 0
    Lcd "Ustaw godziny: " ; Ustaw_h
    Loop Until Command = 4
    Cls
    Do
    Getrc5(Command , Addres)
    Command = Command And &B01111111
    If Command = 1 Then Incr Ustaw_m
    If Command = 2 Then Decr Ustaw_m
    If Ustaw_m > 59 Then Ustaw_m = 0
    Lcd "Ustaw Minuty: " ; Ustaw_m
    Loop Until Command = 4
    Cls
    Do
    Getrc5(Command , Addres)
    Command = Command And &B01111111
    If Command = 1 Then Incr Ustaw_s
    If Command = 2 Then Decr Ustaw_s
    If Ustaw_s > 59 Then Ustaw_s = 0
    Lcd "Ustaw Sekundy: " ; Ustaw_s
    Loop Until Command = 4
    I2cstart
    I2cwbyte 162
    I2cwbyte 2
    I2cwbyte Ustaw_s
    I2cwbyte Ustaw_m
    I2cwbyte Ustaw_h
    I2cstop
    Cls : Lcd "    Zapisano    "
    Wait 1
    Enable Int0
    Enable Int1
    Return


    Program zatrzymuje się po wejściu do przerwania "Menu". Co w takim razie robię źle? Z góry pozdrawiam, Polprzewodnikowy.
  • REKLAMA
  • #3 7810304
    polprzewodnikowy
    Poziom 26  
    Dziękuję za odpowiedź :) Linijka Enable Interrupts pomogła i przerwanie menu działa prawidłowo. W poprzednim kodzie zamieniłem miejscami wyrażenia w nawiasie w instrukcji Getrc5. Po przemyśleniach kod wygląda tak:

    $regfile = "m32def.dat"
    $crystal = 16000000
    Enable Interrupts
    Enable Int0
    On Int0 Menu
    Dim Sekunda As Byte , Minuta As Byte , Godzina As Byte
    Dim Ustaw_h As Byte , Ustaw_m As Byte , Ustaw_s As Byte
    Dim Command As Byte , Address As Byte
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Rs = Portc.2 , E = Portc.3 , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6 , Db7 = Portc.7
    Cursor Off
    Config Sda = Portc.1
    Config Scl = Portc.0
    Config Int0 = Rising
    Config Rc5 = Pind.2
    Ustaw_h = 1
    Ustaw_m = 1
    Ustaw_s = 1
    Cls
    
    Do
       I2cinit
       I2cstart
       I2cwbyte 162
       I2cwbyte 2
       I2cstart
       I2cwbyte 163
       I2crbyte Sekunda , Ack
       I2crbyte Minuta , Ack
       I2crbyte Godzina , Nack
       I2cstop
       Godzina = Makedec(godzina)
       Minuta = Makedec(minuta)
       Sekunda = Makedec(sekunda)
       Locate 1 , 1
       Lcd Godzina ; ":" ; Minuta ; ":" ; Sekunda ; "                "
       Waitms 20
    Loop
    End
    
    Menu:
    Disable Int0
    Enable Interrupts
    Cls
    Do
    Getrc5(address , Command)
    Command = Command And &B01111111
    If Command = 82 Then Return
    If Command = 2 Then Incr Ustaw_h
    If Command = 1 Then Decr Ustaw_h
    If Ustaw_h > 23 Then Ustaw_h = 0
    If Command = 5 Then Incr Ustaw_m
    If Command = 4 Then Decr Ustaw_m
    If Ustaw_m > 59 Then Ustaw_m = 0
    If Command = 8 Then Incr Ustaw_s
    If Command = 7 Then Decr Ustaw_s
    If Ustaw_s > 59 Then Ustaw_s = 0
    Locate 1 , 1
    Lcd "H:" ; Ustaw_h ; " M:" ; Ustaw_m ; " S:" ; Ustaw_s ; "            "
    Locate 2 , 1
    Lcd Command ; "    " ; Address ; "    "
    Waitms 80
    Loop Until Command = 87
    Ustaw_h = Makebcd(ustaw_h)
    Ustaw_m = Makebcd(ustaw_m)
    Ustaw_s = Makebcd(ustaw_s)
    I2cstart
    I2cwbyte 162
    I2cwbyte 2
    I2cwbyte Ustaw_s
    I2cwbyte Ustaw_m
    I2cwbyte Ustaw_h
    I2cstop
    Cls
    Lcd "    Zapisano    "
    Waitms 500
    Cls
    Enable Int0
    Return


    Teraz kolejny problem, gdy na przykład mamy czas: "12:08:33" na lcd widać tak: "12:8:33". Jak dodać zero przed liczbą poniżej 10?
  • REKLAMA
  • #4 7810585
    polprzewodnikowy
    Poziom 26  
    Nie zauważyłeś że w temacie pisze Bascom? Niestety ale przykłady w C mi się nie przydadzą :)
  • Pomocny post
    #5 7810620
    manekinen
    Poziom 29  
    Tak na szybko mam takie rozwiązanie:
    
    Dim Go_s As String * 2 , Mi_s As String * 2 , Se_s As String * 2
    

    
    Go_s = Str(godzina)
    Mi_s = Str(minuta)
    Se_s = Str(sekunda)
    Lcd Format(go_s , "00") ; ":" ; Format(mi_s , "00") ; ":" ; Format(se_s , "00")
    


    Wartości można też przepisać do zmiennej single a tą konwertować podobnie, używając polecenia Fusing - patrz help

    Lub jeszcze jeden pomysł mi przychodzi. Wartości można rozbijać najpierw na dwa bajty (po 4 bity), kowertować osobno do BCD, i osobno wyświetlać, tzn
    
    Lcd Godzina1 ; Godzina2 ; ":"...itp
    


    Dodano po 7 [minuty]:

    O, wiedziałem że jest przecież prostsze rozwiązanie...

    
    Lcd Bcd(godzina) ;...itp
    

    To od razu przekonwertuje z BCD i poprawnie wyświetli, sprawdź.
  • #6 7810677
    polprzewodnikowy
    Poziom 26  
    Dziękuje, wszystko działa jak należy. Teraz już zapewne ostatni problem. Gdy po włączeniu menu i zapisaniu wszystkich danych wyświetla się napis "Zapisano" a potem wyświetla się tylko "H:" i na tym program się zatrzymuje i trzeba ręcznie resetować procesor. Co powoduje ten błąd?
  • REKLAMA
  • #7 7810687
    manekinen
    Poziom 29  
    Czyli wywalasz całe
    
    Godzina = Makedec(godzina)
    Minuta = Makedec(minuta)
    Sekunda = Makedec(sekunda)
    

    A przy wyświetlaniu samo skonwertuje, w symulatorze wyświetla dobrze czyli 1 = 01
  • REKLAMA
  • #8 7810703
    polprzewodnikowy
    Poziom 26  
    O, faktycznie, dobrze wyświetla. A co z tym problemem zatrzymywania się programu?
  • #9 7810831
    manekinen
    Poziom 29  
    Przerwanie INT0 może włączaj dopiero w głównej pętli, nie wiem może jakąś flagę ustaw że wyłączałeś i jak w nią wpadnie to sobie włączy. Innego powodu nie widzę
  • #10 7811073
    polprzewodnikowy
    Poziom 26  
    Wszystko działa jak należy, dziękuję za pomoc. Ostateczny kod wygląda tak:

    $regfile = "m32def.dat"
    $crystal = 16000000
    Enable Interrupts
    On Int0 Menu
    Dim Sekunda As Byte , Minuta As Byte , Godzina As Byte
    Dim Ustaw_h As Byte , Ustaw_m As Byte , Ustaw_s As Byte
    Dim Command As Byte , Address As Byte , Flaga_rc5 As Bit
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Rs = Portc.2 , E = Portc.3 , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6 , Db7 = Portc.7
    Cursor Off
    Config Sda = Portc.1
    Config Scl = Portc.0
    Config Int0 = Low Level
    Config Rc5 = Pind.2
    Ustaw_h = 1
    Ustaw_m = 1
    Ustaw_s = 1
    Cls
    Flaga_rc5 = 1
    Do
       If Flaga_rc5 = 1 Then
       Enable Int0
       Flaga_rc5 = 0
       End If
       I2cinit
       I2cstart
       I2cwbyte 162
       I2cwbyte 2
       I2cstart
       I2cwbyte 163
       I2crbyte Sekunda , Ack
       I2crbyte Minuta , Ack
       I2crbyte Godzina , Nack
       I2cstop
       Locate 1 , 1
       Lcd Bcd(godzina) ; ":" ; Bcd(minuta) ; ":" ; Bcd(sekunda)
    Loop
    End
    
    Menu:
    Disable Int0
    Enable Interrupts
    Flaga_rc5 = 1
    Cls
    Do
    Getrc5(address , Command)
    Command = Command And &B01111111
    If Command = 53 Then Return
    If Command = 2 Then Incr Ustaw_h
    If Command = 1 Then Decr Ustaw_h
    If Ustaw_h > 23 Then Ustaw_h = 0
    If Command = 5 Then Incr Ustaw_m
    If Command = 4 Then Decr Ustaw_m
    If Ustaw_m > 59 Then Ustaw_m = 0
    If Command = 8 Then Incr Ustaw_s
    If Command = 7 Then Decr Ustaw_s
    If Ustaw_s > 59 Then Ustaw_s = 0
    Locate 1 , 1
    Lcd "H:" ; Ustaw_h ; " M:" ; Ustaw_m ; " S:" ; Ustaw_s ; "            "
    Locate 2 , 1
    Lcd Command ; "    " ; Address ; "    "
    Waitms 80
    Loop Until Command = 87
    Ustaw_h = Makebcd(ustaw_h)
    Ustaw_m = Makebcd(ustaw_m)
    Ustaw_s = Makebcd(ustaw_s)
    I2cstart
    I2cwbyte 162
    I2cwbyte 2
    I2cwbyte Ustaw_s
    I2cwbyte Ustaw_m
    I2cwbyte Ustaw_h
    I2cstop
    Cls
    Lcd "    Zapisano    "
    Wait 3
    Cls
    Return
  • #11 7811150
    manekinen
    Poziom 29  
    Zauważ tylko, że teraz nie konwertujesz odczytanych wartości z RTC i są ciągle w formacie BCD. Przy wyświetlaniu są one konwertowane tylko na string dla wyświetlacza, a same nie ulegają zmianie. Tak na dobrą sprawę musiał byś je konwertować PO wyświetleniu... ale po co....

    Przy ustawianiu operujesz na zmiennych Ustaw_h itd, jeśli zegar pochodzi kilka godzin i będziesz chciał go przestawić, to wciskając przycisk dostaniesz wartość z ostatniego ustawiania a nie aktualny czas zwiększony o 1... trochę nie wygodne prawda?

    Więc wywal te osobne zmienne dla ustawiania. Po wejściu w nastawę czasu odczytaj aktualny czas, przekonwertuj, zwiększaj, wyślij.
  • #12 7811393
    polprzewodnikowy
    Poziom 26  
    Pokombinowałem i wyszło takie coś. Teraz wszystko działa jak należy.

    $regfile = "m32def.dat"
    $crystal = 16000000
    Enable Interrupts
    On Int0 Menu
    Dim Sekunda As Byte , Minuta As Byte , Godzina As Byte
    Dim Command As Byte , Address As Byte , Flaga_rc5 As Bit
    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Rs = Portc.2 , E = Portc.3 , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6 , Db7 = Portc.7
    Cursor Off
    Config Sda = Portc.1
    Config Scl = Portc.0
    Config Int0 = Low Level
    Config Rc5 = Pind.2
    Cls
    Flaga_rc5 = 1
    Do
       If Flaga_rc5 = 1 Then
       Enable Int0
       Flaga_rc5 = 0
       End If
       I2cinit
       I2cstart
       I2cwbyte 162
       I2cwbyte 2
       I2cstart
       I2cwbyte 163
       I2crbyte Sekunda , Ack
       I2crbyte Minuta , Ack
       I2crbyte Godzina , Nack
       I2cstop
       Locate 1 , 1
       Lcd Bcd(godzina) ; ":" ; Bcd(minuta) ; ":" ; Bcd(sekunda)
    Loop
    End
    
    Menu:
    Disable Int0
    Enable Interrupts
    Flaga_rc5 = 1
    Cls
    Godzina = Makedec(godzina)
    Minuta = Makedec(minuta)
    Sekunda = Makedec(sekunda)
    Do
    Getrc5(address , Command)
    Command = Command And &B01111111
    If Command = 53 Then Return
    If Command = 2 Then Incr Godzina
    If Command = 1 Then Decr Godzina
    If Godzina > 23 Then Godzina = 0
    If Command = 5 Then Incr Minuta
    If Command = 4 Then Decr Minuta
    If Minuta > 59 Then Minuta = 0
    If Command = 8 Then Incr Sekunda
    If Command = 7 Then Decr Sekunda
    If Sekunda > 59 Then Sekunda = 0
    Locate 1 , 1
    Lcd "H:" ; Godzina ; " M:" ; Minuta ; " S:" ; Sekunda ; "   "
    Locate 2 , 1
    Lcd Command ; "    " ; Address ; "    "
    Waitms 80
    Loop Until Command = 87
    Godzina = Makebcd(godzina)
    Minuta = Makebcd(minuta)
    Sekunda = Makebcd(sekunda)
    I2cstart
    I2cwbyte 162
    I2cwbyte 2
    I2cwbyte Sekunda
    I2cwbyte Minuta
    I2cwbyte Godzina
    I2cstop
    Cls
    Lcd "    Zapisano    "
    Wait 3
    Cls
    Return
REKLAMA