PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer 1 Genauigkeit



asunn
27.06.2008, 19:37
Hallo!

Ich bin gerade dabei die Drehzahl eines Motors zu erfassen.( siehe unter Sensor GP1A038 RNcontrol Rnkeylcd) Die Genauigkeit der Meßergebnisse laßt jedoch zu wünschen. Einige Änderungen an der Hardware haben das Ergebnis verbessert, doch nun bin ich auf ein anderes Problem gestoßen, das ich mir nicht erklären kann.
Dazu habe ich unten die Meßsoftware eingefügt, die um alles angespeckt ist, was nicht zum Timer prüfen notwenig ist. Das hat das Ergebnis schon verbessert.

Programmablauf
- Timer 1soll alle 0,5 sec einen Interrurt auslößen
- währen dieser Zeit wird der Zähler Z hochgezählt

Do
Z = Z + 1
If Timer1interrupt = 1 Then Ausgabe_nach_timer1int
Loop

- Kommt der Interrupt wird der Zählerwert auf das RNkeylcd ausgeben.

Da nichts anderes passiert ( auch Meßfühler ist abgezogen) sollte Z immer gleich sein. +/- 1 ist ok. ( Anzeige 10840/10841) Aber in mehr oder weniger regelmäßigen Abständen schwanken die Werte von max 10791 ... 10841.
Nun ist die Frage, braucht der Timer1 länger zum Höchzähler, also bis zum Auslösen des Timerinterrupts, was auch die Schwankungen der Drehzahllmessung im Originalprogramm erklären würde,
oder werden beim Durchlaufen der Schleife hin und wieder noch andere Aufgaben vom Prozessor ausgeführt, so das die Schleifendurchläufe sinken.

andreas



'################################################# #########################
'Probe Timer1.BAS
'
'Test 27.06.08
' Hardware RN-Contreol + RNkeylcd
'################################################# #########################`

' --------------- RN-Control Anweisungen -------------------

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

' --------------- RN-Control Hardwareconfiguration ----------
Config Scl = Portc.0 'Ports fuer IIC-Bus
Config Sda = Portc.1

Config Int0 = Rising ', Nosave ' Interupt0 für steigende Flanke def
' . Nosave speichert register nicht
Config Timer1 = Timer , Prescale = 256 ' Vorteiler vom Timer1 wird auf 256 gestellt

' --------------------- Variablendeklaration ----------------

Dim Impulseprominute As Long
Dim Impulseprosekunde As Integer
Dim K As Integer
Dim Le As Byte
Dim Rnkeylcd_befehl As String * 4
Dim Text As String * 80
Dim Timer1interrupt As Byte
'Dim Umdrehungenprominute As Integer
Dim Zaehlerirq0 As Integer
Dim Z As Integer
' --------------------- Konstantendeklarationn --------------

Const Markierungenproscheibe = 120 'Scheibe für GP1S23 hat 120 Markierungen
Const Rnkeylcd_slaveid_write = &H40 'I2C SlaveAdresse
Const Rnkeylcd_slaveid_read = &H41
Const Timervorgabe = 34286 'Timervoreinstellung um bei Vorteiler 256 und Takt 16 MHz
'Auslösung alle 0,5 sec


' -------------------- I2cbus init ----------------------------

Wait 1 'Warte bis LCD bereit
I2cinit 'I2C bus init

' ---------------------- Routinendeklaration ------------------

Declare Sub Ausgabe_nach_timer1int()
Declare Sub Rnkeylcd_cursorpos(byval Spalte As Byte , Byval Zeile As Byte)
Declare Sub Rnkeylcd_lcd_ausgabe()
Declare Sub Rnkeylcd_lcd_loeschen()

' ---------------------- Hauptprogramm ------------------------

Zaehlerirq0 = 0 'Zähler für Striche auf der Codescheibe auf 0
On Int0 Irq0 ' bei INTO Routine Irg0 aufrufen
Enable Int0 'Interupt INT0 einschalten

On Timer1 Timer_irq ' wenn Timer1 interrupt auslöst Routine Timer_irq aufrufen
Enable Timer1 'Timer1 ein

Enable Interrupts ' alle Interrupts einschalten

Rnkeylcd_lcd_loeschen
Timer1interrupt = 0
Z = -32768

Do
Z = Z + 1
If Timer1interrupt = 1 Then Ausgabe_nach_timer1int
Loop

End

' ----------------------------------------------------------------------------

Sub Ausgabe_nach_timer1int()
Timer1interrupt = 0
Text = " "
'Impulseprominute = Impulseprosekunde * 60
'Umdrehungenprominute = Impulseprominute / Markierungenproscheibe
Text = "Zähler : " + Str(z)
Rnkeylcd_cursorpos 2 , 2
Rnkeylcd_lcd_ausgabe
Z = -32768
End Sub

Sub Rnkeylcd_lcd_ausgabe()
Le = Len(text)
I2csend Rnkeylcd_slaveid_write , Text , Le
End Sub

Sub Rnkeylcd_cursorpos(byval Spalte As Byte , Byval Zeile As Bit Byte) ' Cursor auf Pos
Rnkeylcd_befehl = Chr(27) + Chr(79) + Chr(spalte) + Chr(zeile)
I2csend Rnkeylcd_slaveid_write , Rnkeylcd_befehl , 4
End Sub

Sub Rnkeylcd_lcd_loeschen()
'Local Rnkeylcdbefehl As String * 2
Rnkeylcd_befehl = Chr(12)
I2csend Rnkeylcd_slaveid_write , Rnkeylcd_befehl , 1
End Sub
' ---------------------- Interruptroutinen -------------------------------

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

Timer_irq: 'Pro Sekunde zwei Aufrufe
Timer1 = Timervorgabe
'Impulseprosekunde = Zaehlerirq0
Zaehlerirq0 = 0
Timer1interrupt = 1
Return

'programmlänge 1278 dec

Michael
27.06.2008, 22:51
Hallo asunn,

vorweg: ich kann dir versichern, daß die Timer der Atmegas genau sind.

Ich habe dein angehängtes Programm nur überflogen.
Wenn du willst, daß man sich damit beschäftigt, solltest du es besser formatiern und kommentieren. Nicht jeder hat Lust, sich durch deine auskommentierten Vorversuche zu navigieren.

Wo ist die Baudratenfestlegung?

Z ist ein Integer. Weißt du, wie weit der Wertebereich bei diesem geht?

Deine Do-Loop- Schleife macht nur das Zählen, bei dem Wertebereich von Z kann ich mir mehrere Überläufe pro Timer1-Interrupt vorstellen.

Gruß, Michael