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

[Mega8][BASCOM] zegarek pov dziwny problem

madart 16 Cze 2008 19:17 2593 3
REKLAMA
  • #1 5253334
    madart
    Poziom 26  
    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.
    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:
    $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
  • REKLAMA
  • #2 5277402
    elektronika1984
    Poziom 13  
    Witam.
    A próbowałeś może wykomentować to:
    
    ...
    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:
    
    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
  • REKLAMA
  • #3 5277738
    Korazon
    Poziom 12  
    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 :) ):
    $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
  • #4 5320892
    Konto nie istnieje
    Poziom 1  
REKLAMA