Zeitmessung am Hallschalter

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo Forum,

    zur Zeit beschäftige ich mich damit ein paar Sensoren in ein RC-Auto einzubauen und mit dem Raspi auszulesen. Nachdem ich es nun geschafft habe, dass mein Auto seine LEDs anschaltet, wenn es dunkel wird, wäre es auch noch hübsch die Drehzahl der Antriebswelle auszulesen. Dazu habe ich mir einen Hallschalter (PIC H501) besorgt und einen kleinen Magneten an einem Zahnrad am Ende der Welle angebracht. Soweit... so gut.
    Die Signale sehen am Oszi ganz brauchbar aus. HIGH-Pegel (3,3V) wenn sich Magnet und Sensor nicht gegenüberstehen und LOW (geht gegen Null) dementsprechend als Puls.
    Bei langsamer Fahrt wird eine Wellenumlaufdauer von ca. 62,5ms angezeigt und die Pulsdauer entspricht ca. 5ms, bei Höchstgeschwindigkeit sind es ca. 9,37ms bzw. 0,75ms (HIGH:LOW demnach ungefähr 12,5:1).

    Für die Aufnahme der Werte im Pi sehe ich bis jetzt zwei Möglichkeiten für mich:
    1. Da ich sowieso schon einen AD-Wandler verbaut habe, hab ich zu Testzwecken das Hallsignal mal auf einen Kanal gelegt. Gibt mir für HIGH > 900 und für LOW < 100 aus. Könnte man also einfach so abfragen und prüfen wie lange der Wert unter 100 (oder lass es ruhig 500 sein) liegt.

    2. Wahrscheinlich eleganter: ich benutze eine event detection für die fallende Flanke (vermutlich mittels:

    Code
    void bcm2835_gpio_fen 	( 	uint8_t  	pin	)

    ) und messe die Zeit zwischen zwei Events.

    Spätestens da liegt dann aber auch der Hund für mich begraben... Aus Schulzeiten hatte ich das bei der Programmierung am ATmega nicht mehr als so schwierig in Erinnerung (Zugriff auf Timer - Clock_Devide einstellen - Overflows zählen...), beim Pi ist mir aber leider nicht klar wie ich den Punkt "Zeitmessung" hier vernünftig unterbringen kann. Gibt es für einen meiner beide Ansätze schon eine bewährte Methode oder bin ich komplett auf dem Holzweg?

    Recht herzlichen Dank für ihre Aufmerksamkeit

    Einmal editiert, zuletzt von pi'ster (31. Juli 2014 um 15:23)

  • Hi,

    Du verwendest doch die bcm2835-Library von mikem ...
    hast Du mal nachgesehen - der sollte doch entsprechende Hires-Routinen zur Verfügung stellen.

    Achte aber darauf, ob das alles so klappt mit dem Interrupt-Handling.
    Ich bin damals damit auf die Nase gefallen (Programm eingefroren) und nutze seitdem die pigpio-lib.

    cheers,
    -ds-

  • Habe nochmal in der Library nachgeschaut und bin dann auf folgendes gestoßen:

    Code
    uint64_t bcm2835_st_read 	( void ) 	
    
    
    /*Read the System Timer Counter register.
    
    
    Returns
        the value read from the System Timer Counter Lower 32 bits register*/

    In Zusammenhang mit dem bcm2835-datasheet (S.172ff.) verstehe ich das ganze jetzt so:

    Mit oben genanntem Befehl kann ich die 32 LSBits des Timers auslese, die bei einem Takt von 700MHz ungefähr 6,135...s bis zu einem Überlauf brauchen müssten(?).

    Dann würde ich ja mit meiner max. 62,5ms lange Messung reichlich hinkommen, bzw. müsste bei der Berechnung der Zeitdifferenz zwischen zwei Ereignissen (hier: fallende Flanke) nur für einen negativen Wert einen evtl. Überlauf berücksichtigen. Weiteres "herummanipulieren" am Timer, bzw. Interrupts, die von diesem ausgelöst wären sind für meine Zwecke ja überflüssig.

    P.S.: Meintest du ungefähr sowas mit "Hires-Routinen"? Der Begriff war mir leider noch nicht bekannt :daumendreh2:

  • Hallöle,

    im Prinzip ist das wohl richtig, was Du da schreibst.
    Allerdings glaube ich, dass der Timer keine 700 MHz als Takt verwendet, sondern Mikrosekunden als Einheit hat.
    Müsste man mal genauer eruieren ... ich hab' jetzt auf die Schnelle nix verbindliches gefunden ( nur so was -> hier <- oder -> so was <-).

    //EDIT:
    HiRes = High Resolution ;) ... hast Du richtig erkannt - hochauflösende Timer Routinen

    cheers,
    -ds-

  • Danke schonmal für die Tipps.

    Die Vermutung mit dem µs-Timer (bzw. 1 MHz-Timer) bestätigen auch noch andere Quellen [1] [2] [3]

    Demnach sollte ein Durchlauf ca. 4295sek dauern, was ja mehr als einer Stunde entspricht. Dass ich da mit meinem Zeitfenster von 62,5ms nun gerade einen Überlauf erwische ist zwar mehr als unwahrscheinlich, aaaaber "Der Teufel ist ein Eichhörnchen"...

    Wenn ich mittels "bcm2835_st_read" nun aber ein 32-bit Register auslese wie in der Anleitung beschrieben, warum soll ich das Ergebnis dann nach datasheet in einer uint64_t erhalten?

  • Gute Frage ...

    ich vermute mal, dass das Register/der ausgelesene Wert uint64_t ist, aber nur die unteren 32 Bit relevant sind.
    Wäre für mich zumindest logisch ...

    Und das mit dem Überlauf ... nimm doch abs(differenz) ... dann kann es Dir wurscht sein ;) ...

    cheers,
    -ds-

  • Hab mich jetzt mal wieder meinem Problem gewidmet und bin in der Testphase auf eine neue Herausforderung gestoßen, die auch in einem anderen Thread schon einmal erwähnt, aber nicht beantwortet wurde.
    Kurz gesagt: Wenn ich versuche einen low-Pegel, wie im bcm2835-Beispielprogramm "event.c"
    durch

    Code
    void bcm2835_gpio_len ( uint8_t pin)


    beschrieben, detektieren zu lassen, dann hängt sich der Pi auf und reagiert auf nichts mehr, so lange dieser low-Pegel / Masse anliegt. Danach läuft alles wieder scheinbar normal. Die vom Programm geforderte Ausgabe wird deshalb aber auch nicht getätigt.
    Anscheinend tritt dieses Verhalten ja nicht nur bei mir auf :(
    Hat jemand vllt auch schon ähnliche Erfahrungen gemacht und evtl. einen Lösungsansatz parat?

    Grüße

    Edit: Habe in der bcm2835-Beschreibung noch folgendes gefunden

    /// Tested on debian6-19-04-2012, 2012-07-15-wheezy-raspbian and Occidentalisv01
    /// CAUTION: it has been observed that when detect enables such as bcm2835_gpio_len()
    /// are used and the pin is pulled LOW
    /// it can cause temporary hangs on 2012-07-15-wheezy-raspbian and Occidentalisv01.
    /// Reason for this is not yet determined, but suspect that an interrupt handler is
    /// hitting a hard loop on those OSs.
    /// If you must use bcm2835_gpio_len() and friends, make sure you disable the pins with
    /// bcm2835_gpio_cler_len() and friends after use.

    Einmal editiert, zuletzt von pi'ster (27. August 2014 um 10:18)

  • Das mit den Interrupts funktioniert bei mir auch nicht, bin daher auf Polling umgestiegen...-.-

    eventuell funktionierts mit einer anderen Bibliothek, für eine Lösung mit Interrupts würde ich mich auch interessieren :thumbs1:

  • Moin ...

    probiert mal pigpio - das ist ganz klar mein Favorit.
    Von der bcm2835 bin ich vor längerer Zeit abgekommen. Da gab's ein Problem mit dem Interrupt-Handling und der Autor wollte/konnte dazu nichts weiter sagen. Dazu müsste evtl. hier im Forum sogar noch ein Beitrag von mir existieren ...

    cheers,
    -ds-

  • Mahlzeit,

    hab jetzt erstmal (um die Funktion schnell umsetzen zu können) die unelegante Lösung über Polling mit zwei while-schleifen, welche die Pegeländerung abwarten, gewählt. Sobald das steht und ich anfange die unterschiedlichen Funktionen zu einem Komplettprogramm zusamenzufügen, werde ich dann versuchen die Verbesserung über den interrupt mit pgpio zu implementieren. Geben dann hier weiterhin meine Fortschritte zum Besten!

    Danke erstmal soweit!

  • Die Methode über Polling hat letztendlich nicht den gewünschten Erfolg erziehlt, weil sie 1. zu ungenaue Werte ausgibt und 2. immer mal wieder dazu neigt eine
    Umdrehung zu überspringen. Das könnte daran liegen, dass der Prozessor unter Vollauslastung ja trotzdem noch gewisse andere Dinge tun muss und in dieser Zeit eben nicht den Pegel abfragen kann und so den ein oder anderen Wechsel verpasst.

    In der angesprochenen pigpio-library gibt es praktischerweise ein Beispielprogramm, was den Titel hall.c trägt und im Groben das tut, was ich für eine Drehzahlmessung brauche: es setzt einen Timestamp bei Pegelwechsel und einen weiteren bei erneutem Pegelwechsel und gibt jeweils die Dauer zwischen den beiden aus.

    Mit zwei Extra-Variablen (zur Fallunterscheidung von high- bzw. low-pegel) und der Addition von beiden gibt das Programm nun die Umdrehungsdauer der Welle aus und kann nach einer weiteren Zeile Voodoo dementsprechend natürlich den Kehrwert (sprich: die Drehzahl) ausgeben.

    Bin ganz zufrieden mit der Lösung. Vielen Dank an dreamshader für den Hinweis!

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!