PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Nach Reset falsche Berechnung!?



drivepro82
08.11.2008, 08:36
Hallo!
Ich habe auf einem Mega16 mit dem RN-Control Board unter Bascom eine Drehzahlmessung (und Drehgradientenmessung) programmiert (s.u.). Das Programm funktioniert auch soweit. Das einzige Problem ist, dass wenn man den Reset-Taster betätigt, während eine Frequenz am Interrupt anliegt, viel zu große Werte raus kommen, und zwar immer die gleichen, bei der jeweiligen Frequenz. Das geschieht nicht, wenn man Reset betätigt während keine Frequenz anliegt. Nach dem Starten des Programms kann dann die Frequenz verändert werden, was auch richtig angezeigt wird. Teilweise tritt dieser Fehler auch einfach so auf, bei höheren Frequenzen. Und dann kommt man nicht mehr auf einen vernünftigen Wert zurück, ohne die Ferquenz auf Null zu fahren und dann Reset zu drücken.
Sollte der Controller bei einem Reset das Programm nicht von ganz vorne starten?? Wenn das so wäre müsste auch bei anliegender Frequenz ein richtiger Wert angezeigt werden, oder??
Hat jemand ne Idee, wo der Fehler liegen könnte?


Hier mein Programm:


'################################################# ##
'LVA_Drehzahlmessung.BAS

'Diese Programm ermittelt über die Signale einer Lichtschranke
'die Drehzahl am Motorenprüfstand 1 des LVA an der Fachhochschule Köln.
'Die ermittelte Drehzahl und der Drehzahlgradient werden an D/A-Wandler gegeben,
'die eine analoge Spannung ausgeben, für die Weiterverarbeitung in der folgenden
'Regelungselektronik.

'Autor: Christian Hungenberg
'################################################# ######



$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000 'Angabe der Quarzfrequenz
$baud = 9600


Config Int0 = Falling 'Der Interrupt wird bei fallendem Flankensignal aktiviert
Config Timer1 = Timer , Prescale = 256 'Timer 1 (16-bit Timer)


Config Spi = Soft , Din = Pinc.5 , Dout = Portc.1 , Ss = None , Clock = Portc.0 'Konfiguration der Software SPI
Config Portc.2 = Output 'Ausgang für CS1
Config Portc.3 = Output 'Ausgang für CS2

Portc.2 = 1 'CS1 auf High
Portc.3 = 1 'CS2 auf High

Dim Pointer As Byte 'zeigt dei aktuelle Speicherstelle für die Impulse an
Dim Array(24) As Byte '24 Speicherstellen für Impulse
Dim Impulszaehler As Long 'Zaehlt die Impulse der Lichtschranke waehrend 10ms (dies ist die Timerzeit)
Dim Impulse As Long 'in dieser Variablen werden die gezaehlten Impulse für die Berechnung gespeichert
Dim Drehzahl_alt As Single 'zur Berechnung des Gradienten speichtert diese Variable den vorangegangenen Drehzahlwert

Dim Drehzahl_neu As Single 'Drehzahl in 1/min, als Dezimalwert
Dim Umdpm1 As Byte
Dim Umdpm2 As Byte
Dim Umdrehungenprominute As Word At Umdpm1 Overlay 'enthaelt den aktuellen Drehzahlwert in 1/min, als ganzzaligen Wert fuer DAC

Dim Drehgradient As Single 'für die Berechnung des Gradienten als Dezimalwert
Dim Grad1 As Byte
Dim Grad2 As Byte
Dim Gradient As Word At Grad1 Overlay 'enthaelt den Drehzahlgradienten in U/s2, als gangzzahligen Wert fuer DAC
Dim I As Integer
Dim Syncro As Byte 'synchronisiert die Ausgabe mit der Berechnung


Pointer = 1 'Pointer zeigt auf die erste Speicherstelle
Impulszaehler = 0
Impulse = 0
Drehzahl_neu = 0
Syncro = 0


On Int0 Irq0 'bei fallenden Flanken wird der Interrupt ausgeloest und ruft Irq0 auf
Enable Int0

On Timer1 Timer_irq 'beim Ueberlaufen des Timers wird die Routine Timer_irq aufgerufen
Enable Timer1

Enable Interrupts



Do
If Syncro = 1 Then
Drehzahl_neu = Impulse * 2.5 'Berechnung der Drehzahl: Imp/(BZ*100)*60 Imp=1; BZ=0,24
Drehgradient = Drehzahl_neu - Drehzahl_alt 'Berechnung der Drehzahländerung für Gradienten
Drehgradient = Drehgradient * 10 'Gradient = Drehzahländerung * Kerwert der Zeiteinheit (1/0,01s)
Drehzahl_alt = Drehzahl_neu 'Speichern der neuen Drehzahl als alte fuer naechste Berechnung der Drehzahlaenderung
Drehzahl_neu = Drehzahl_neu * 0.4096 'Umrechnung von Drehzahl 0...10.000 auf Binaerzahl 0...4096 (10.000/4096)^-1
Umdrehungenprominute = Round(drehzahl_neu)

Portc.2 = 0 'CS1 auf LOW
Spiinit
Spiout Umdpm2 , 1 ' Bit 15 - BIT 8
Spiout Umdpm1 , 1 ' Bit 7 - BIT 0
Portc.2 = 1 'CS1 auf High

If Drehgradient > 0 Then
Drehgradient = Drehgradient * 2.048 'Umrechnung von Drehzahlgradient 0...2.000 auf Binärzahl 0...4095 (2.000/4096)^-1
Gradient = Round(drehgradient)
Else
Gradient = 0
End If

Portc.3 = 0 'CS1 auf LOW
Spiinit
Spiout Grad2 , 1 ' Bit 15 - BIT 8
Spiout Grad1 , 1 ' Bit 7 - BIT 0
Portc.3 = 1 'CS1 auf High
'Print Impulse
'Print Impulszaehler
'Print Drehzahl_neu

Syncro = 0
End If

Loop

End



Irq0: 'Pro Impuls (Markierung auf Scheibe) ein Aufruf
Incr Impulszaehler
Return




Timer_irq: 'wird beim Ablauf der Berechnungszeit aufgerufen
Impulse = Impulse + Impulszaehler 'addiert die Impulse der neuen 10ms
Impulse = Impulse - Array(pointer) 'subtrahiert die Impulse der 10ms-Zeiteiheit vor 240ms
Array(pointer) = Impulszaehler 'speichert die Impulse der aktuellen 10ms-Zeiteinheit in den aktuellen Speicherplatz
Impulszaehler = 0 'resetet den Impulszaehler

If Pointer = 24 Then 'hier wird der Pointer um den Wert "1" hoch gesetzt, nach 24 fängt er von vorne an
Pointer = 1
Else
Incr Pointer
End If

Timer1 = 64911 'laed den timer vor, dies definiert die Timerzeit
Incr Syncro 'fuer die Sychronisierung der Ausgabe mit der Berechnung
Return

for_ro
08.11.2008, 11:10
Hallo,
ich habe mir dein Programm jetzt nicht genauer angesehen. Aber könnte es sein, dass der µC schon einen Interrupt durch die extern anliegende Frequenz bekommt, bevor er nach einem Reset in die Hauptschleife kommt? Und könnte es deshalb sein, dass da etwas anders abläuft, als du es dir vorstellst?
Vielleicht kannst du das mal checken.

Gruß

Rolf

drivepro82
09.11.2008, 18:17
Hallo!
Erst mal danke für die Antwort! Es ist gut möglich, dass der uC schon einen Interrupt bekommt, da die Frequenz ja auch während des Reset anliegt. Dann kann es auch gut sein, dass Interrupts ausgelöst werden wenn das Programm noch gar nicht in der Hauptschleife ist. Nach meinem Verständnis müsste dann aber meine Zählvariable (Impulszaeher) einfach beim ersten mal eine zu gro0e Zahl anzeigen. Sie wird aber bei jedem Durchlauf Null gesetzt und müsste doch demnach beim zweiten Durchlauf schon richtig sein, oder nicht? Auch wenn ich die Frequenz am Interrupt bei Auftreten des Fehlers auf Null stelle, dann wird der Ausgabewert nicht Null was er nach der Berechnung eigentlich müsste.
Gruß Christian

stefan_Z
10.11.2008, 10:19
Interrupt erst aktivieren, wenn alles andere eingestellt ist?

Vitis
10.11.2008, 23:46
hat er, der SEI kommt erst direkt vor der mainloop,
sollte gehen. der SPIINIT ist falsch platziert fällt mir
gerade auf ... sollte aber damit auch nix zu tun haben.
würd ihn dennoch gleich hinter die Config SPI hängen,
ist da sinnvoller aufgehoben und muss auch nur einmal
ausgeführt werden, beschleunig auch etwas das progrämmchen.
... hat aber auch nicht direkt mit dem problem zu tun.