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.

[atmega8][BASCOM] liczenie czasu miedzy impulsami

zuraf 29 Paź 2008 21:40 3053 14
  • #1 29 Paź 2008 21:40
    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? :

    Code:
    $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]

    0 14
  • #2 29 Paź 2008 23:14
    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

    0
  • #3 29 Paź 2008 23:20
    komanche
    Poziom 13  

    właśnie.

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

    Code:


    $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
     

    0
  • #4 29 Paź 2008 23:31
    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:)

    0
  • #5 29 Paź 2008 23:40
    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.

    0
  • #6 30 Paź 2008 00:04
    zuraf
    Poziom 14  

    wiem co to sinusoida. z tym że to moje bedzie "zasilane" prostokątami, ale to chyba nie powino mieć znacznia.

    0
  • #8 30 Paź 2008 22:52
    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.

    0
  • #9 30 Paź 2008 23:00
    ZbeeGin
    Poziom 38  

    Ź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?

    0
  • #10 30 Paź 2008 23:05
    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?

    0
  • #11 30 Paź 2008 23:17
    ZbeeGin
    Poziom 38  

    "Listen very carefully - I shall say this only once."

    0
  • #12 30 Paź 2008 23:28
    zuraf
    Poziom 14  

    po prostu nie jestem pro w tej dziedzinie i chciałem się upewnić, czy dobrze rozumiem:)

    0
  • #13 31 Paź 2008 00:23
    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.

    0
  • #14 31 Paź 2008 03:07
    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.

    0
  • #15 16 Lis 2008 21:32
    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ę?

    Code:
    $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

    0