PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Bahnsteuerung für Schrittmotor auf Mega128 macht Probleme



olby2
18.03.2009, 20:28
Brauche Hilfe !
Mein Code macht undefinierbare Probleme - er läuft zwar stabil, doch die Bahn/Rampe wird nicht ordnungsgemäß mit Geschwindigkeit 0 beendet.

Eigentlich soll per CTC-Mode eine Frequenz für eine Schrittmotorendstufe erzeugt werden um bei gegebener Strecke auf ein Speedlimit zu beschneunigen und rechtzeitig vor ende der Strecke auf "Null" abgebremst zu haben.
Ich habe einer Timer auf 200Hz eingestellt um eine Interruptroutine in gleichbleibenden Zeitabständen die Berechnungen durchführen zu lassen.
Im Hauptprogramm wird eigentlich nur ein neuer Durchlauf gestartet und die Ausgabe auf dem Display gemacht.

Problem 1:
ich lasse mir bei jedem Timerereigniss einen Interrupt auslösen, damit ich
die ausgegebenen Pulse genau zählen kann.
Ich lasse eine Variable bei 0 beginnen und hochzählen und am Display anzeigen, die andere Variable zählt von vorgegebener Strecke ( 8000 ) herunter.
In einer If Abfrage wird der Timer gestoppt, wenn auf Null heruntergezählt wurde -> so wünsche ich es mir - aber er macht es nicht !

Es kommt manchmal vor, dass die Routine auf unergründliche Weise viel
früher zum ende kommt, die eine Variable ist nicht bis auf Null runter gekommen , und die andere nicht bei 8000 angekommen - Noch viel dubioser : nicht einmal mit einer rechnerisch erklärbaren Differenz!
Obwohl die beiden Variablen genau untereinander runter/hochgezählt werden , scheint eine von beiden Zeilen manchmal nicht bearbeitet zu werden, da z.B. die eine Variable bei 8000 angekommen ist, die andere aber noch bei weitem nicht bei Null angekommen ist , sie steht z.b. bei 50

Gibt es Jemanden in dieser Gemeinde, der mir das erklären kann ??


Problem 2:
Ich beobachte aber in aller Regel eine große Geschwindigkeit beim ende der Strecke - manchmal bremst er auch zu früh und läuft mit einer minimalen Geschwindigkeit( meine Vorgabe ) zum ende der Strecke.




$hwstack = 192
$swstack = 192
$framesize = 128
'you might need to raise these numbers if your code grows !!!!!!! (unexpected behaviour of the program often results of too small stacks)

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

$regfile = "m128def.dat"
$crystal = 16000000 'enter the used clock of your actual microcontroller

Declare Sub Geschwindigkeit
Declare Sub Rampe
Declare Sub Timerladen

Const Frq = 16000000 '# hier muss die Prozessorfrequenz nochmal rein !!!!
Const T3prescale = 64 '# Timer3 Vorteiler
Const T0prescale = 1024 '# Timer3 Vorteiler
Const True = 1
Const False = 0
Const Time0 = 78 ' für 200Hz Wiederholrate
'##############
'# A/D Port #
'##############
Config Adc = Single , Prescaler = Auto , Reference = Internal
'########### FrequenzGenerator mittels Timer0 ###############
Config Timer0 = Timer , Prescale = T0prescale '###### Interrupr für die Wiederholrate / sekunde
Load Timer0 , Time0
On Ovf0 Timer0_ovf
Enable Timer0
Start Timer0
'########### PWM Generator mittels Timer3, Porta ###############
Stop Timer3
Config Timer3 = Timer , Prescale = T3prescale , Clear Timer = 1 , Compare A = Toggle ' 1. Achse
On Compare3a Compare_3a_int ' When Timer3 = Compare3A register
Compare3a = 55000 ' Load the TimerLimit value into the Compare1A (OCR1A) register

Disable Compare3a


Config Porte.3 = Output
'################################################# ##############
'Now we need to select Port B as to an output port (data output to the display)
Ddrb = &B11111111 'DDR = Data direction register; All 8 ports switched to output (1)

Ddra = &B00000000 'switch all 8 Ports of Port A to input (0), Pin (PA.0 - PA.7)
Porta = &B11111111 'All port pins have individually selectable pull-up resistors. Here we enable these pull-up-resisitors, so these Pins are always at logical 1
'You need to pull these Pins against ground (GND)
Ddrc = &B00000000 'switch all Ports of Port C to input
Portc = &B11111111

Ddrd = &B00000000 'switch all Ports of Port D to input
Portd = &B11111111 'all pull-up-Resistors turned on

'Ddre = &B00000000 'switch all Ports of Port E to input
'Porte = &B11111111 'all pull-up-Resistors turned on

Ddrf = &B00000000 'switch all Ports of Port F to input
Portf = &B11111111 'all pull-up-Resistors turned on

Ddrg = &B00000000 'switch all Ports of Port G to input
Portg = &B11111111 'all pull-up-Resistors turned on
'all pull-up-Resistors turned on

Debug0 Alias Porta.0
Debug1 Alias Porta.1
Debug2 Alias Porta.2
Debug3 Alias Porta.3
Debug4 Alias Porta.4
Debug5 Alias Porta.5
Debug6 Alias Porta.6
Debug7 Alias Porta.7


'##### Variablen #############################################
Dim Problem As Bit
Dim Menudraw As Bit
Dim Init As Bit
Dim Modus As Bit
Dim Continus As Bit
Dim Port As String * 14
Dim Timer3reload As Word
Dim Schrittzaehler As Long
Dim T3basis As Long
Dim T0basis As Long
Dim Wunschspeedlong As Long
Dim Speedakt As Single
Dim Speedquadrat As Single ' Speedakt zum Quadrat
Dim Wiederholrate As Single
Dim Gesamtschritte As Long
Dim Halbschritte As Long
Dim Beschleunischritte As Long
Dim Schritte As Long
Dim Umin As Long ' so viele Schritte sing vom Weg noch übrig
Dim Uminmax As Long
Dim Beschleunigung As Single
Dim Speedlimit As Single
Dim Zeitincrement As Single
Dim Wunschspeed As Single
Dim Minspeed As Single
Dim Tick As Single
Const Fertig = 1
Const Nichtfertig = 0
Dim Schleife As Byte
Dim Untersetzung As Integer
Dim Schritteproumdrehung As Integer
Dim Acc As Single
Dim Speed As Single
Dim Timecount As Long
Dim Count As Long
Dim Sek As Single


Enable Interrupts
Menudraw = 1
Wunschspeed = 1
Schrittzaehler = 0
Beschleunigung = 30
Speedlimit = 30
Minspeed = 10
Modus = 1
Init = 0
Gesamtschritte = 4000
'################################################# ###########################################
'4 - Definition of used ports and pull up resistors
$include Init21_display3000.bas 'At our boards we are using Port B for the SPI-communication to the LCD.

Orientation = Portrait ' fürs Display
Graphics_mode = 65k_uncompressed 'select the needed color mode, here 65.536 colors
Call Lcd_cls

'################################################# #################
Start Adc


'################################################# #################


T3basis = Frq / T3prescale ' berechnung der Grundgeschwindigkeit aus Frq und Teiler
T0basis = Frq / T0prescale
Wiederholrate = T0basis / Time0
Tick = 1 / Wiederholrate

Do ' Schleife Hauptprogramm - eigentlich nur zum anzeigen der Variablen aus dem Display
Toggle Debug1

If Schleife = Fertig Then ' Wenn eine Rampe komplett ist
Waitms 700 ' Variablen neu bestücken
Schleife = Nichtfertig ' um neuen Durchlauf nach Wartezeit starten
Schrittzaehler = 0
Gesamtschritte = 8000
Beschleunigung = Beschleunigung + 100
Speedlimit = Speedlimit + 200
Init = 0
Modus = 1
Halbschritte = Gesamtschritte / 2
Uminmax = 0
End If


'#### Anzeige auf dem LCD zur Kontrolle #########################

If Menudraw = 1 Then

Port = "Gesamtschritte"
Call Lcd_print(port , 8 , 32 , 1 , 1 , 1 , White , Black)

Port = "Speedakt "
Call Lcd_print(port , 8 , 45 , 1 , 1 , 1 , White , Black)

Port = "Schrittzaehl"
Call Lcd_print(port , 8 , 100 , 1 , 1 , 1 , White , Black)

Port = "Umin"
Call Lcd_print(port , 8 , 120 , 1 , 1 , 1 , Green , Black)

Port = "Modus"
Call Lcd_print(port , 8 , 130 , 1 , 1 , 1 , Green , Black)

Port = "sek"
Call Lcd_print(port , 8 , 150 , 1 , 1 , 1 , Green , Black)


Menudraw = 0
End If


Port = Str(gesamtschritte)
Port = Format(port , "0000000")
If Len(port) < 8 Then
Call Lcd_print(port , 85 , 32 , 1 , 1 , 1 , Green , Black)
End If

Port = Fusing(speed , "####.#")
Port = Format(port , "0000000")
If Len(port) < 8 Then
Call Lcd_print(port , 85 , 45 , 1 , 1 , 1 , Blue , Black)
End If

Port = Str(schrittzaehler)
Port = Format(port , "0000000")
If Len(port) < 8 Then
Call Lcd_print(port , 85 , 100 , 1 , 1 , 1 , White , Black)
End If

Port = Str(uminmax)
Port = Format(port , "00000.0")
If Len(port) < 8 Then
Call Lcd_print(port , 85 , 120 , 1 , 1 , 1 , White , Black)
End If

Port = Str(modus)
Call Lcd_print(port , 85 , 130 , 1 , 1 , 1 , White , Black)

Port = Fusing(sek , "####.##")
Port = Format(port , "000000")
If Len(port) < 8 Then
Call Lcd_print(port , 85 , 150 , 1 , 1 , 1 , White , Black)
End If

Acc = Beschleunigung * Tick ' Berechnung der Beschleunigungsrate
Loop

End



'#########################################
'# Timerinterruptrutine alle 5ms #
'#########################################
Timer0_ovf:
Load Timer0 , Time0
Debug0 = 1
Incr Count
Enable Interrupts

Call Geschwindigkeit ' Gteschwindigkeitsberechnung
If Init = 0 Then
Start Timer3
Enable Compare3a
Init = 1
End If

Call Rampe ' berechnung der Wunschgeschwindigkeit für die Rampe

Call Timerladen
Debug0 = 0 ' Timer mit Sollwert bestücken
Return



'################################
'# Compare Interrupt Timer3a #
'################################
Compare_3a_int:
If Timer3 < Timer3reload And Problem = True Then Compare3a = Timer3reload 'bei Problemen Timer hier neu laden
Toggle Porta.6
Incr Schrittzaehler ' Schrittzaehler hochzählen
Decr Gesamtschritte ' Gesamtschritte runterzählen

If Gesamtschritte <= 0 Then ' wenn Gesamtschritte auf Null > keine Pulse mehr
Stop Timer3
Disable Compare3a
Schleife = Fertig
Timecount = Count ' Zeit eines Ablaufes speichern
Count = 0
End If

Return


'###################################
'# Sub Geschwindigkeitsberechnung #
'###################################
Sub Geschwindigkeit
Speedakt = T3basis / Compare3a '# Frequenzbasis / PWM WERT
Speed = Speedakt / 2 ' / 2 da 2 Interrupte für eine Periode benötigt werden
End Sub

'###################################
'# Sub Beschleunigungsrampe #
'###################################
Sub Rampe
Umin = Speedakt * 6 ' 60 für 1 Min
Umin = Umin / 8 '800 Schritte pro umin &
' > zum Anzeigen mit 2 Kommastellen nur durch 8
If Umin > Uminmax Then ' zum Speichern der max. U/min
Uminmax = Umin
End If

If Modus = 1 Then ' wenn beschleunigt wird :
If Wunschspeed > 0 Then ' wenn gefahren werden soll
If Wunschspeed < Speedlimit Then ' wenn Speedlimit noch nicht erreicht
Wunschspeed = Wunschspeed + Acc ' Berechnung der beschleunigung
If Schrittzaehler > Halbschritte Then ' noch in der beschleunigungsphase darf nur die hälfte der Strecke beschleunigt werden
Modus = 0
Continus = 0
End If
Else
If Continus = 0 Then
Beschleunischritte = Schrittzaehler
Continus = 1
End If
If Beschleunischritte > Gesamtschritte Then
Modus = 0
End If
End If
Else
Wunschspeed = 1
End If
Else ' Bremsung einleiten !!
If Wunschspeed > 0 Then
Wunschspeed = Wunschspeed - Acc ' Beschleunigungsfaktor abziehen
Else
Wunschspeed = 0
End If
End If
Sek = Timecount / Wiederholrate ' wie lange hat eine Rampe gesauert
End Sub



Sub Timerladen: ' Timerwert aus "Wunschspeed" errechnen
If Wunschspeed > 0 Then
Wunschspeedlong = Wunschspeed
Timer3reload = T3basis / Wunschspeedlong
Else
Timer3reload = 30000
End If
If Timer3reload > 30000 Then Timer3reload = 30000 ' Grenzen für den erlaubte werde für die Geschwindigkeit
If Timer3reload < 10 Then Timer3reload = 10
If Timer3 < Timer3reload Then
Compare3a = Timer3reload
Problem = False
Else
Problem = True
End If
End Sub

$include Glcd21_display3000.bas

$include Glcd21_fonts.bas
'Dummy Data um Fehlermeldungen bei der Kompilierung der Standardroutinen zu vermeiden
'Die Tabelle wird dann bei Nutzung eines indizierten Grafikdatei mit "echten" Daten ausgetauscht
Colortable:
Data 0


kann mal bitte jemand sie meinen Code anschauen und konstruktive Kritik
üben - ich bitte darum - ich komme hier nicht weiter - habe schon die berechnung der Bahnsteuerung mit Gleichnungen aus dem Physik-Buch gemacht und da hab ich auch die selben Ergebnisse bekommen.

Ich Programmiere mit der neusten Bascom Version und setzte
einen AT Mega 128 auf einer Platine von Display3000 (D071)ein.


vielen Dank.

Vitis
19.03.2009, 06:53
hmmm ... verzwickt,
denkbare Szenarios gibts viele ...
zum Einen verwendeste Variablennamen, die eventuell
in Deinen includeten Programmteilen verwendet werden
könnten ... z.B. "speed"
dann haste in Deiner Interruptroutine nen
"enable interrupts" ... int in int, das kann Verwirrung stiften
wozu brauchste das?

olby2
19.03.2009, 07:24
Hallo Vitis, das mit den Variablen werd ich mir anschauen.


hmmm ... verzwickt,
dann haste in Deiner Interruptroutine nen
"enable interrupts" ... int in int, das kann Verwirrung stiften
wozu brauchste das?

Da ich jeden Timerinterrupt zählen möchte, muss ich auch in meinem Timerinterrupt ( 200 Hz ) wieder weitere interrupte freigeben.
Mir haben zwar viele Leute gesagt, dass kann zu Problemen führen, doch 1. hab ich noch keine andere Lösung gefunden.
2. 200 Hz ..... da bin ich alle mal mit der Routine durch,sodass allein durch die Codelänge verhindert wird, dass die gleiche Routine ineinander mehrfach aufgerufen wird. Das funktioniert eigentlich gut , hab mir es mit dem Oszi angeschaut.

gruß olby2

Vitis
19.03.2009, 07:40
eben drum, Deine Interruptroutine ist "schnell" sollte auch ohne den
SEI ohne Probleme gehen

olby2
19.03.2009, 08:04
Leider nicht ,
das habe ich mir mit dem Oszi schon angeschaut, wenn ich in meiner Timerroutine nicht weitere Interrupte erlaube, werden Timerereignisse in dieser Zeit nicht gezählt.

Ich muss das aus jetziger sicht also machen - ich glaube aber nicht das in den geschachtelten IRQ´s das Problem zu finden ist , doch ich habe mir auch schon überlegt mit einem weiteren Timer einfach zu zählen was im CTC Mode bei Ocr3a alles so raus kommt


gruß olby2