PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Drehzahlmesserprogramm funktioniert nur bis 7000 U/min HILFE



Tommy75
16.08.2007, 10:56
Hallo !

Ich habe hier ein Programm für einen Drehzahlmesser gefunden.
Benutze einen Mega 32 und 16 MHz Quartz.

Meine Frequenz liegt zwischen 20Hz und 200Hz.

Der Quellcode zeigt mir Frequenzen bis 117MHz (7000 U/min) richtig an.

Ab dann springt die Anzeige zurück auf 6000 und die Zählung wird fortgesetzt.

Woran kann denn das liegen ?

Wenn ich mir nur das Timerergebnis anzeigen lasse stimmt dieses über den ganzen Bereich. Der Fehler muss also in der Berechnung oder den Variablen liegen oder ?

Danke für eure Antwort.

Gruß

Hier der Code:

'-------------------------------------------------------------------
' Drehzahlmesser mit
' Messung der Periodendauer mit Timer1
'-------------------------------------------------------------------
$regfile = "m32def.dat" 'Mega32
$crystal = 16000000 '16 MHz Quarz

Config Pind.6 = Input
Portd.6 = 1

Dim Impulse As Byte
Dim D As Long
Dim W As Long
Dim W1 As Long
Dim W2 As Long
Dim W3 As Long
Config Timer1 = Timer , Prescale = 64 , Capture Edge = Rising

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

Waitms 50

Gosub Dog

On Ovf1 Overflow
On Icp1 Steigende_flanke
Enable Icp1
Enable Ovf1

Enable Interrupts




Main:

D = 0
W3 = 0

Impulse = 0

Cls
Cursor Off

Locate 1 , 1

Lcd "Drehzahl"

Locate 2 , 1

Lcd D

Lcd " UpM "


Tcnt1l = 0
Tcnt1h = 0


Do

nop

Loop

End


Steigende_flanke:

Disable Icp1
Disable Ovf1

W3 = Timer1

Timer1 = 0

W2 = W2 + W3

Incr Impulse

If Impulse = 6 Then

W1 = W2 * 400

W = W1 / 60


D = 600000000 / W

Locate 2 , 1

Lcd D

Lcd " UpM "

W = 0
W2 = 0
W3 = 0
D = 0
Impulse = 0

Else

End If

Enable Icp1
Enable Ovf1

Return


Overflow: ' Timer1 Ueberlauf, bei Stillstand.

Disable Icp1 ' Zahler auf Null setzen.
Disable Ovf1

D = 0

Locate 2 , 1

Lcd D

Lcd " UpM "

W = 0
W2 = 0
D = 0

Enable Icp1
Enable Ovf1
Timer1 = 0
Return




' ---------------------- LCD DOG162 Initialisieren -----------------------------

Dog:
Portb = &B00000011 : Gosub Enbl : Waitms 2 ' dummy Funktion Set
Portb = &B00000011 : Gosub Enbl : Waitms 2 ' dummy Funktion Set
Portb = &B00000011 : Gosub Enbl : Waitms 2 ' dummy Funktion Set
Portb = &B00000010 : Gosub Enbl : Waitms 1 ' dummy Funktion Set
Portb = &B00000010 : Gosub Enbl : Waitms 1 ' Funktion Set 1
Portb = &B00001001 : Gosub Enbl : Waitms 1 ' Funktion Set 2
Portb = &B00000001 : Gosub Enbl : Waitms 1 ' Bias 1
Portb = &B00001100 : Gosub Enbl : Waitms 1 ' Bias 2
Portb = &B00000101 : Gosub Enbl : Waitms 1 ' Power/Icon/Contrast 1
Portb = &B00000010 : Gosub Enbl : Waitms 1 ' Power/Icon/Contrast 2 Contrast =38
Portb = &B00000110 : Gosub Enbl : Waitms 1 ' Follower control 1
Portb = &B00001001 : Gosub Enbl : Waitms 1 ' Follower control 2
Portb = &B00000111 : Gosub Enbl : Waitms 1 ' Contrast Set 1
Portb = &B00000000 : Gosub Enbl : Waitms 1 ' Contrast Set 2 Contrast =38
Portb = &B00000000 : Gosub Enbl : Waitms 1 ' Display On 1
Portb = &B00001100 : Gosub Enbl : Waitms 1 ' Display On 2
Portb = &B00000000 : Gosub Enbl : Waitms 1 ' Clear Display 1
Portb = &B00000001 : Gosub Enbl : Waitms 2 ' Clear Display 2
Portb = &B00000010 : Gosub Enbl : Waitms 1 ' Funktion Set 1
Portb = &B00001000 : Gosub Enbl : Waitms 1 ' Funktion Set 2
Portb = &B00000000 : Gosub Enbl : Waitms 1 ' Entry Mode Set 1
Portb = &B00000110 : Gosub Enbl : Waitms 1 ' Entry Mode Set 2
Portb = &B00000000
Return
Enbl: ' Enable ein
Set Portb.4
Waitus 400 ' Enable aus
Reset Portb.4
Return
Rw:
Set Portb.5
Waitus 400
Reset Portb.5
Return

End

Tommy75
16.08.2007, 12:04
Problem hat sich erledigt.

Habs geschafft.

Habe die Capture ISR wie folgt geändert:



Steigende_flanke:

Disable Icp1
Disable Ovf1

W = Timer1

Timer1 = 0

Incr Impulse

If Impulse = 6 Then


D = 15000000 / W


Locate 2 , 1

Lcd D

Lcd " UpM "

W = 0
D = 0
Impulse = 0

Else

End If

Enable Icp1
Enable Ovf1

Return

linux_80
16.08.2007, 13:33
Hallo,

wenn du schon Capture verwendest könntest du auch das Capture-Register auslesen, dann wirds evtl. etwas genauer, da dort der Wert des Timers gesichert wird, als das Event aufgetreten ist. Man hat dann die Zeit erst andere Sachen zu erledigen, bzw. als erstes den Timer auf 0.

Dann musst Du in der ISR auch die beiden ISR's nicht disablen, da in dieser Zeit sowieso keine weitere auftreten kann, evtl. am Ende der ISR diese Flags zurücksetzen falls doch eine aufgetreten sein sollte. Aber zumindest kann man sich am Anfang die Zeit sparen.

Tommy75
16.08.2007, 15:51
8-[

Dachte ich hätte es schon richtig gemacht ?

Wie würde deine Lösung dann aussehen ?

Sorry aber bin neu auf dem Gebiet und freue mich immer über jede Lösung die ich finde.

So ganz perfekt ists noch ned. Ich will eigentlich die Drehzahl immer nur in Hunderter Werten haben.

Die Lösung hab ich aber noch ned gefunden. Weißt du das vielleicht abhilfe ?

Gruß Tommy

EDIT:

So oder ?


Steigende_flanke: 'ISR für Capture Ereignis

'Disable Icp1
'Disable Ovf1

Timer1 = 0

W = Capture1


'Timer löschen

Incr Impulse

If Impulse = 6 Then 'Damit die Anzeige ruhiger wird nur jeden 6.Impuls messen


D = 3750000 / W ' bei Prescaler 256 und 16Mhz
' 60000000 µs / 16µs = 3750000
' geteilt durch die Counts gibt Drehzahl

Select Case D: 'Schaltblitz ab 10500 U/min
Case 0 To 10499 : Led = 0
Case 10500 To 12000 : Led = 1
End Select

Locate 2 , 1

Lcd D

Lcd " UpM "

W = 0
D = 0
Impulse = 0

Else

End If

'Enable Icp1
'Enable Ovf1
W = 0

Return

linux_80
16.08.2007, 16:33
Wenn jeder gleich alles richtig machen würde, gäbs wohl keine Foren wie dieses hier :-)

Hab nur noch ein paar Tipps:
Die LCD-Sachen aus der ISR rauslassen, das dauert sonst viel zulange,
bau das ins Hauptprogramm, und mit einem Waitms 500, oder so, dazwischen.
So in etwa:

' Hauptschleife
Do
Disable Interrupts
' LCD-zeugs ...

Enable Interrupts
Waitms 500
Loop
Die Interrupts kann man hier ruhig kurz anhalten (wegen der langen Variablen), denn sollte in dieser Zeit in IRQ auftreten, merkt sich das Capture-Register den Timer-Wert, und gleich nach dem aktivieren wird die ISR aufgerufen.

Ansonsten könnt's schon was werden.

Tommy75
16.08.2007, 16:39
da hast recht ja. :-)

Werd ich probieren.

Mit den Zahlen auf hunderter anzeigen weißt au ned zufällig an rat ?

Mal was andres. Dieser Drehzahlmesser soll zusammen mit andren Sachen auf einem Screen angezeigt werden.

Unter andrem lese ich geschwindigkeit vom GPS und welcher gang eingelegt ist über gangsensor aus und zeige es zusammen mit der drehzahl an.

Wenn mir nun dauernd ein interrupt vom capture das andre unterbricht ist das doch schlecht oder ?

Gibts ne andre Möglichkeit die Drehzahl zu messen ohne interrupt oder ...

Gruß Tommy

linux_80
16.08.2007, 16:56
Wenn du nur auf hundert genau haben willst, einfach den Wert /100, und zwei nullen hinten dranhängen. :-k

Drehzahlmessen ohne Interrupt wird wohl schlecht gehen, man braucht ja ein definiertes Ergeignis (Zeit) damit man sich den Rest ausrechnen kann.

Du musst nur die ISR's so kurz wie möglich halten (evtl. auch die Berechnungen rausnehmen), und alle Ausgaben im Hauptprogramm machen. Dann klappts auch mir dem restlichen Programm.

Und, je schneller die Anzeige aktualisert wird, desto schlechter wird es das zu erkennen falls sich der Wert jedesmal ändern sollte, deswegen kann das ruhig im Hauptprogramm erledigt werden.

Tommy75
16.08.2007, 17:18
Okay, ich werde mal alle routinen zu einem Proggi zusammen basteln und dann probieren wie es klappt.

Ja, natürlich. Ich depp ....

Geteilt durch hundert und dann "00" anstellen. TS TS TS

Ich mach schon zulange....

Danke dir...

Gruß Tommy