Forum: Mikrocontroller und Digitale Elektronik Schrittmotoren


von amal (Gast)


Lesenswert?

bitte um Korrektur, der Motor sollte nach 100 Schritte anhalten, aber 
das tut er nicht:
[c]
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned int zx=0,zy=0;
void motorxR(unsigned int schr);
void motorxL(unsigned int schr);

int main()
{
DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)| (1<<PB5); // PIN0-5 
als Ausgang für die Motoren definieren // PortB als Ausgang definieren
DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren



TCCR1A = (1<<COM1A0) | (0<<WGM11);
TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10);
OCR1A=18432;


//****************** Interrupt initialisieren 
*************************************
PCMSK1 = (1 << PCINT|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << 
PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1 
setzen
PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3 
setzen für PCINT30

//*********** TIMER1 OVF *****************

TIMSK1|=(1<<TOIE1);
sei();

while (1) {}
}

ISR(TIMER1_OVF_vect)
{
zx++;
if(zx>100)
{
PORTB&=~(1<<PB0);
TCCR1B&=~(1<<CS10);
}
zx=0;
}

ISR(PCINT1_vect) //Interrupt Service Routine
{
if(!(PINC&(1<<PC0)))
{motorxR(zx);
}
if(!(PINC&(1<<PC1)))
{motorxL(zx);
}
}

void motorxR(unsigned int schr)
{
PORTB|=(1<<PB4);
PORTB|=(1<<PB0);
}
void motorxL(unsigned int schr)
{
PORTB&=~(1<<PB4);
PORTB|=(1<<PB0);
} [c]

von Albert .. (albert-k)


Lesenswert?

Der Fehler liegt hier drin
amal schrieb:
> unsigned int zx=0,zy=0;
Du musst die Variablen zx und als volatile deklarieren. Sonst weiß der 
kompiler nicht das zx auch von außerhalb der ISR gesetzt werden kann und 
das er sie nicht bei jeder ausfürhugn der ISR neu initialisieren soll.

von Nikos (Gast)


Lesenswert?

Ohne das jetzt gelesen zu haben ...
Globale Variablen müssen mit volatile deklariert werden wenn sie in der 
ISR routine verändert werden sollen

von Nikos (Gast)


Lesenswert?

ups zu langsam ... :-D

von amal (Gast)


Lesenswert?

amal schrieb:
Nikos schrieb:
> ups zu langsam ... :-D
was ist zu langsam

von amal (Gast)


Lesenswert?

es ist leider nicht der Fall, der Motor dreht sich immer noch ohne ende.

von Albert .. (albert-k)


Lesenswert?

Mir ist in der ISR beim genaueren betrachten folgendes aufgefallen:
amal schrieb:
> ISR(TIMER1_OVF_vect)
> {
> zx++;
> if(zx>100)
> {
> PORTB&=~(1<<PB0);
> TCCR1B&=~(1<<CS10);
> }
> zx=0;
> }
Du zählst zx am Anfang hoch udn vergleichst dann, und am Ende setzt du 
es wieder auf 0 zurück. natürlich wird es so niemals 100 erreichen da es 
immer wieder bei 0 anfängt. Du musst zx=0 in die if-Abfrage packen.

von ulp (Gast)


Lesenswert?

das liegt daran das du zx direkt wieder auf 0 setzt

das muss in die if anweisung

von amal (Gast)


Lesenswert?

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
volatile uint16_t zx=0,
4
void motorxR(unsigned int schr);
5
void motorxL(unsigned int schr);
6
7
int main()
8
{
9
DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)| (1<<PB5); // PIN0-5
10
als Ausgang für die Motoren definieren // PortB als Ausgang definieren
11
DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren
12
13
14
15
TCCR1A = (1<<COM1A0) | (0<<WGM11);
16
TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10);
17
OCR1A=18432;
18
19
20
//****************** Interrupt initialisieren
21
*************************************
22
PCMSK1 = (1 << PCINT|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 <<
23
PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1
24
setzen
25
PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3
26
setzen für PCINT30
27
28
//*********** TIMER1 OVF *****************
29
30
TIMSK1|=(1<<TOIE1);
31
sei();
32
33
while (1) {}
34
}
35
36
ISR(TIMER1_OVF_vect)
37
{
38
zx++;
39
if(zx>100)
40
{
41
PORTB&=~(1<<PB0);
42
TCCR1B&=~(1<<CS10);
43
}
44
zx=0;
45
}
46
47
ISR(PCINT1_vect) //Interrupt Service Routine
48
{
49
if(!(PINC&(1<<PC0)))
50
{motorxR(zx);
51
}
52
if(!(PINC&(1<<PC1)))
53
{motorxL(zx);
54
}
55
}
56
57
void motorxR(unsigned int schr)
58
{
59
PORTB|=(1<<PB4);
60
PORTB|=(1<<PB0);
61
}
62
void motorxL(unsigned int schr)
63
{
64
PORTB&=~(1<<PB4);
65
PORTB|=(1<<PB0);
66
}
ja wie gesagt der Motor dreht sich permanent

von amal (Gast)


Lesenswert?

1
C-
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
volatile uint16_t zx=0,
5
void motorxR(unsigned int schr);
6
void motorxL(unsigned int schr);
7
8
int main()
9
{
10
DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)| (1<<PB5); // PIN0-5
11
als Ausgang für die Motoren definieren // PortB als Ausgang definieren
12
DDRC = 0; //PORTC als Eingang für PCINT MASK 1 definieren
13
14
15
16
TCCR1A = (1<<COM1A0) | (0<<WGM11);
17
TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10);
18
OCR1A=18432;
19
20
21
//****************** Interrupt initialisieren
22
*************************************
23
PCMSK1 = (1 << PCINT|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 <<
24
PCINT12)|(1 << PCINT13); //Pin C0-5 für Pin Change Interrupt in Maske 1
25
setzen
26
PCICR |= (1 << PCIE1); //Pin Change Interrupt Control Register - PCIE3
27
setzen für PCINT30
28
29
//*********** TIMER1 OVF *****************
30
31
TIMSK1|=(1<<TOIE1);
32
sei();
33
34
while (1) {}
35
}
36
37
ISR(TIMER1_OVF_vect)
38
{
39
zx++;
40
if(zx>100)
41
{
42
PORTB&=~(1<<PB0);
43
TCCR1B&=~(1<<CS10);
44
}
45
zx=0;
46
}
47
48
ISR(PCINT1_vect) //Interrupt Service Routine
49
{
50
if(!(PINC&(1<<PC0)))
51
{motorxR(zx);
52
}
53
if(!(PINC&(1<<PC1)))
54
{motorxL(zx);
55
}
56
}
57
58
void motorxR(unsigned int schr)
59
{
60
PORTB|=(1<<PB4);
61
PORTB|=(1<<PB0);
62
}
63
void motorxL(unsigned int schr)
64
{
65
PORTB&=~(1<<PB4);
66
PORTB|=(1<<PB0);
67
}
ja wie gesagt der Motor dreht sich permanent

von ulp (Gast)


Lesenswert?

das liegt daran das du zx direkt wieder auf 0 setzt

das muss in die if anweisung

ulp schrieb:
> das liegt daran das du zx direkt wieder auf 0 setzt
>
> das muss in die if anweisung

von Tip (Gast)


Lesenswert?

Kannst du mit deiner Entwicklungsumgebnung (welche?) den Programmablauf 
nicht simulieren und dabei die Variablenwerte verfolgen? Dann würdest du 
sofort sehen, wenn etwas anders läuft als vorgesehen.
AVR-Strudio 4.18 z.B. konnte das.

von amal (Gast)


Lesenswert?

Tip schrieb:
> Kannst du mit deiner Entwicklungsumgebnung (welche?) den Programmablauf
> nicht simulieren und dabei die Variablenwerte verfolgen? Dann würdest du
> sofort sehen, wenn etwas anders läuft als vorgesehen.
> AVR-Strudio 4.18 z.B. konnte das.

ich könnte das nur wenn ich mit Assembler programmiere, in C weiß ich 
nicht wie das geht, weil du gar nicht weißt wo dein Prog steht. auf 
jedenfall der Fehler liegt daran, dass ich nie einen OVF erreichen kann, 
weil in CTC Mode 4 erreicht man OVF nur bei Max=FFFF, deswegen wird ich 
jetzt anderen Weg nehmen, und zwar über ISR(TIMER1_COMPA_Vect).übrigens 
ich habe AVR4.14

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Albert ... schrieb:
> Du musst die Variablen zx und als volatile deklarieren. Sonst weiß der
> kompiler nicht das zx auch von außerhalb der ISR gesetzt werden kann und
> das er sie nicht bei jeder ausfürhugn der ISR neu initialisieren soll.
Falsch.

Nikos schrieb:
> Globale Variablen müssen mit volatile deklariert werden wenn sie in der
> ISR routine verändert werden sollen
Auch falsch. Aber schon ein wenig besser... ;-)

Variablen müssen als volatil deklariert werden, wenn sie unverhofft von 
ausserhalb einer Funktion geändert werden könnten. Wenn z.B. in einer 
"normalen" Funktion ein Wert verwendet wird, sich dieser Wert aber von 
aussen ändern kann (z.B. ein Timer oder ein Pin oder eine globale 
Variable), dann muß dem Compiler gesagt werden, er soll diesen Wert doch 
bitte jedesmal neu einlesen. Und dieses "der Wert kann sich unvermittlet 
ändern" bedeutet volatil (=flüchtig).

Eine globale Variable, die in einer nicht unterbrechbaren 
Interuptroutine nur gelesen wird, braucht dieses Schlüsselwort also 
sicher nicht.

Eine globale Variable, die nur in 1 Interuptroutine verwendet, braucht 
dieses Schlüsselwort auch nicht.

Ein Problem wurde schon genannt:
1
ISR(TIMER1_OVF_vect)
2
{
3
  zx++;      // hochzählen 
4
  if(zx>100) 
5
  {
6
    PORTB&=~(1<<PB0);
7
    TCCR1B&=~(1<<CS10);
8
  }  
9
  zx=0;      // zu Null setzen
10
}
zx wird NIEMALS größer 100.
zx hatt immer nur die Werte 0 und 1.
Die meiste Zeit ist zx = 0.

@ amal
Formatier deinen Quelltext mit Einrückungen, dann siehst du das gleich..

von Jannis C. (kabelwurm)


Lesenswert?

Hallo,
Du must beim Hochzählen beachten, dass du wirklich zwei Möglichkeiten 
programmierst.

ISR(TIMER1_OVF_vect)
{
  zx++;      // hochzählen
  if(zx>100)      {
      PORTB&=~(1<<PB0);
      TCCR1B&=~(1<<CS10);
      }
  zx=0;      // zu Null setzen
}
Bei dem hier gibt es nur eine Möglichkeit da zx den Wert 100 nie 
erreichen kann.

ISR(TIMER1_OVF_vect)
{

  if(zx>100)
  {
    PORTB&=~(1<<PB0);
    TCCR1B&=~(1<<CS10);
    zx=0;      // zu Null setzen
  }esle{
    zx++;      // hochzählen
  }

}
Bei dieser Variante wird zx nur dann auf 0 gesetzt, wenn die Abfrage 
zutrifft.
Gruß Jannis

von amal (Gast)


Lesenswert?

ich habe jetzt den COMP Interrupt benutzt, ich möchte jetzt zum beispiel 
100schritte machen dann auf einem PIN eine PWM signal ausgeben, dann 
nochmal 100 Schritte, das ganze 10mal,das heißt der Motor soll sich 1000 
Schritte machen und 10 mal pwm signal ausgeben. und das habe ich so 
realisiert, ich bitte um Korrektur.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
5
6
7
8
volatile uint16_t zx=0,zy=0;
9
void motorxR(void);
10
11
void sleep_ms(unsigned int ms);
12
13
14
15
    
16
17
18
int main()
19
{
20
21
22
    DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5); // PIN0-5 als Ausgang für die Motoren definieren                // PortB als Ausgang definieren
23
    DDRC = 0;                     //PORTC als Eingang für PCINT MASK 1 definieren
24
25
26
  // Timer 1 einstellen
27
  //  
28
  // Modus 15:
29
  //    Fast PWM, Top von OCR1A
30
  //
31
  //    WGM13    WGM12   WGM11    WGM10
32
  //      0        1       0        0
33
  //
34
  //    Timer Vorteiler: 1
35
  //     CS12     CS11    CS10
36
  //       0        0       1
37
  //
38
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
39
  //     COM1A1   COM1A0
40
  //       0        1
41
 // OCR1A=(fclk/2*N)-1  N: Vorteiler
42
          TCCR1A = (1<<COM1A0) | (0<<WGM11)| (0<<WGM10);
43
         TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10);
44
         OCR1A=18432;
45
46
47
//******************               Interrupt initialisieren             *************************************
48
    PCMSK1 = (1 << PCINT8)|(1 << PCINT9)|(1 << PCINT10)|(1 << PCINT11)|(1 << PCINT12)|(1 << PCINT13);      //Pin C0-5 für Pin Change Interrupt in Maske 1 setzen
49
    PCICR  |= (1 << PCIE1);      //Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30
50
51
//***********  TIMER1 COMP *****************
52
53
        TIMSK1|=(1<<OCIE1A);
54
        TCNT1=0;
55
56
    
57
58
sei();    
59
60
        
61
    
62
63
64
 
65
  while (1) {}
66
}
67
68
69
70
ISR(TIMER1_COMPA_vect)
71
{
72
       if(zx>100)
73
        {
74
        PORTB&=~(1<<PB0);
75
        }
76
    zx++;
77
  
78
}
79
80
ISR(PCINT1_vect)            //Interrupt Service Routine
81
{
82
83
        sei();
84
        //*******************************       MESSUNG STARTEN    ********************************************
85
//*****************************************************************************************************
86
87
  if(!(PINC&(1<<PC0)))
88
     {
89
    
90
             for(unsigned int j=0;j<10;j++)
91
            {    
92
                  motorxR();
93
                PORTB|=(1<<PB5);        //
94
                sleep_ms(5);            //   TRIGGERN
95
                PORTB&=~(1<<PB5);        //
96
                sleep_ms(2);*/
97
                zx=0;            // WARTEN 2ms
98
            }
99
    }
100
101
void motorxR(void)
102
{
103
  PORTB|=(1<<PB3);
104
  PORTB|=(1<<PB0);
105
  //PORTB&=~(1<<PB2);
106
107
}
108
109
110
111
void sleep_ms(unsigned int ms)
112
{
113
  for (unsigned int s=0; s<ms; s++)
114
   {
115
    for (long int i=0; i<461; i++) 
116
  {
117
      asm volatile("nop"); 
118
    }
119
   }
120
}

von Jannis C. (kabelwurm)


Lesenswert?

Hallo



ISR(PCINT1_vect)            //Interrupt Service Routine
{

       sei ();


Willst du an dieser Stelle den Interrupt erlauben oder nicht?
Wenn du in abschalten willst dann musst du diesen Befehl benutzen: cli 
().
Gruß Jannis

von amal (Gast)


Lesenswert?

Jannis C. schrieb:
> Willst du an dieser Stelle den Interrupt erlauben oder nicht?

erlauben, ich will den nicht löschen

von Tip (Gast)


Lesenswert?

amal schrieb:
> ich könnte das nur wenn ich mit Assembler programmiere, in C weiß ich
> nicht wie das geht, weil du gar nicht weißt wo dein Prog steht.

Wieso weißt du nicht wie das geht, wenn ich nicht weiß, wo mein "Prog" 
steht?

In C unter AVRStudio gibt es im Menü "Debug" einige nützliche 
Funktionen. Vielleicht solltest du dich damit mal beschäftigen. Das 
würde dir die Fehlersuche deutlich erleichtern.

von Jannis C. (kabelwurm)


Lesenswert?

Hallo,
Um den Interrupt zu löschen musst du aber cli (); schreiben.
                sleep_ms(2);
Dafür gibt es delay- Funktion. Du musst also also die Funktion sleep 
löschen und ein paar Zeilen ergänzen.

#ifndef F_CPU
#define F_CPU ( Takt in Herz) UL
#endif

#include <util/delay.h>

Die vier Zeilen kopierst du dir unter die anderen Includes.
Anstelle von Sleep schreibst du jetzt _delay_ms(Zeit in Ms);

Gruß Jannis

von amal (Gast)


Lesenswert?

aber trotzdem der Motor macht nur 100 Schritte, nicht 10x100. weißt 
jemand warum

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.