Forum: Mikrocontroller und Digitale Elektronik Interruptausführung bei Frequenzänderung


von maxim (Gast)


Lesenswert?

Hallo,
ich bin gerade dabei einen Controller für eine Schrittmotorkarte mit 
Takt/Richtung zu programmieren. Den Takt will ich dabei per 
Timer-Interrupt generieren. Dies ist soweit auch kein Problem. Da 
Schrittmotoren für gewisse Geschwindigkeiten jedoch eine Anfahrtsrampe 
brauchen, erhöhe ich die Frequenz mit jedem Schritt in meiner 
Interruptfunktion. Dies funktioniert soweit auch. Das Problem ist nun 
jedoch, dass der Controller je nach Frequenz mal mehr und mal weniger 
Takte erstellt, obwohl ich im Interrupt mitzähle.
D.h., ich möchte z.B. 200 Schritte fahren. Diese werden ohne meiner 
Rampe auch ohne Probleme angefahren. Sobald ich jedoch mit Rampe auf 
schnellere Frequenzen fahre, fängt er an im Phase Correct PWM Mode 
Schritte zu verlieren und im CTC Mode Schritte hinzu zu gewinnen.

Hier mein Code:
1
#ifndef F_CPU
2
#define F_CPU 16000000
3
#endif
4
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <util/delay.h>
8
9
#define CONCAT(a,b) a##b
10
#ifdef USE_PINx_TOGGLE
11
#  define TOGGLE(a,b) CONCAT(PIN,a) = (1 << (b))
12
#else
13
#  define TOGGLE(a,b) CONCAT(PORT,a) ^= (1 << (b))
14
#endif
15
16
volatile uint16_t steps = 0;
17
18
ISR (TIMER0_COMPA_vect) {
19
  if (steps > 0) {
20
    steps--;
21
    TOGGLE(B,0);
22
  }
23
  if (OCR0A > 100)
24
    OCR0A--;
25
}
26
27
void initIO() {
28
  DDRD |= (1 << PD5) | (1 << PD6);
29
  DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0);
30
31
  //TCCR0A |= (1 << COM0A0); // Toggle OC0A
32
  TCCR0A |= (1 << WGM00); // Phase Corect PWM Mode
33
  TCCR0B |= (1 << WGM02);
34
  TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00); // Prescaler
35
  TIMSK0 |= (1 << OCIE0A); // Interrupt active
36
37
  OCR0A = 200;
38
}
39
40
int main(void) {
41
  initIO();
42
43
  steps = 400; // 200 * 2
44
45
  sei();
46
47
  while(1) {
48
49
  }
50
}

Woran kann es liegen? Letzendlich wird
1
steps
 ja bis auf 0 dekrementiert, hierfür muss also der Interrupt 400 mal 
aufgerufen werden und auch gleichzeitig den Ausgang umschalten, aber es 
scheint so, als ob nur dekrementiert wird und nicht geschaltet wird.
Benutzt wird ein Arduino Uno.

Gruß, Maxim

von Karl H. (kbuchegg)


Lesenswert?

maxim schrieb:

> Sobald ich jedoch mit Rampe auf
> schnellere Frequenzen fahre, fängt er an im Phase Correct PWM Mode

Phase Correct PWM ist der falsche Ansatz.
Weißt du, wie Phase Correct arbeitet? Da wird der Timer abwechselnd hoch 
UND runter gezählt.
Ausserdem brauchst du die nicht. Die PC_PWM braucht man nur dann, wenn 
man eine Phasenbeziehung einhalten muss (zb zu einer weiteren PWM)

> Schritte zu verlieren und im CTC Mode Schritte hinzu zu gewinnen.

Im CTC sollte das allerdings funktionieren.

Sicher, dass du mit der Zeitverringerung nicht zu kurz wirst, so dass 
der Schrittmotor mit der Schrittfrequenz ganz einfach nicht mehr 
mitkommt?

von maxim (Gast)


Lesenswert?

> Phase Correct PWM ist der falsche Ansatz.
> Weißt du, wie Phase Correct arbeitet? Da wird der Timer abwechselnd hoch
> UND runter gezählt.
> Ausserdem brauchst du die nicht. Die PC_PWM braucht man nur dann, wenn
> man eine Phasenbeziehung einhalten muss (zb zu einer weiteren PWM)

Phase Correct PWM war nur ein Test im Vergleich zu CTC, weil der Motor 
in CTC bei mir mehr Schritte macht, als er sollte. Aber wiederrum nur 
bei Fahrten mit Rampe.

> Sicher, dass du mit der Zeitverringerung nicht zu kurz wirst, so dass
> der Schrittmotor mit der Schrittfrequenz ganz einfach nicht mehr
> mitkommt?

Die Schrittmotorkarte kann mit einer Frequenz bis 300 kHz arbeiten, ich 
jedoch erzeuge max. 2 kHz. Selbst wenn ich eine Rampe von 500 Hz auf 
1000 Hz mache, entsteht ein Verlust/Gewinn von Schritten.

von maxim (Gast)


Lesenswert?

Grad nochmal auf CTC umgestellt. Hier der Code:
1
#ifndef F_CPU
2
#define F_CPU 16000000
3
#endif
4
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <util/delay.h>
8
9
#define CONCAT(a,b) a##b
10
#ifdef USE_PINx_TOGGLE
11
#  define TOGGLE(a,b) CONCAT(PIN,a) = (1 << (b))
12
#else
13
#  define TOGGLE(a,b) CONCAT(PORT,a) ^= (1 << (b))
14
#endif
15
16
volatile uint16_t steps = 0;
17
18
ISR (TIMER0_COMPA_vect) {
19
  if (steps > 0) {
20
    steps--;
21
    TOGGLE(B,0);
22
  }
23
  if (OCR0A > 60)
24
    OCR0A--;
25
}
26
27
void initIO() {
28
  DDRD |= (1 << PD5) | (1 << PD6);
29
  DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0);
30
31
  TCCR0A |= (1 << WGM01); // CTC Mode
32
  TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00); // Prescaler
33
  TIMSK0 |= (1 << OCIE0A); // Interrupt active
34
35
  OCR0A = 200;
36
}
37
38
int main(void) {
39
  initIO();
40
41
  steps = 400; // 200 * 2
42
43
  sei();
44
45
  while(1) {
46
47
  }
48
}

Wieder fährt der Motor ca. 20-30 Grad weiter, als er sollte. Gewinnt 
also Schritte hinzu. Wenn ich die Frequenz mit einem Multimeter 
überprüfe, so hat diese eine Abweichung von weniger als 1% von dem 
errechneten Wert aus dem Manual, das stimmt also soweit.

von Axel S. (a-za-z0-9)


Lesenswert?

maxim schrieb:

>> Sicher, dass du mit der Zeitverringerung nicht zu kurz wirst, so dass
>> der Schrittmotor mit der Schrittfrequenz ganz einfach nicht mehr
>> mitkommt?
>
> Die Schrittmotorkarte kann mit einer Frequenz bis 300 kHz arbeiten, ich
> jedoch erzeuge max. 2 kHz.

Das war nicht die Frage!

maxim schrieb:
> Wieder fährt der Motor ca. 20-30 Grad weiter, als er sollte. Gewinnt
> also Schritte hinzu.

Aha. Du zählst also nicht die Schritte, sondern schaust wie weit sich 
der Motor gedreht hat. Aber dann ist deine Schlußfolgerung falsch! Wenn 
der Motor sich weiter gedreht hat, dann heißt das nicht zwangsläufig, 
daß die Steuerung mehr Schritte verlangt hat. Es kann auch ganz einfach 
sein, daß der Motor diesmal weniger Schlupf hatte.

Die genannten 2kHz erscheinen mir auch sehr hoch. Kann der Motor das 
überhaupt? (mit der Last und der Betriebsspannung)

Vorschlag: mach die Chose doch erstmal langsamer. So ca. Faktor 10. 
Einfach nur um sicherzustellen, daß der Motor wirklich mitkommt. Und 
dann mach eine Rampe drauf.


XL

von Karl H. (kbuchegg)


Lesenswert?

Axel Schwenke schrieb:

> Vorschlag: mach die Chose doch erstmal langsamer. So ca. Faktor 10.
> Einfach nur um sicherzustellen, daß der Motor wirklich mitkommt. Und
> dann mach eine Rampe drauf.

Hätte ich auch gesagt.
Erst mal braucht man eine Referenz die über jeden Zweifel erhaben ist, 
wenn man die tatsächlich gemachten Schritte anders nicht zählen kann.

Den Motor gaaaanz langsam 200 Schritte machen lassen.
Ein simples Programm, welches mit _delay_ms(100) dazwischen den Pin 
toggelt, erfüllt den Zweck. Und 5 Schritte/sek wird der Motor (ohne 
Last) ziemlich sicher schaffen :-)

von amateur (Gast)


Lesenswert?

Ich würde einfach mal einen Zähler in die Motorleitung hängen und dann 
eine genau definierte Rampe abfahren. Am Ende sagt Dir der Zähler wer 
Recht haben könnte - Dein Motor oder deine Elektronik.
Übrigens: Schau Dir mal die Rampen selber an. Steigen die zu steil an 
bzw. fallen sie zu schnell ab, kann der Brummer auch stolpern - selbst, 
wenn Du im Rahmen des erlaubten bleibst.
Eine weitere Fehlermöglichkeit ist, während der Frequenzänderung können, 
bei ungeschickter Programmierung, halbe Schritte oder überlange Schritte 
entstehen. Die sind nicht besonders Gut nachzuweisen, da es sich dabei 
um "Einzeltäter" handelt.

von Maxim B. (maximb)


Lesenswert?

Axel Schwenke schrieb:
> Du zählst also nicht die Schritte, sondern schaust wie weit sich
> der Motor gedreht hat.

Genau, hierfür hab ich unteranderem einen Inkremental-Encoder am Motor. 
Bei Frequenzen ohne Rampe, geht bis ungefähr 800 Hz, macht der Motor 
immer exakt 200 Schritte. Der Motor wird übrigens mit 48V und 2A ohne 
jegliche Last bestromt und ist bei uns in der Firma erprobt, auch bei 
höheren Frequenzen. Der Motor sollte also nicht das Problem darstellen. 
Dennoch werde ich mal in den nächsten Tagen eine CNC Software dranhängen 
und prüfen.

Letzlich werde ich wohl tatsächlich mal einen Counter mitzählen lassen. 
Ich werde berichten :) Danke soweit.

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.