Forum: Mikrocontroller und Digitale Elektronik Zeitprobleme bei Berechnung linearer Rampe für Schrittmotor(AVR)


von stepper motor (Gast)


Lesenswert?

Hallo,

ich will eine lineare Rampe für einen Schrittmotor implementieren. Als 
Endstufe verwende ich das Triple Beast, das über den LPT-Port-Eingang 
die
Schritt- und Richtungssignale vom µC erhält. Die Application Note von 
Atmel (AVR446) und diese Seite
http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time
habe ich mir dazu schon angesehen.
Mein Problem ist, dass die Berechnung des nächsten Reloadwertes für die 
Beschleunigungsrampe nach dieser Formel
zu lange dauert, sodass ich keine genügend hohen Schrittfrequenzen 
erzeugen kann. Benötigen würde ich maximal ca. 5 U/s also eine 
Schrittfrequenz von 5kHz bei 1000 Mikroschritten pro Umdrehung. Die ISR 
muss dazu aber leider mit 10kHz aufgerufen werden, da die Endstufe nur 
auf steigende Flanken beim Schrittsignal reagiert und ich in der ISR den 
Pin nur toggeln kann.
Die Berechnung dauert momentan laut Simulator ca. 120 µs.
Eine Tabelle mit den Reloadwerten möchte ich nicht verwenden, da später 
auch die Beschleunigung variabel sein soll.
Ich programmiere mit Bascom. Bei der Berechnung des nächsten 
Reloadwertes habe ich mich an den Beispielcode aus der AVR446 gehalten, 
also diese Zeilen:
1
new_step_delay = srd.step_delay - (((2 * (long)srd.step_delay) + rest)/
2
(4 * srd.accel_count + 1));
3
4
rest = ((2 * (long)srd.step_delay)+rest)%(4 * srd.accel_count + 1);

Hier mein Testprogramm, worin auch µC und dessen Taktfrequenz stehen:
1
$regfile = "m328def.dat"
2
$crystal = 11059200
3
4
$hwstack = 64
5
$swstack = 64
6
$framesize = 64
7
8
Dim C_n_alt As Word
9
Dim C_n_neu As Word
10
Dim Rest As Word
11
Dim 4n_plus1 As Long
12
Dim 2c_n_alt As Long
13
Dim Reload_akt As Word
14
Dim Restsumme As Long
15
Dim N As Long
16
Dim Motor_nr As Byte
17
18
Dim Constant As Bit
19
20
Config PORTD = Output
21
22
Config Timer1 = Timer , Clear Timer = 1 , Prescale = 8
23
Enable Timer1
24
On Timer1 Clk
25
Enable Interrupts
26
27
28
Declare Sub Calculate_reload_akt
29
30
31
'Beschleunigung: 1 U/s², 1000 Mikroschritte pro Umdrehung(U)
32
C_n_alt = 29552
33
Reload_akt = 65536 - C_n_alt
34
Timer1 = Reload_akt
35
Rest = 0
36
N = 0
37
Constant = 0
38
39
Do
40
41
'Bis ca. 4,5 U/s beschleunigen und dann Drehungszahl halten
42
If Reload_akt > 65383 Then
43
   Constant = 1
44
   Reload_akt = 65383
45
End If
46
47
Loop
48
49
'Dauer(laut Simulator): ca. 0,12 ms
50
Sub Calculate_reload_akt
51
2c_n_alt = 2 * C_n_alt
52
4n_plus1 = 4 * N
53
4n_plus1 = 4n_plus1 + 1
54
2c_n_alt = 2c_n_alt + Rest
55
Restsumme = 2c_n_alt
56
2c_n_alt = 2c_n_alt / 4n_plus1
57
C_n_neu = C_n_alt - 2c_n_alt
58
Reload_akt = 65536 - C_n_neu
59
Rest = Restsumme Mod 4n_plus1
60
C_n_alt = C_n_neu
61
End Sub
62
63
Clk:
64
If Constant = 0 Then
65
   Incr N
66
   Call Calculate_reload_akt
67
End If
68
Timer1 = Reload_akt
69
Toggle Portd.motor_nr
70
71
Return

Ich hoffe mir kann jemand weiterhelfen.

von radiostar (Gast)


Lesenswert?

stepper motor schrieb:
> Eine Tabelle mit den Reloadwerten möchte ich nicht verwenden, da später
> auch die Beschleunigung variabel sein soll.

Dann mach mehrere Tabellen für verschiedene Beschleunigungen.

von Karl H. (kbuchegg)


Lesenswert?

Überprüf mit deinen konkret auftretenden Zahlenwerten, welche der 
Variablen
1
Dim C_n_alt As Word
2
Dim C_n_neu As Word
3
Dim Rest As Word
4
Dim 4n_plus1 As Long
5
Dim 2c_n_alt As Long
6
Dim Reload_akt As Word
7
Dim Restsumme As Long
8
Dim N As Long
9
Dim Motor_nr As Byte
tatsächlich Long sein müssen, und bei welchen Berechnungen (auch 
Zwischenergebnissen), du dem µC eine Menge Fleissaufgaben aufbürdest, 
indem du ihn zwingst in 32 Bit zu rechnen, wo es 16 Bit auch tun.

von Karl H. (kbuchegg)


Lesenswert?

Ich mag mich auch täuschen, aber ob BASCOM zb das hier
1
4n_plus1 = 4 * N
in einen Links-Shift umwandelt, da bin ich mir nicht sicher.

Auf jeden Fall sind 0.12ms für diese simple Berechnung bei 11Mhz recht 
indiskutabel. Aber fang mal damit an, die Datentypen an das anzupassen, 
was du tatsächlich brauchst.

: Bearbeitet durch User
von LostInMusic (Gast)


Lesenswert?

Ich vermute den Kern des Problems hier:

2c_n_alt / 4n_plus1

Integer- oder Float-Division? Wie wird das gerechnet?

von stepper motor (Gast)


Lesenswert?

Also ich habe jetzt die Multiplikationen durch Shifts ersetzt und die 
Datentypen auf Word geändert. Jetzt dauert die Berechnung ca. 60 µs.
Das reicht leider noch nicht, da bei Maximalgeschwindigkeit jede 100 µs 
die ISR aufgerufen wird und das Hauptprogramm auch noch zum Zuge kommen 
soll. Kann man das Problem mit dem Toggeln nicht irgendwie lösen? Die 
Impulsbreite des Schrittsignals muss für die Endstufe jedoch mindestens 
2 µs betragen.

von LostInMusic (Gast)


Lesenswert?

>Kann man das Problem mit dem Toggeln nicht irgendwie lösen?

Ich würde Timer 1 im CTC-Modus laufen lassen. Nach jeder Neuberechnung 
OCR1A auf C_n_neu setzen, und OCR1B auf die Hälfte davon. Du kannst den 
Timer so konfigurieren, dass bei Erreichen des OCR1B-Wertes von der 
Hardware ein Pin gesetzt oder gelöscht wird. Weitere Infos siehe 
Datenblatt.

von stepper motor (Gast)


Lesenswert?

Ich habe gerade bemerkt, dass ich 2c_n_alt doch 32 Bit groß machen muss, 
da der Rest auch noch hinzuaddiert wird und leider auch sehr groß werden 
kann.
Damit sind Division(Festkomma) und Modulo auch wieder 32 Bit 
Operationen.
Mit dem zweimaligen Toggeln und neuen µC-Takt von 18,432 MHz komme ich 
auf eine Berechnungsdauer von ca. 80 µs, was für 4 U/s reichen sollte, 
da die ISR nur jede 250 µs aufgerufen wird.

Der Bascom-Simulator setzt TCNT1 immer auf 0 sobald der kleinste Wert 
von OCR1A und OCR1B erreicht ist. Wenn jetzt z.B. OCR1B auf 10000 und 
OCR1A auf 20000 gesetzt ist, würde der Interrupt von OCR1A nie ausgelöst 
werden.
Ist das ein Fehler im Simulator?

von LostInMusic (Gast)


Lesenswert?

>Damit sind Division(Festkomma) und Modulo auch wieder 32 Bit Operationen.

Du hast zwei Alternativen: (1) Solange rumprobieren, bis es irgendwie 
geht und Du mit dem Ergebnis leben kannst, oder (2) den Algorithmus und 
den Code von vorne bis hinten durchanalysieren und auf Basis der 
gewonnenen Erkenntnisse fundierte Entscheidungen treffen. (1) ist 
schnell und (2) ist sauber.

>Mit dem zweimaligen Toggeln und neuen µC-Takt von 18,432 MHz komme ich
>auf eine Berechnungsdauer von ca. 80 µs, was für 4 U/s reichen sollte,
>da die ISR nur jede 250 µs aufgerufen wird.

Aber ist es eigentlich nötig, mit jedem Motorstep eine Neuberechnung 
durchführen? Würde es nicht auch reichen, das nur z. B. 80 mal pro 
Sekunde zu machen? Um einen entsprechenden Takt zu erzeugen, kannst Du 
Timer 0 nehmen, und die "lahme" Rechenroutine gehört dann ins Main, 
damit sie von den schnellen Timer 1-Interrupts unterbrochen werden kann. 
Die Aktualisierung des OCR1A-Werts musst Du in der ISR vom Timer1-OCRA 
erledigen, und die Bereitstellung des Ergebnisses durch die 
Rechenroutine atomar machen. You understand? Ist aber alles relativ easy 
zu bewerkstelligen.

>Ist das ein Fehler im Simulator?

Wahrscheinlich... keine Ahnung, sorry. Das von Dir beschriebene 
Verhalten ist jedenfalls nicht konform zu dem eines realen Controllers.

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.