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.

[Mega8][BASCOM] zegarek pov dziwny problem

madart 16 Cze 2008 19:17 2320 3
  • #1 16 Cze 2008 19:17
    madart
    Poziom 25  

    Zrobiłem sobie propeller clock na i działa prawie dobrze :)
    Problem w tym że co jakieś 50 obrotów zegarek przestaje działać na kolejne 50 obrotów. Wiąże się to z funkcją zliczania czasu obrotu i przeliczanie na 60 pozycji na tarczy zegara.

    Code:
    Stop Timer1
    
    Timer1 = 0
    Start Timer1

    Incr Y
    If Y = 50 Then
    X = Capture1
    X = X / 60
    Y = 0
    End If

    Compare1a = X
    Pozycja = 60

    Jeśli zmiejsze Y to czas wyświetlania i czas niewyświetlania skraca się, przy Y=1 obraz miga dość uciążliwie. Ta funkcja wykonywana jest przy przerwaniu ICP1 czyli gdy na nóżce PB.0 pojawi się stan niski z fototranzystora. Ma ktoś pomysł skąd takie coś? Wyświetlanie odbywa się przy porównaniu licznika T1 z rejestrem compare1a. Może coś przeoczyłem albo czegoś zabrakło? To tak jakby przy zliczaniu y nie odbywało się przerwanie od compare1a.
    Tutaj cały kod:
    Code:
    $regfile = "m8def.DAT"
    
    $crystal = 8000000
    $baud = 9600

    Config Portc = Output
    Set Portc.2
    Reset Portc.1
    Reset Portc.0

    Config Pinb.0 = Input

    Config Timer1 = Timer , Prescale = 1024 , Capture Edge = Falling , Compare A = Disconnect , Clear Timer = 1


    On Icp1 C1
    On Compare1a C2

    Enable Compare1a
    Enable Icp1
    Enable Interrupts


    Dim _s As Byte , _m As Byte , _h As Byte
    Dim Y As Byte
    Dim X As Word
    Dim Pozycja As Byte

    Config Sda = Portd.6
    Config Scl = Portd.5

    Dim _weekday As Byte
    Dim _day As Byte
    Dim _month As Byte
    Dim _year As Byte
    Dim _sec As Byte
    Dim _min As Byte
    Dim _hour As Byte

    Dim Ds1307w As Byte
    Dim Ds1307r As Byte

    Ds1307w = &B11010000
    Ds1307r = &B11010001



    Do

    Reset Portc.0
    Reset Portc.1
    Set Portc.2

    Loop
    End


    C1:
    Stop Timer1
    Timer1 = 0
    Start Timer1

    Incr Y
    If Y = 50 Then
    X = Capture1
    X = X / 60
    Y = 0
    End If

    Compare1a = X
    Pozycja = 60

    ' ODCZYT DATY I CZASU*********
    I2cstart
    I2cwbyte Ds1307w
    I2cwbyte 0
    I2cstart
    I2cwbyte Ds1307r
    I2crbyte _sec , Ack
    I2crbyte _min , Ack
    I2crbyte _hour , Nack
    I2cstop


    _s = Makedec(_sec)
    _m = Makedec(_min)
    _h = Makedec(_hour)




    Return

    C2:
    Decr Pozycja


    If _s = Pozycja Then Reset Portc.2

    If _m = Pozycja Then
    Set Portc.1
    Set Portc.0
    End If

    If _h = Pozycja Then Set Portc.0

    Return

    0 3
  • #2 23 Cze 2008 15:45
    elektronika1984
    Poziom 12  

    Witam.
    A próbowałeś może wykomentować to:

    Code:

    ...
    Incr Y
    If Y = 50 Then
    X = Capture1
    X = X / 60
    Y = 0
    End If

    Compare1a = X

    '-----------------------
    Pozycja = 60             <-- to do wykomentowania
    '-----------------------

    ' ODCZYT DATY I CZASU*********
    I2cstart
    ...

    Oraz wpisz coś takiego:
    Code:

    C2:
    Decr Pozycja

    '-------to dopisac------------
    if Pozycja > 254 then      'jesli Pozycja mniejsza od 0
    pozycja = 60
    end if
    '-------------------------------


    If _s = Pozycja Then Reset Portc.2

    If _m = Pozycja Then
    Set Portc.1
    Set Portc.0
    End If
    ...

    Pozdrawiam

    0
  • #3 23 Cze 2008 17:53
    Korazon
    Poziom 11  

    Moim zdaniem całość nie działa poprawnie, bo używasz Timera1 pracującego w trybie CTC jednocześnie do odmierzania odcinków czasowych wyświetlacza i do pomiaru czasu zatoczenia pełnego koła. W trybie CTC Timer liczy od 0 do wartości Compare1a po czym zostaje wyzerowany, więc ten podprogram w przerwaniu ICP1, który oblicza Ci ile cykli zliczył Timer podczas obiegu wyświetlacza, liczy tak naprawdę ile cykli upłynęło od momentu ostatniego przerwania Compare1a. Żeby się dowiedzieć ile cykli upłynęło od poprzedniego przerwania ICP1 trzeba pomnożyć ilość przerwań Compare1a przez ilość cykli która przypadała na jedno przerwanie (czyli rejestr Compare1a) i dodać do tego przechwyconą wartość Timera.
    Druga sprawa to za duża wartość preskalera. Przy częstotliwości 8MHz timer 16-bitowy z preskalerem 1024 przepełni się dopiero po: 65536*1024/8000000 = 8,4s. A jeden obieg wyświetlacza to czas nieprzekraczający kilku setnych s. Wartość 64 da przepełnienie po ok. 0,5s.
    Trzecia sprawa to nie za szczęśliwe umieszczenie odczytu po I2C w przerwaniu ICP1. Odczyt ten jest dość powolny, a blokowanie innych przerwań w AVR (u nas przerwania Compare1a) na czas obsługi jednego z nich może spowodować, że pierwsze wskazówki pozostaną niewidoczne. Rozwiązaniem byłoby przeniesienie tych funkcji do pętli głównej oraz zaprzęgnięcie do pracy Timera0 w którym byłaby procedura z pętli głównej programu, wygaszająca diody po krótkim czasie od wystąpienia przerwania je zaświecającego (Compare1a), ponieważ pętla główna stanie się wtedy na to za wolna.
    Przykładowy program mógłby wyglądać tak (bez uwzględnienia ostatniego punktu i nie twierdzę, że zadziała :) ):

    Code:
    $regfile = "m8def.DAT"
    
    $crystal = 8000000
    $baud = 9600

    Config Portc = Output
    Set Portc.2
    Reset Portc.1
    Reset Portc.0

    Config Pinb.0 = Input

    Config Timer1 = Timer , Prescale = 64 , Capture Edge = Falling , Compare A = Disconnect , Clear Timer = 1


    On Icp1 C1
    On Compare1a C2

    Enable Compare1a
    Enable Icp1
    Enable Interrupts


    Dim _s As Byte , _m As Byte , _h As Byte
    Dim Y As Byte
    Dim X As Word
    Dim Pozycja As Byte
    Dim Obrot As Byte

    Config Sda = Portd.6
    Config Scl = Portd.5

    Dim _weekday As Byte
    Dim _day As Byte
    Dim _month As Byte
    Dim _year As Byte
    Dim _sec As Byte
    Dim _min As Byte
    Dim _hour As Byte

    Dim Ds1307w As Byte
    Dim Ds1307r As Byte

    Ds1307w = &B11010000
    Ds1307r = &B11010001



    Do

    Reset Portc.0
    Reset Portc.1
    Set Portc.2


    Loop
    End


    C1:
    Stop Timer1
    Timer1 = 0
    Start Timer1

    Incr Y
    If Y = 50 Then
    X = Capture1 + Obrot * (Compare1a + 1)
    X = X / 60
    Y = 0
    End If

    Compare1a = X
    Pozycja = 60
    Obrot = 0

    ' ODCZYT DATY I CZASU*********
    I2cstart
    I2cwbyte Ds1307w
    I2cwbyte 0
    I2cstart
    I2cwbyte Ds1307r
    I2crbyte _sec , Ack
    I2crbyte _min , Ack
    I2crbyte _hour , Nack
    I2cstop


    _s = Makedec(_sec)
    _m = Makedec(_min)
    _h = Makedec(_hour)

    Return

    C2:
    Decr Pozycja
    Incr Obrot


    If _s = Pozycja Then Reset Portc.2

    If _m = Pozycja Then
    Set Portc.1
    Set Portc.0
    End If

    If _h = Pozycja Then Set Portc.0

    Return

    1
  • #4 07 Lip 2008 19:37
    gromleon
    Poziom 33  

    Witam zastanawia mnie jedna rzecz w tym programie jak kolega chce wyświetlać godziny porównujac ją do "pozycja" skoro godzin jest 12 lub 24 a "pozycji" 60 czyli wg mnie wskazówka godzin nie bedzie się wyswietlać prawidłowo, a może się mylę. wydaje mi się ze należało by godziny odpowiednio przeliczyć na podziałkę 60 punktów czyli np jest godzina 6 5 X 6 = 30

    0