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

[atmega8][BASCOM] liczenie czasu miedzy impulsami

zuraf 29 Paź 2008 21:40 3446 14
REKLAMA
  • #1 5681517
    zuraf
    Poziom 14  
    Witam

    Tak jak w temacie. Jak liczyć czas między pojawieniem sie na porcie impulsów stanu niskiego (o ile stan niski można nazwać impulsem)? tzn tak: pojawia się 0 timer rusza, pojawia sie 0, timer się zatrzymuje, zczytuję stan timera, robie z tym to i tamto, zeruje licznik i od początku, czekam na 0, licznik rusza, itp. Nie chcę korzystać z licznia impulsów w czasie np 1s, gdyż zależy mi na szybkości odczytu, a muszę odcztać czasy z dwóch źródeł, więc ten czas i tak jest *2. Pozatym nie mogę zkorzystać z funkcji counter, gdyż z tego co się orientuje, timer atmegi 8 nie reaguje na stan niski (chyba że źle zrozumiałem)

    Ja wymyśliłem coś takiego, ale nie chce działać. Dlaczego? :

    $crystal = 1000000
    $regfile = "m8def.dat"
    
    
    Config Portc = Output
    Config Portd.1 = Output
    Config Portd.7 = Output
    Config Timer1 = Timer
    Config Portb.0 = Input
    
    Portd.1 = 1
    Portc = &B11111111
    
    Declare Sub Cyfra
    Dim Wynik As Single
    Dim Obr As Word
    
    Dim U As byte
    
    
    Set Portb.0
    Set Portd.7
    
    
    Do
    
      If Pinb.0 = 0 Then
    
          Start Timer1
            Do
    
            Loop Until Pinb.0 = 0
    
          stop TIMER1
    
    
       Obr = Timer1
       Wynik = Obr / Obr
    
          If Wynik = 0 Then U = 1
    
    
    
       Call Cyfra
    
       End If
    
    Timer1 = 0
    
    
    Loop
    
    
    
    Sub Cyfra
    
    Select Case U
    
    Case 1 : Portc = &B11011101
     Portd.1 = 1
    Case 2 : Portc = &B11001010
     Portd.1 = 0
    Case 3 : Portc = &B11001000
     Portd.1 = 1
    Case 4 : Portc = &B11010001
     Portd.1 = 1
    Case 5 : Portc = &B11100000
     Portd.1 = 1
    Case 6 : Portc = &B11100000
     Portd.1 = 0
    Case 7 : Portc = &B11001101
     Portd.1 = 1
    Case 8 : Portc = &B11000000
     Portd.1 = 0
    Case 9 : Portc = &B11000000
     Portd.1 = 1
     End Select
    
    
    
    
    
    End Sub
    
    End


    akurat licznie stosunku obr/obr ma na celu uzyskanie w celach testowych pewnego wniku, niezależnie od uzyskanego czasu, co pozwoli mi wyświetlić 1 na wysw. 7-seg. Gdyby to działało, bez problemu dostosował bym program do licznia tego co potrzeba.

    Jakie są opcjonalne rozwiązania tego problemu?

    Poprawiłem tytuł.
    [zumek]
  • REKLAMA
  • #2 5681944
    dawid512
    Poziom 32  
    Osobiście wykorzystał bym nóżkę np. INT0. Wtedy wszystko dzieje się w przerwaniu, po za tym w zmiennej Counter1 masz twój wynik. Coś skąpą masz tę konfigurację timera :P
  • #3 5681960
    komanche
    Poziom 13  
    właśnie.

    Jestem wkurzony, bo właśnie skończyłem pisac swoj kod.
    Ja nie miałem gotowca ;)

    
    
    $regfile "m8def.dat"
    $crystal = 8000000
    Config Lcd = 40 * 2
    Config Timer1 = Timer , Prescale = 256
    Stop Timer1
    Config Pind.2 = Input
    Config Int0 = Falling
    Enable Interrupts
    Enable Int0
    On Int0 Przerwanie1 Nosave
    
    Cls
    Timer1 = 0
    
    
    Dim Li As Word
    Dim Lj As Word
    Dim La As Word
    
    
    Do
    Loop
    
    
    
    Przerwanie1:
    
    Stop Timer1
    Cls
    Li = 31250 / Timer1
    Lcd Li ; "impulsow/sek"
    
    Timer1 = 0
    Start Timer1
    
    
    
    Return
    
     : End 
      
  • #4 5681992
    zuraf
    Poziom 14  
    tzn tak: taka konfiguracja zrobiona tylko po to żeby sprawdzić czy działa ten sposób. Pozatym skill niezbyt wysoki (raptem od tygodnia w tym siedze), dlatego chciałem zasięgnąć rady od starszych:).

    Właśnie nie do końca rozumiem te przerwania. Można na wejście dawać stan niski, jako impuls przerwania?

    A wracając do tego mojego pomysłu... Co w nim jest źle? złą obsługa timerów, źle zczytuje, czy co? Nie chodzi o to że ten program praktycznie nic nie robi... to wersja testowa:)
  • #5 5682016
    komanche
    Poziom 13  
    Widziales kiedys sinusoidę?

    ma dwa zboCza:
    narastająCe (rising)
    i
    opadająCe (falling)

    Przerwanie może byC wyzwolone jednym z tyCh dwóCh zboCz.

    w powyższym kodzie masz na zboCze opadająCe, będzie działaC.
  • REKLAMA
  • #6 5682073
    zuraf
    Poziom 14  
    wiem co to sinusoida. z tym że to moje bedzie "zasilane" prostokątami, ale to chyba nie powino mieć znacznia.
  • #7 5683494
    komanche
    Poziom 13  
    bedzie dzialac ;)
  • REKLAMA
  • #8 5685276
    zuraf
    Poziom 14  
    Witam po raz kolejny.

    Zrobiłem to za pomocą przerwań, jak radziliście i można powiedzieć że działa. Niestety pojawił sie kolejny problem. Mianowicie, jak pogodzić obsługę przerwań z dwóch źródeł na raz?

    Mniej więcej chodzi o to, że na przerwanie int0 mierzy ten czas, zapisuje do zmiennej np "a" zeruje timer, a następnie czeka na przerwanie int1, mierzy czas, zapisuje do "b", zeruje timer i czeka na int0? Konkretnie to nie wiem jak zmusić go żeby po przerwaniu int0 czekał na int1. oczywiście w międzyczasie jeszcze przetwarza otrzymane wyniki, ale to już nie problem.
  • #9 5685316
    ZbeeGin
    Poziom 39  
    Źródło INT0 włącza źródło INT1 i same siebie wyłącza. W przerwaniu z INT1 podobnie: Źródło INT1 włącza INT0 i same siebie wyłącza.
    A może jednak popróbujesz z przełączaniem trybu pracy INT0 "w locie": raz narastające, raz opadające zbocze?
  • #10 5685341
    zuraf
    Poziom 14  
    czyli tak: na końcu procedury przerwania int1 wstawiam disable int1 i enable int0, a na końcu int 0 disable int0 i enable int 1?
  • REKLAMA
  • #12 5685437
    zuraf
    Poziom 14  
    po prostu nie jestem pro w tej dziedzinie i chciałem się upewnić, czy dobrze rozumiem:)
  • #13 5685569
    dawid512
    Poziom 32  
    A może po prostu dodaj sobie flagę którą ustawiaj po wykonaniu pierwszego przerwania. W drugim przerwaniu sprawdzaj czy flaga ustawiona. Jeśli tak to wykonuj coś tam jeśli nie to nic nie rób.
  • #14 5685663
    mirekk36
    Poziom 42  
    do toego o co pytasz i to bez zaprzęgania kilku przerwań i jeszcze dodatkowo timera nadaje się wprost - wyśmienicie, zresztą po to stworzony jest ten mechanizm....

    .... wejście ICP procka (przerwanie Capture1). Pin ten może generować przerwania dla Timera1 w zależności od zbocza jakie pojawia się na wejściu. Gdy pojawia się takie przerwanie można odczytywać zawartość rejestru ICRx aby obliczać właśnie czas pomiędzy zboczami. Oczywiście po wystąpieniu przerwania zmieniasz od razu rodzaj wyzwalanego zbocza na przeciwny. I masz załatwione wszystko w jednym. Poczytaj sobie o tym sprzętowym mechaniźmie. Dzięki temu nie trzeba pisać wiele kodu a i spora część innych zasobów jak przerwania INT0 czy INT1 u ciebie pozostają wolne i można użyć je jeszcze do czegoś innego.
  • #15 5747726
    zuraf
    Poziom 14  
    przeanalizowalem to jeszcze raz i na logike to nie ma co niedziałać. pomimo stałej czestotliwosci impulsów podawanych na int0 i int1, na wyswietlaczu wyswietlane sa naprzemiennie, z losowa czestotliwością "1" i "2". Układ pracuje na wewnętrznym oscylatorze. Czy jest to spowodowane jego niestabilną pracą, i zastosowanie zewnętrznego poprawi sprawę?

    $crystal = 1000000
    
    $regfile "m8def.dat"
    
    
    
     Config Timer1 = Timer , Prescale = 64
     Stop Timer1
    
    
     Config Int1 = Rising
      Config Int0 = Rising
     Timer1 = 0
    
    Enable Interrupts
    Enable Int1
    On Int1 Przerwanie1
    On Int0 Przerwanie0
    
     Dim Wynik As Single
    
    Declare Sub Cyfra
    Declare Sub Wyswietl
    Dim U As Byte
    Dim I As Word
    Dim A As Byte
    Dim P As Word
    
    Timer1 = 0
    
    A = 0
    Config Portc = Output
    Config Portd.1 = Output
    
    Portd.1 = 1
    Portc = &B11111111
    
    Do
    
    
    Loop
    
    Przerwanie1:
    
    A = A + 1
    
    
    
    
    If A = 1 Then Start Timer1
    
    If A = 2 Then
    Stop Timer1
    I = Timer1
    Timer1 = 0
    A = 0
    
    
    
    
    Disable Int1
    
    Enable Int0
    Waitms 30
    
    
    End If
    
    
    Return
    
    
    Przerwanie0:
    
    A = A + 1
    
    
    
    
    If A = 1 Then Start Timer1
    
    If A = 2 Then
    Stop Timer1
    P = Timer1
    Timer1 = 0
    A = 0
    
     Disable Int0
    
    Waitms 30
    
    Call Wyswietl
    End If
    
    
    Return
    
    
    Sub Wyswietl
    
     Wynik = I / P
    
      If Wynik > 1 Then U = 2
      If Wynik < 1 Then U = 1
    
      Call Cyfra
    
      Enable Int1
        Waitms 40
    
    End Sub
    
    
    Sub Cyfra
    
    Select Case U
    
    Case 1 : Portc = &B11011101
     Portd.1 = 1
    Case 2 : Portc = &B11001010
     Portd.1 = 0
    Case 3 : Portc = &B11001000
     Portd.1 = 1
    Case 4 : Portc = &B11010001
     Portd.1 = 1
    Case 5 : Portc = &B11100000
     Portd.1 = 1
    Case 6 : Portc = &B11100000
     Portd.1 = 0
    Case 7 : Portc = &B11001101
     Portd.1 = 1
    Case 8 : Portc = &B11000000
     Portd.1 = 0
    Case 9 : Portc = &B11000000
     Portd.1 = 1
    
    End Select
    
    
    End Sub
    
    End
    
    
REKLAMA