Mäta frekvens med PIC från hallsensor

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
wolfheat
Inlägg: 202
Blev medlem: 14 oktober 2007, 20:42:51
Ort: Gävle

Mäta frekvens med PIC från hallsensor

Inlägg av wolfheat »

Funderar på något bra sätt att räkna om de insignaler jag får från hallsensorerna till rotationshastighet. Eller egentligen så vet jag inte hur jag skall skriva min kod för att PICen (använder 16F877A, kör i 4MHz-XT ) på ett bra sätt skall få fram med vilken frekvens insignalerna kommer.

Jag kommer röra mig mellan 0-50Hz och ta medelvärden typ var 5:e sekund. Så mitt problem är främst att jag vill mäta små frekvenser, men använder en klockfrekvens på 4MHz. Kollade en del på ifall man kunde använda Timer1-modulen som finns inbyggd i 877A:an men problemet är att man endast kan prescale:a den till 1:8 och vid 4MHz klockfrekvens blir det typ 0.5sek innan räkneverket är fyllt detta gör det svårt att mäta frekvenser under 2Hz.

Lite tips på vad jag bör kolla på eller någon metod som är användbar?

Tack för ett jättebra forum.
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

Låt timern rulla flera varv då, och räkna med en extern variabel när den slår över. Sätt prescalern så lågt som möjligt så du får din önskade upplösning.
Användarvisningsbild
squiz3r
Inlägg: 5424
Blev medlem: 5 september 2006, 20:06:22
Ort: Lund
Kontakt:

Inlägg av squiz3r »

Om du vill att den ska bli full snabbare så kan du ju lägga in ett värde i den från början. Ladda den med tex. F0, då kommer du ju bara få en 8bitars räknare.

Eller missförstog jag dig nu hur du tänkte använda den? Du kan ju (väll) ha den som counter, och inte räkna klockfreqvensen utan hur många signaler det kommer på porten. Om du tex. ställer timer2 så du var 5'e sekund kollar hur långt timer1 (extern triggning) har kommit, då ser du ju genomsnittet för de senaste 5 sekunderna.

Mvh
Användarvisningsbild
wolfheat
Inlägg: 202
Blev medlem: 14 oktober 2007, 20:42:51
Ort: Gävle

Inlägg av wolfheat »

Hmm, det är just det att den externa triggningen dvs den från hallsensorerna kan vara nere på 2Hz och då blir det rätt stor felmarginal om jag bara räknar hela pulser under 5sek. Upplösningen blir inte särskilt stor. Men det är möjligt att det kanske fungerar ändå. Annars kommer jag ha problemet att ifall jag har 0Hz så kommer jag fastna i loopen och behöver ta mig ut ur den medTimer interrupt eller WDT etc. I det fallet verkar det vara bättre att räkna antal pulser under 5sek trots felet.
Användarvisningsbild
squiz3r
Inlägg: 5424
Blev medlem: 5 september 2006, 20:06:22
Ort: Lund
Kontakt:

Inlägg av squiz3r »

mm.. Man kanske kunde mäta på längre tid och på något sätt räkna ut genomsnitt för de senaste 5 sekunderna.
Användarvisningsbild
wolfheat
Inlägg: 202
Blev medlem: 14 oktober 2007, 20:42:51
Ort: Gävle

Inlägg av wolfheat »

Det känns inte som en bra idé. det är så mycket andra mätningar jag vill ha tid till att mäta med PICen också. Pular med att komma på nåt bra sätt att lösa problemet. Men det känns som om fler borde ha gjort något liknande tidigare.
v-g
EF Sponsor
Inlägg: 7875
Blev medlem: 25 november 2005, 23:47:53
Ort: Kramforce

Inlägg av v-g »

Duger inte 16 BITs upplösning? Bara att köra räknaren såpass att den hinner med både 2 & 50 Hz. Problemet är bara att man får lite svårt med de lägre frekvenserna. Men tex så kan man känna av att räknaren "rundar" och om pulsen då ännu inte kommit så ökar man på en variabel och tar med denna i beräkningen. Glöm ej nolla den innan allt startar bara ;)

Det jag syftar på är alltså att räkna tid MELLAN pulser.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Inlägg av jesse »

Nu programmerar jag bara AVR, men skillnaden kan inte vara så stor när det gäller principen?
(ganska ungefärligt - det får finslipas en del)

Du fixar en Timer som slår över varje millisekund och skapar ett interrupt vid owerflow.

Kod: Markera allt

vid varje interrupt gör du följande:
--- interrrupt-sekvens----------
öka värdet med ETT i 16-bit räknare A
öka värdet med ETT i 16-bit räknare B

om A == 5000 så har det gått 5 sekunder och du sätter en flagga 5SEK och nollställer A
om B == 0 så har den slått över (65,536 sekunder!) och du sätter en flagga STILLA
--- interrrupt-sekvens-slut---------

Vid puls från Hallelementet får du ett interrupt  - och då händer följande:
--- interrrupt-sekvens----------
om flagga STILLA == 1 så betyder det att det är den första pulsen på 65 sekunder och värdet i B spolas eller sätts till lägsta hastighet, samt nollställer flagga B

annars:

du läser av värdet i B och kopierar över i ett register PULSTID.
nollställer B
sätter flagga PULS_IN
--- interrrupt-sekvens-slut---------

Huvudprogtammet gör följande:

initiera timer och interrupt
nollställ en massa variabler ...

LOOP:
  ; denna yttre loopen körs en gång var 5e sekund
TOT_HAST=0
PULSANTAL_PER_5_SEK=0

LOOP2:   ; loop 2 körs oavbrutet för att kolla om något har hänt...
     sleep      ; är ett kommando i AVR som försätter processorn i sovande tills ett interrupt
                   ; inträffar. Så slipper man bränna processorkraft då inget händer.
                   ; Kanske finns liknande i PIC?

kolla flagga PULS_IN == 1 ?
    ja.     ;  det har kommit in en puls från Hallelementet!
       öka PULSANTAL_PER_5SEK med ett   ; bra att räkna hur många pulser
       Beräkna hastighet med konstant   HAST=KONST/PULSTID
       addera TOT_HAST = TOT_HAST + HAST
   nej 
kolla flagga 5SEK == 1 ?
    ja
       ; ok nu har det gått fem sekunder och vi ska sammanfatta vad som hänt
       ;  PULSANTAL_PER_5SEK innehåller antalet pulser som kommit in
       om PULSANTAL_PER_5_SEK == 0  så är hastigheten noll, annars:
       MEDELHAST = TOT_HAST / PULSANTAL_PER_5_SEK
       Skriv ut medelhastighet
        hoppa till LOOP
    nej
        Åter till LOOP2
// okej, jag kanske har missat en del (orkar inte tänka så noga nu) men du har principen och den fungerar nog? Kommentera gärna om ni ser något som kanske borde gjorts på något annat vis (eller om något är helt tokigt :roll: )

EDIT: det är inte helt klart såhär. bl.a. måste flagga STILLA hanteras och nollställas på rätt ställe mm. mm..
Senast redigerad av jesse 18 maj 2008, 13:02:28, redigerad totalt 1 gång.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Nu är det en sak som är viktig här: vilken upplösning behöver du?

xx,xHz?
xx,xxHz?
Eller i RPM?

Innan det är besvarat kan lämpligaste sätt inte definieras. Jag hade likaväl använd CCP-enheten i Capture-mode, det går alldeles enkelt och bra att utöka tidsmätningen till 32 bit t.ex.
Senast redigerad av Icecap 15 maj 2008, 13:16:10, redigerad totalt 1 gång.
badtastex
Inlägg: 1116
Blev medlem: 17 februari 2007, 10:16:33
Ort: Borensberg
Kontakt:

Inlägg av badtastex »

Finns det någon mäjlighet att lägga till fler sensorer som mäter? På så sätt kan du ju få flera pulser per varv.

Annars borde en encoder vara nåt att tänka på.
Användarvisningsbild
wolfheat
Inlägg: 202
Blev medlem: 14 oktober 2007, 20:42:51
Ort: Gävle

Inlägg av wolfheat »

Det jag måste tänka på är dels att jag endast vill räkna pulsen när den går från 0 till 1 (alternativt 1 till 0). Dvs det räcker inte med att endast kolla om signalen är '1', men det problemet går att lösa.

Att räkna antal pulser under en viss tid. Så jag inte fastnar i loopen om nu frekvensen är 0Hz.

Om jag får en signal varje 2.49 eller 2.51sekund så kommer jag ha räknat till 2 respektive 1 under de 5 sekundrarna jag mäter. Jag kommer alltså ett ganska osäkert värde på frekvensen trots att det i stort sett är samma frekvens.

Ett alternativ är att man mäter både tiden mellan två pulser och antal pulser under 5 sek och sedan använder det värde som blir bäst.

Vet inte riktigt hur stor noggrannhet jag kommer behöva. Men XX.XXHz är antagligen mer än nödvändigt. Jag siktar på XX.XHz.

CCP-enheten har jag inte satt mig in i hur den funkar. Skall ske...

Tack för alla tips!
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Trillar man CCP-enheten rätt kan man utöka mätningen till hur många bytes man vill vid att fånga Timer1 OF-interrupts, man kan även använda det interrupt till att bestämma time-out (= 0,00Hz).

Sedan är "allt" klart, det är bara att dela den uppmätta tid i en konstant och resultatet är då i 1/10 eller 1/100 Hz.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Inlägg av jesse »

jag endast vill räkna pulsen när den går från 0 till 1

Med interrupt för uppåtgående flank så kommer du att veta exakt när signalen gick upp. Ingången borde avstöras med filter samt förses med en schmitt-trigger-grind för att inte felaktiga interrupr ska uppstå under en uppgående flank.

Att räkna antal pulser under en viss tid. Så jag inte fastnar i loopen om nu frekvensen är 0Hz.


Du fastnar inte i loopen om du gör som jag skrev innan... du har en räknare som mäter tiden och kollar helt enkelt om räknaren går för långt...

Om jag får en signal varje 2.49 eller 2.51sekund ..

så kommer du att få ett exakt värde om du mäter tiden som jag beskrivit. Du kan även mäta tider som är längre än 5 sekunder med mitt program ( upp till 65 sek) fast resultatet uppdateras givetvis inte lika ofta då. Det gäller bara att kopiera värdet från föregående femsekundersperiod för att inte få noll som svar varannan gång om det tar t.ex 5.4 sekunder mellan varven.

Ett alternativ är att man mäter både tiden mellan två pulser och antal pulser under 5 sek och sedan använder det värde som blir bäst.

ska inte behövas.

Jag siktar på XX.XHz.

Mitt exempel ger dålig noggrannhet vid höga frekvenser men det är lätt att åtgärda - jag tog exemplet att öka timern varje millisekund = dålig upplösning. Det går att minska till 0.01 ms utan problem (då har man 40 instruktioner på sig att köra interruptrutin + huvudprogram vilket torde räcka) och ger då noggrannheten 0.025 Hz vid 50 Hz. Ju lägre frekvens desto bättre noggrannhet. EDIT: men då måste du antagligen använda tre bytes för tidräknarna istället för två. Och då kanske divisionen blir lite mer avancerad,,,

(hoppas mitt exempel tillförde något och att det var begripligt!)
Skriv svar