Forum: Mikrocontroller und Digitale Elektronik ATMega 32 + Schrittmotoransteuerung+Interruptroutine


von René G. (gess12)


Lesenswert?

Hallo an Alle,

ich stehe hier vor einem kleinem Problem, vielleicht kann mir Jemand von 
euch helfen.
Für meine Projektarbeit benötige ich einen Schrittmotor.
Ich benutze einen ATMega32 dazu kommt eine Schrittmotorsteuerung aus 
L297/L298.
Den Schrittmotor habe ich am laufen aber mit einer Einschränkung.

Hier die Schilderung des Problems.

Der Schrittmotor wird gestartet und soll danach 600 Schritte lange 
drehen.
Das ganze ist Interrupt gesteuert über einen Timer. Das macht er auch.
Danach sollen 30 Sekunden vergehen, dann soll er wieder 600 Schritte 
drehen, und nach 30 Sekunden das gleiche Spiel. Und das über 6 Minuten.

Allerdings kommt es jetzt gelegentlich vor das anstatt 600 Schritte, nur 
512 Schritte gemacht werden. Und das unregelmäßig, kein festes Muster zu 
erkennen. Mal macht er es 1 mal in den 6 Minuten, manchmal 2 mal.

Ich lasse in der Interruptroutine eine Variable hochzählen und auf dem 
Display ausgeben, so das ich sehen kann wie oft in die Interruptroutine 
gesprungen wird.

In der Funktion, welche den Timer einschaltet, gebe ich die 
Schrittanzahl vor, wenn diese erreicht wird, wird der Timer 
ausgeschaltet.

Ich verstehe es nicht wirklich.
Vielleicht hat von euch so etwas schon mal gehabt und kann mir einen Tip 
geben.

Danke
René

von Michael (Gast)


Lesenswert?

René Geßner schrieb:
> Vielleicht hat von euch so etwas schon mal gehabt und kann mir einen Tip
> geben.

Das könnte am Programm oder an Störungen auf der Stromversorgung liegen.

von René G. (gess12)


Lesenswert?

Hallo Michael,

vielen Dank für deine Antwort.
Was ich bis jetzt ausschliessen kann ist, das es nicht am Schrittmotor 
bzw. an der Schrittmotoransteuerung ( L297/L298) liegt.

Ich poste mal meinen Source Code. Da ich kein Profi bin kann mir schon 
mal ein Fehler unterlaufen.

Und hier die Kurzbeschreibung dazu.

Das Ganze läuft natürlich in einer Main ab, da das Programm doch sehr 
umfangreich ist, ist es nicht sinnvoll den gesamten Source Code zu 
posten.

Ich springe zuerst in die Schrittmotor Funktion, dort wird neben einer 
Ausgabe auf dem Display auch der Timer2 eingeschaltet solange die Anzahl 
der Schritte unter 600 ist. Ist der Timer2 eingeschaltet, und das 
Overflow Bit ist gesetzt wird in der ISR die Variable Schritte um eins 
erhöht. Wenn Schritte 600 erreicht hat wird der Timer2 wieder 
ausgeschaltet und ich springe in die Startfunktion. Dort startet dann 
die Zeit von 30 Sekunden.
Ist diese erreicht geht es zurück zur Schrittmotorfunktion. Und das 
Ganze läuft wieder bis 600 und geht zurück zur Startfunktion.

Da ich ja die Aufrufe der ISR in der ISR mitzähle und danach auf dem 
Display ausgebe muss wohl der Fehler in der Schrittmotorfunktion liegen, 
denn da wird wohl zu früh der Timer2 ausgeschaltet. Und das nur ab und 
zu und sehr unregelmäßig. Also kein festes Schema zu erkennen, eher 
Zufallsprinzip.

Lasse ich z.B. nur eine Umdrehung, also 200 Schritte, den Motor 
verfahren läuft es ohne ohne Probleme. Es werden exakt alle 30 Sekunden 
200 Takte verfahren über die 6 Minuten.

Dazu läuft paraell der Timer1, aber das sollte ja nicht das Problem 
sein. Sind ja zwei getrennte Bits zum ein- und ausschalten im TIMSK 
Register.

Also wer einen Fehler in meiner Programmierung findet darf es mir gern 
sagen. Ich weiß das es nicht professional programmiert ist, aber es 
funktioniert mit dieser einen Einschränkung.

Danke schon mal.

René
1
// ISR Routine
2
3
ISR( TIMER2_OVF_vect )
4
5
{
6
  
7
  Schritte++;        // hochzählen der Schritte
8
  schritte++;        // Hilfsvariable um die Anzahl der ISR Aufrufe zu zählen und auf Display auszugeben
9
    PORTB ^= ( 1 << 2 ) | (1<<0) | (1<<3);  // Ausgabe am PortB, Enable, Clock und Drehrichtung
10
  TIFR = 0x40;     // Rücksetzen des Interruptes
11
}
12
13
// Schrittmotorfunktion
14
15
 void Schrittmotor ()
16
{
17
    
18
    lcd_clear();            
19
      lcd_setcursor(2, 1 );
20
      lcd_string("Belichtungstest 1");
21
      lcd_setcursor(7, 3 );
22
      lcd_string(":   min");
23
24
    lcd_setcursor(6, 3 );
25
    lcd_data(M + 48);
26
    lcd_setcursor(8, 3 );
27
    lcd_data(S10 + 48 );
28
    lcd_setcursor(9, 3 );
29
    lcd_data(S +48);
30
  
31
  
32
  while(1)
33
   { 
34
    if (M >=0)
35
        Richtung=links;
36
    else
37
        Richtung=rechts;
38
39
    if (Schritte <= 599)
40
     {
41
           TIMSK = 0x44;        // Timer2 einschalten solange Schritte kleiner 600 ( 600 = Anzahl Schritte)
42
     }
43
          else
44
      {
45
                  TIMSK = 0x04;        // Timer2 ausschalten wenn 2000 Schritte erreicht sind.
46
      Schritte=0;
47
      Intervall=0;        // Zählen der Intervalle
48
      Start ();        
49
           }
50
        }  
51
}
52
53
void Start ()
54
{
55
  lcd_clear();
56
  lcd_setcursor(2, 1 );
57
  lcd_string("Belichtungstest 1");
58
  lcd_setcursor(7, 3 );
59
  lcd_string(":   min");
60
    
61
62
    lcd_setcursor(3,2);  // Nur für Anzeige der gezälten Schritte
63
    itoa(schritte, f,10);  // Nur für Anzeige der gezälten Schritte
64
    lcd_string(f);    // Nur für Anzeige der gezälten Schritte
65
66
  do
67
   {  
68
    lcd_setcursor(6, 3 );
69
    lcd_data(M + 48);
70
    lcd_setcursor(8, 3 );
71
    lcd_data(S10 + 48 );
72
    lcd_setcursor(9, 3 );
73
    lcd_data(S +48);
74
    
75
  if (S >9)
76
   {
77
    S=0;
78
    S10++; 
79
   }
80
81
  if (S10>5)
82
   {
83
    S10=0;
84
    M++;
85
   }
86
87
  if (S==1)
88
   Zyklus=0;
89
      
90
  if (M >= 0 && Zyklus==0)
91
   {
92
    if ((S10 == 0 || S10 == 3 ) && S == 0 )  //((S10 == 0 || S10 == 1 || S10 == 2 || S10 == 3 || S10 == 4 || S10 == 5) && (S == 0 || S == 5))
93
     {
94
      Intervall=1;   //
95
      Zyklus=1; // Verhindert Zweimaliges durchlaufen der Schrittmotorfunktion
96
     }
97
   }
98
    
99
   while( Intervall != 1);        // Ende Belichtung
100
    {
101
     if (M >= 6)
102
     {
103
      M=0;
104
      S10=0;
105
      S=0;
106
      schritte=0;
107
     TIMSK = 0x00;
108
     Test1();
109
     }
110
    
111
     else
112
     {  
113
      Schrittmotor ();
114
     }
115
    }
116
}

von Michael (Gast)


Lesenswert?

René Geßner schrieb:
> PORTB ^= ( 1 << 2 ) | (1<<0) | (1<<3);  // Ausgabe am PortB, Enable, Clock und 
Drehrichtung

Das Timing der Ansteuerung für den L297 solltest du dir noch mal genauer 
im Datenblatt ansehen. Du darfst nicht alle Pins gleichzeitig 
umschalten.

von René G. (gess12)


Lesenswert?

Normalerweise sollte das Timing stimmen, der Schrittmotor dreht sich 
sauber und zügig, verbraucht auch wenig Strom.

Ich hatte erst eine andere Variante um den Clock zu erzeugen für die 
Geschwindigkeit.
1
PORTB = (1<<PB2) | (1<<PB0) | (Richtung<<PB3);
2
   
3
  for (i = 0; i <= 150; i++)
4
  {
5
  }
6
  PORTB = (0<<PB2) | (0<<PB0);

Da habe ich sozusagen jeden Interrupt genutzt um einen Clock auf den 
Schrittmotor zu geben. Mit der For-Schleife konnte ich die Dauer des 
High-Signals einstellen. Und so lange diese High-Flanke kürzer war als 
die Periodenzeit des Timers sollte das auch kein Problem sein. Dies 
hatte den Vorteil das eben bei 600 Schritte 3 Umdrehungen gemacht 
wurden.
Mit der Methode jetzt brauche ich ja die doppelte Anzahl von Schritten.
Aber das spielt für mich im Moment nicht die Rolle. Und damit hatte es 
auch nicht funktioniert.

Dadurch das es jetzt toggelt, ist bei einem Low, Enable auch auf Low. 
Aber das macht nichts.

Allerdings habe ich es jetzt geschafft das die Anzahl der Schritte 
stabil bleibt und exakt 600 Schritte sich der Motor weiter dreht aller 
30 Sekunden.
Aber verstehen kann ich es nicht wirklich.

Ich habe jetzt nur noch eine kleine Zeitschleife in der 
Schrittmotorfunktion, bevor der Timer2 eingeschaltet wird.
Seitdem keine Probleme mehr bei 600 Schritten.

Hier der Source Code
1
 void Schrittmotor ()
2
{
3
    lcd_clear();
4
      lcd_setcursor(2, 1 );
5
      lcd_string("Belichtungstest 1");
6
      lcd_setcursor(7, 3 );
7
      lcd_string(":   min");
8
9
    lcd_setcursor(6, 3 );
10
    lcd_data(M + 48);
11
    lcd_setcursor(8, 3 );
12
    lcd_data(S10 + 48 );
13
    lcd_setcursor(9, 3 );
14
    lcd_data(S +48);
15
  
16
  
17
  while(1)
18
   {
19
    
20
     
21
  
22
    if (M >=0)
23
        Richtung=links;
24
     else
25
       Richtung=rechts;
26
     
27
     if (Schritte <= 599)
28
     {
29
    
30
       for(i=0; i <= 20; i++)  // Neu, für genaue Schritte 
31
  {
32
  } 
33
         
34
      TIMSK = 0x44;        // Timer2 einschalten solange Schritte kleiner 600 ( 600 = Anzahl Schritte)
35
    
36
       }
37
      else
38
 
39
       {
40
          TIMSK = 0x04;        // Timer2 ausschalten wenn 2000 Schritte erreicht sind.
41
       
42
     Schritte=0;
43
     Intervall=0;
44
     Start ();
45
       }
46
    }
47
  
48
}

von René G. (gess12)


Lesenswert?

Hallo Michael,
du hattest Recht, es lag am Timing für die Schrittmotoransteuerung.
Habe mich heute Morgen noch einmal, ausgeschlafen, daran gesetzt die 
Datenblätter zu wälzen und danach das Timing korrekt eingestellt und 
seit dem gibt es keine Probleme mehr. Die Clockimpulse werden jetzt 
exakt am PortB ausgegeben, egal welche Anzahl ich einstelle.

Ich danke dir für deine Hilfe.

René

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.