Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[Mega8][Bascom] Pomiar prędkości obrotowej

17 Mar 2010 12:33 3813 13
  • Poziom 9  
    Celem jest pomiar prędkosci obrotowej. Program się kompiluje, ale wyświetla cały czas 0.0 rpm. Nie wiem gdzie tkwi błąd, czy ktoś może mi pomóc?

    Code:

    $regfile = "m8def.dat"
    $crystal = 8000000

    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5

    Config Timer1 = Timer , Prescale = 8 , Capture Edge = Rising
    Config Int0 = Rising


    Dim Wynik As Single
    Dim Zmienna As Single


    Enable Interrupts
    Enable Timer1
    Enable Int0



    On Int0 Przerwanie

    Do
    cls

    Lcd "obrotomierz"
    Lowerline
    Lcd Wynik ; " rpm"
    Loop
    End


    Przerwanie:

    Stop Timer1
    Zmienna = Timer1
    Wynik = 60000000 / Zmienna
    Start Timer1

    Return

  • Poziom 34  
    Wstaw przed Do instrukcję Start Timer1. Z helpa nie wynika, że Config włącza timer automatycznie, a jeśli ten się nie uruchomi to nie będzie przerwania i nie zadziałają instrukcje Start/Stop w podprogramie obsługi przerwania.

    P. S. Nie miga ci wyświetlacz? Zastosuj Locate albo Upperline zamiast CLS.
  • Poziom 38  
    Sprawdź połączenia- czy na wejście INT0 wchodzi jakiś sygnał.
  • Poziom 9  
    OK, dzięki;) Faktycznie, sygnał miałem podpięty do pind.5...
  • Poziom 38  
    Co nie zmienia faktu że głopoty pokazuje.
  • Poziom 36  
    nauritius napisał:
    Celem jest pomiar prędkosci obrotowej.


    Ta czesc twojej wypowiedzi rozumiem, ale dalej jest gorzej.
    Z listingu programu nie mozna doszukac sie jaka metode przyjmujesz w pomiarze RPM.
    Czy to ma byc zwyczajny pomiar czasu jednego obrotu i przliczenie na RPM (pomiar pomiedzy dwoma 'rising edges') z uzyciem jednego z timerow i jednego interruptu, czy tez w okreslonych przedzialach czasu masz zamiar zliczac ilosc impulsow (obrotow) i to przeliczyc na RPM (z usrednianiem wyniku albo bez).

    Masz Timer1 skonfigurowany do pracy w trybie 'Capture".
    Tryb ten ma swoj interrupt ICP1 sterowany na pin PB0, ale musialby on byc uruchomiony i dopisana odpowiednia procedura co ma byc zrobione na okolicznosc wystapienia "Capture1". Inaczej nic z tego.

    W zaleznosci od wybranej metody bedzie inna procedura pomiaru i obliczania wyniku.
    Najprosciej i najlatwiej zrobisz to stosujac Timer0 i Interrupt powiedzmy INT0.
    Zliczaj do jednej zmiennej przepelnienia timera0.
    W momencie wystapienia INT0 kopiujesz stan Timera0 do innej zmiennej a takze stawiasz flage np: F=1
    W petli Do ... loop dajesz caly rachunek obliczenia wszystkich zliczonych przedzialow czasowych, przeliczenie tego na RPM, kasowanie flagi i wyswietlenie wyniku na LCD. Aby nie "mrugac" wyswietlasz tylko zmienione wartosci na display

    e marcus.
  • Pomocny post
    Poziom 43  
    emarcus napisał:
    Z listingu programu nie mozna doszukac sie jaka metode przyjmujesz w pomiarze RPM.

    Ja jakoś się doszukałem. A nie, sory. Nawet doszukiwać się nie musiałem.
    Liczy okres pomiędzy impulsami.

    Ale przerwanie to powinno wyglądać tak:
    Code:

    Przerwanie:
    Zmienna = Timer1
    Timer1 = 0
    Wynik = 7500000 / Zmienna
    Return


    Preskaler Timera ustaw na 64.

    A:
    Code:

    Capture Edge = Rising

    przy konfiguracji Timera jako "Timer" jest niepotrzebne (w sumie to nawet błędne).

    Pomijam już to że te całe obliczenia to trzeba by robić w pętli głównej. Tak jak napisał emarcus.
  • Poziom 9  
    Nie byłem pewien, czy Capture Edge jest potrzebne, ale sprawa już się wyjaśniła. Na razie nie mam możliwości "polowego" przetestowania, bo coś szwankuje mi generator. Mierze okres między dwoma impulsami (zbocza narastające). Przy prescalerze 8 minimalna mierzona prędkość to ok. 920rpm, także dodam jeszcze fragment zliczający przepełnienia. Dlaczego prescale 64 byłby lepszy? Czy nie zmniejszy się dokładność?
  • Poziom 43  
    Preskale 64 był by lepszy bo mógł byś mierzyć mniejsze prędkości.
  • Poziom 9  
    Zrobiłem przypadek ze zliczaniem przepełnień timera1:

    Code:

    $regfile = "m8def.dat"
    $crystal = 8000000

    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5

    Config Timer1 = Timer , Prescale = 8
    Config Int0 = Rising


    Dim Wynik As Single
    Dim Zmienna As Single
    Dim Zmienna2 As Single
    Dim M As Byte
    Dim N As Byte


    Enable Interrupts
    Enable Timer1
    Enable Int0

    M = 0                                                       'ilość przepelnien timera1
    N = 0                                                       '0-pierwszy pomiar;1-pomiary kolejne
    On Int0 Przerwanie

    Do

    If Timer1 = 65536 Then
       Stop Timer1
       Timer1 = 0
       Incr M
       Start Timer1
    End If

    Wynik = 60000000 / Zmienna                                  'obliczanie rpm
    Cls
    Lcd "obrotomierz"
    Lowerline
    Lcd Wynik ; " rpm"

    Loop
    End


    Przerwanie:

    Stop Timer1
    If N = 0 Then                                               'sprawdzam, czy to pierwszy pomiar
       Start Timer1
       N = 1                                                    'ustawiam,ze pierwszy pomiar wykonano
       Return
    Else
       If M = 0 Then                                            ' rpm mieszcza sie w zakresie  licznika timer1
       Zmienna = Timer1
       Else                                                     'nastapiło m przepelnien
       Zmienna2 = M * 65536
       Zmienna = Zmienna2 + Timer1
       Timer1 = 0
       M = 0
       N = 1
       End If
    End If
    Start Timer1

    Return


    jak myślicie, zadziała? Mam takie pytania:
    1. Czy stop timer1 automatycznie zeruje timer?
    2. Opłaca się uwzględniać, to , że w pierwszym przerwaniu będe miał 0-rowy okres?
  • Poziom 43  
    1. Nie.
    2. Też nie.

    Ale opłacało by się zrobić sprawdzanie przekroczenia zakresu. Bo bez tego jak znikną impulsy to układ zamarznie na ostatnim wskazaniu.
    A w tym programie strasznie nakombinowałeś.
    Ja bym po prostu dodał jedną zmienną od przepełnienia:
    Code:

    '--------------------------------------
    Dim Okres As Long
    Dim Predkosc As Single
    Dim Timer1_MSB As Byte

    Do
      If Flaga = 1 Then
          cli
          Predkosc = Okres  'atomowy dostęp do zmiennej bo przerwanie od Timera też z niej korzysta
          sei

          Predkosc = 7500000 / Predkosc
          Flaga = 0

          ...
          ...
      End If
    Loop
    '--------------------------------------
    Przerwanie_INT0:
        Okres = Timer1_MSB
        Shift Okres, Left, 16
        Okres = Okres + Timer1

        Timer1 = 0
        Timer1_MSB = 0

        Flaga = 1
    Return
    '--------------------------------------
    Przerwanie_Timer1:
        Timer1_MSB = Timer1_MSB + 1

        If Timer1_MSB >= 100 Then  'Zabezpieczenie przed przepełnieniem
            Timer1 = 0
            Timer1_MSB = 0

            Predkosc = 0
        End If
    Return
    '--------------------------------------
  • Poziom 36  
    atom1477 napisał:

    Ja jakoś się doszukałem. A nie, sory. Nawet doszukiwać się nie musiałem.
    Liczy okres pomiędzy impulsami.



    Eh, Nie kazdy nosi imie Albert...

    e marcus
  • Poziom 43  
    No nie każdy. Ja też nie noszę ;)
  • Pomocny post
    Poziom 38  
    Code:

    'Działa od 30rpm do 300000rpm

    $regfile = "m8def.dat"
    $crystal = 8000000

    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.4 , Rs = Portc.5
    Config Timer1 = Timer , Prescale = 64
    Config Int0 = Rising

    Dim Flaga As Byte
    Dim Text As String * 10
    Dim Wynik As Single
    Dim Zmienna As Word
    Dim Okres As Long
    Dim Predkosc As Single
    Dim Timer1_msb As Byte

    Enable Interrupts

    Enable Int0
    enable OVF1

    Cls
    Lcd "obrotomierz"
    Cursor Off

    On Int0 Przerwanie_int0
    On Ovf1 Przerwanie_timer1

    Do
       If Flaga = 1 Then
          cli
          Predkosc = Okres        'atomowy dostęp do zmiennej bo przerwanie od Timera też z niej korzysta
          sei
          Wynik = 7500000 / Predkosc
          Flaga = 0
          Text = Fusing(wynik , "#.&")     
          Lowerline
          Lcd "rpm: " ; Text ;"             "
        End If
    Loop

    Przerwanie_int0:

        Okres = Timer1_msb
        Shift Okres , Left , 16   'a tu była mała pomyłka
        Okres = Okres + Timer1
        Timer1 = 0
        Timer1_msb = 0
        Flaga = 1

    Return

    Przerwanie_timer1:
        'Timer1_msb = Timer1_msb + 1;  'A to nie działa-nie wiem dlaczego
      Incr Timer1_msb
        If Timer1_msb >= 100 Then 'Zabezpieczenie przed przepełnieniem
            Timer1 = 0
            Timer1_msb = 0
            Predkosc = 0
        End If
    Return

    Chociaż wynalazków atoma to tak do końca nie rozumiem- ale chyba ten typ tak ma.
    No ale sprawdziłem w praktyce- działa.
    Pewnie sam bym to starał się zrobić w bardziej tradycyjny sposób- a nie tak "atomowy"- ale pewnie by zajęło więcej kodu.
    P.S.
    Przy braku impulsów na INT pokazuje ostatni wynik- a nie 0.