Forum: Mikrocontroller und Digitale Elektronik Timing Problem


von Hias (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe ein Timing Problem.
Aber zuerst eine kleine Vorgeschichte:

Ich erzeuge für PC-Lüfter ein PWM - Signal, dass zur Regelung
dergleichen benutzt werden soll. Da ich 6 verschiedene Kanäle haben
möchte, erzeuge ich PWM per Software. Die Frequenz der PWM ist ungefähr
(50Hz). Diese Frequenz wird für alle Kanäle in Timer0 erzeugt. (8bit)
Dabei ist die Timerfrequenz etwa 5kHz. Die Timer-Interrupt-Schleife
dauert ungefähr 30 Taktzyklen.

Jetzt möchte ich noch die Drehzahl der 6 Lüfter auslesen.
Da denke viel PWM und Drehzahlauslesung macht Probleme. Ich denke ich
habe aber das PWM Signal ausreichend geglättet. Ich habe vom
DREHZAHL-Signal (Pullup und Kondensator gegen Masse an
Open-Kollektor-Ausgang des Lüfters) am Oszi a Bild gemacht (siehe
Anhang). Ich kann zumindest keine Verunreinigung des Signals
verstellen. Ihr etwa?

Um die Drehzahl zu bestimmen möchte ich die Zeit zwischen zwei Impulsen
messen.
Dazu warte ich auf ein „high“ und starte dann den Timer1(16bit). Teste
dann auf „low“ und stoppe schließlich den Timer bei einem erneuten
high.
Zur Info: Impulslängen des Drehzahlsignals zwischen 5ms und 100ms.

Hier ein kleiner Codeausschnitt den ich zum Testen meiner Idee
verwendet habe…
1
main:    
2
step1:    sbis pinb,1      ;Test ob pinb 1 (Kanal1) high
3
    rjmp step1      
4
    ldi r16,0x00
5
    out tcnt1l,r16      ;Timer löschen (Timer starten)
6
    out tcnt1h,r16
7
8
step2:    sbic pinb,1      ;low-Test
9
    rjmp step2
10
        
11
step3:    sbis pinb,1      ;high-Test
12
    rjmp step3
13
    
14
    in cl,tcnt1l      ;Timer stoppen
15
    in ch,tcnt1h
16
    sts canal1l,cl      ;speichern
17
    sts canal1h,ch      ;speichern
18
    
19
    ;Hier kommt später noch eine umwandlung von steps in rpm
20
    
21
step4:    rjmp main

Anmerkungen: cl und ch sind Register,  die später zur Umrechnung von
steps in rpm benötigt wird. Diese werden zum Testen einfach im RAM
gespeichert um per UART ausgelesen werden können.

Nun ja genau da liegt mein Problem. Ich erhalte jedes Mal wenn ich die
steps Auslese extrem unterschiedliche Werte.
Warum nur? Ich komm einfach nicht weiter.
Wo liegt mein Fehler?

Danke schon mal…

MfG Hias

P.S.: Kompletter Code im Anhang des nächsten Beitrags.

von Hias (Gast)


Angehängte Dateien:

Lesenswert?

Hier der Code

von Santa Klaus (Gast)


Lesenswert?

>Um die Drehzahl zu bestimmen möchte ich die Zeit zwischen zwei
Impulsen
>messen.
>Dazu warte ich auf ein „high“ und starte dann den Timer1(16bit).
Teste
>dann auf „low“ und stoppe schließlich den Timer bei einem erneuten
>high.

Was ist, wenn Du im laufenden Betrieb den Drehzahlsensor-Kabel-Stecker
abziehst?  Dann tritt das Ereignis, auf das Du in der "step2"- bzw.
"step3"-Schleife des Hauptprogramms wartest, niemals auf.  Bleibt
dann Dein Programm (bis auf die interruptgesteuerten Sachen) stehen?
Ist dieses Verhalten erwünscht?  Wenn nicht, wie könntest Du die
Zeitmessung anders durchführen?  Ginge es möglicherweise auch ohne
Warteschleife (!) im Hauptprogramm?  Und wenn ja, wie?

von Hias (Gast)


Lesenswert?

Ich hab das nur zwecks der Einfachheit halber geändert. Wenn du in
komplett-code nachschaust das siehst du das des auch weiterläuft.
Ich könnte auch die ganze Zeit den Zustand der Pins einlesen und
schauen ob sich was geändert hat, ja. Aber das ändert nichts mit dem
Problem des 2.Timers!? Der Funkt da anscheinend immer dazwischen.

Was ich mir inzwischen angeschaut habe is ICP. Mal probieren ob des
besser geht. Könnte ja dann einen Multiplexer verwenden und könnte
somit auch alle 6 Kanäle abfragen.

Aber vielleicht gehts ja auch ohne. Ich verlass mich da ganz auf
euch... : )

MfG Hias

von Santa Klaus (Gast)


Lesenswert?

>Wenn du in komplett-code nachschaust das siehst du das des auch
>weiterläuft.

Ich will nicht rechthaberisch sein, aber ich sehe das überhaupt nicht.
Ich lese dort:

step2:  sbic pinb,1        ;low-Test
        rjmp step2

Wenn die Bedingung "Bit 1 von pinb ist gesetzt" ab einem bestimmten
Zeitpunkt niemals mehr auftritt (Sensorkabel abgezogen), dann kommt der
Controller doch niemals mehr aus dieser "step2"-Schleife raus (wie
sollte er denn?), oder sehe ich das falsch?

>Ich könnte auch die ganze Zeit den Zustand der Pins einlesen und
>schauen ob sich was geändert hat, ja.

Was bedeutet "die ganze Zeit"?  Hätte es einen Vorteil, wenn Du den
Zustand der Pins in einem genau definierten Zeitintervall (z. B. 0.2
ms) einlesen könntest?  Wie könntest Du Dir ein solches "periodisches
Ereignis" in genau definierten Zeitabständen "beschaffen"?  Oder
vielleicht gibt es ein solches sogar schon in Deinem Progamm?
Vielleicht brauchst Du gar keinen 2. (3., 4., 5. ...) Timer, sondern
nur einen einzigen?

von Hannes L. (hannes)


Lesenswert?

Moin...

Dein Programm ist mehr als nur die ISR, daher solltest du unbedingt den
Stackpointer sichern.

Es gibt noch eine schnellere Möglichkeit, in der ISR eine Mehrkanal-PWM
zu generieren, da werden die durch die Vergleiche beeinflussten
Carry-Flags in ein Register geschoben (eingesammelt) und dieses per OUT
ausgegeben, worauf die "abgelaufenen" Kanäle mit nur einem I/O-Zugriff
abgeschaltet werden. Das geht natürlich nur, wenn alle PWMs in einer
Reihe an einem Port hängen. Für andere Zwecke benutzte Pins dieses
Ports sind zu maskieren (vorher einlesen).

Die Drehzahlen kannst du auch in der ISR ermitteln:

- Erstmal in der ISR einen Zähler hochzählen.

- Dann einfach Port einlesen und mit dem zuletzt eingelesenen Wert
(bitweise) vergleichen (das dürfte ganz gut mit einer abgespeckten
Variante von Peter Danneggers Tastenentprellung gehen, Einlesen und
Bitmanipulation in der ISR, Auswertung von keypress bzw. tfl im
Hauptprogramm).

- Bei Bitänderungen (nur eine Richtung auswerten, damit eine volle
Umdrehung gemessen wird) Differenz  zur letzten Änderung übernehmen
(das ist dann der Istwert einer Umdrehung in der Zeiteinheit
"Timer-Interrupts") und aktuellen Zählerstand für nächste
Differenzermittlung speichern (für jeden Lüfter eine Speicherstelle).

- Möglichst mit Periodendauer ("Zeitdauer einer Umdrehung") rechnen,
das erpart zeitaufwendige Divisionen im AVR. Dafür lieber in der
PC-Software Drehzahl in Periodendauer umrechnen.

- Du nennst im ersten Beitrag die Timer-ISR-Frequenz von 5kHz (0,2ms
Int-Abstand), und die Lüfterperiode von 5ms...100ms. Das wäre ein
Zahlenbereich (für die Zeitmessung) von 25 ISRs/Umdrehung (ganz
schnell) bis 500 ISRs/Umdrehung (ganz langsam). Da wirst du dann wohl
in 16-Bit rechnen müssen.

Nun lass dir diese Gedankengänge mal auf der Zunge zergehen und
berichte dann mal, was daraus geworden ist.

...

von Hannes L. (hannes)


Lesenswert?

Quatsch... Stackpointer sichern... - Das SREG natürlich... (Ich kann
einen Blödsinn schreiben...)

...

von Hias (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!
Hab heute wieder ein wenig gebastelt:

Ergebnis: ich bekomme endlich eine Drehzahl die in etwa stimmen
könnte.

Ich habe wie gesagt den ICP verwendet.
Um auf 8 Kanäle zu kommen verwende ich einen Mulitplexer (74HCT151).
Das funktioniert soweit ganz gut.

Nur ein Problem habe ich:

Ich bekomme komischerweise bei 5 Messungen hintereinander nie die
gleichen Werte. Und immer wieder ist ein extremer Ausreißer dabei.

z.B. (hex)
661, 668, 6A7, 651, 3AC, 66A,....

natürlich sieht das blöd auf einem LCD aus, wenn die Werte so stark
springen...

an was liegt das?
Ideen zur Löung des Problems?

Den Teil des Codes zur Messung findet ihr im Anhang.
drehzahl wird als icp-isr aufgerufen...

MfG Hias

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.