Forum: Mikrocontroller und Digitale Elektronik Ein Interrupt stört den anderen


von B. L. (Gast)


Lesenswert?

Guten Abend!

Ich versuche gerade ein C Programm zu schreiben, in dem brauche ich den 
Analog Comparator Interrupt sowie den Timer 1 Interrupt, das Problem 
ist, der Timer 1 Interrupt wird ca. alle 25µs aufgerufen, und der Analog 
Comparator Interrupt ca. alle 500µs.

Das Problem ist, wenn während des Interrupts vom Analog Comparator der 
Timer Interrupt auslöst, geht mir ein Timer Interrupt verloren, und ich 
weiß nicht wie ich das ändern kann. Denn in meinem Timer Interrupt wird 
jedesmal ein Portpin getoggelt, und demnach wenn er ein Toggle verliert, 
ist plötzlich aus 10% duty cycle 90% duty cycle geworden.

Weiß jemand was abhilfe schafft?

Mit freundlichen Gruß

von Sascha (Gast)


Lesenswert?

Hat dein Prozessor keine Interruptflags, die man per Software abfragen 
kann bzw. solange bestehen bleiben, bis der Interrupt abgearbeitet 
wurde?

von Gaast (Gast)


Lesenswert?

> "abhilfe":

- Taktfrequenz erhöhen
- Ausführungsdauer der Interrupt-Routinen verringern
- Statt Interrupt Hardwarefunktionen nutzen (Output-Compare)

von B. L. (Gast)


Lesenswert?

Interruptflag sollte Abfragbar sein.

Hab nen AtMega8 µC der läuft auf 8MHz internen RC Oszillator.

MfG

von B. L. (Gast)


Lesenswert?

Das Problem ist, ich brauche eine variable die 8000 mal pro Sekunde 
umschaltet. Und das kann ich ja nicht mit dem Output Compare machen.

MfG

von Uwe .. (uwegw)


Lesenswert?

Was passiert denn alles in den ISR? (also wie viel Rechenzeit wird dort 
gebraucht?)

Eventuell könntest du in der Konparator-ISR die Interrupts wieder 
freigeben, damit die Timer-ISR die Konparator-ISR unterbrechen kann. 
Sowas ist allerdings mit Vorsicht zu genießen, falls der 
Konparator-Interrupt doch mal öfter ausgelöst wird und sich dann selbst 
unterbricht.

von B. L. (Gast)


Lesenswert?

Also in dem Komparatorinterrupt wird ein switch case ausgeführt. mit 6 
cases.

Im Timer Interrupt ist es etwas Umfangreicher undzwar, gibts 2 große if 
Abfragen ( ob die variable die getoggelt wird 1 oder 0 ist ) und in 
beiden Fällen wird wieder ein switch case mit 6 cases ausgeführt.

von STK500-Besitzer (Gast)


Lesenswert?

>Denn in meinem Timer Interrupt wird
>jedesmal ein Portpin getoggelt, und demnach wenn er ein Toggle verliert,
>ist plötzlich aus 10% duty cycle 90% duty cycle geworden.

Schon mal nach Output-Compare (OC...) geguckt?
Da macht der Timer das Pintogglen je nach Einstellung ganz von alleine 
in Hardware. Da geht nichts verloren. Geht aber auch nur mit bestimmten 
Portpins.

von STK500-Besitzer (Gast)


Lesenswert?

>Im Timer Interrupt ist es etwas Umfangreicher undzwar, gibts 2 große if
>Abfragen ( ob die variable die getoggelt wird 1 oder 0 ist ) und in
>beiden Fällen wird wieder ein switch case mit 6 cases ausgeführt.

Hatte ich überlesen...
Zeig mal deinen Code, und das Rumgestocher hat ein Ende.

von Karl H. (kbuchegg)


Lesenswert?

B. L. schrieb:

> Hab nen AtMega8 µC der läuft auf 8MHz internen RC Oszillator.

> Das Problem ist, ich brauche eine variable die 8000 mal pro Sekunde
> umschaltet. Und das kann ich ja nicht mit dem Output Compare machen.

D.h. du hast minimal 1000 Takte Zeit, ehe ein Timer Interrupt verloren 
geht
Das ist eine Menge Holz! Was machst du in deinem Compare Interrupt, dass 
sich das nicht ausgeht?

> Also in dem Komparatorinterrupt wird ein switch case
> ausgeführt. mit 6 cases.

Am switch wirds ja nicht liegen. Was passiert ín den cases?

Beschreibe nicht deine Code! Zeige ihn!

von Falk B. (falk)


Lesenswert?

Siehe Interrupt

von Juergen (Gast)


Lesenswert?

> der Timer 1 Interrupt wird ca. alle 25µs aufgerufen

> Im Timer Interrupt ist es etwas Umfangreicher

Deine Interrupt-Routinen sind zu groß.

von Sauger (Gast)


Lesenswert?

Moin,

8Mhz  = 0.125µs -> 8 Takte pro µs. Bei 25 µs hast du also 200 Takte 
zwischen den Timer Interrups.

MfG

von B. L. (Gast)


Lesenswert?

Also momentan ist in meinem Timer Interrupt ja nur der Toggle des 
Ausgangspins, also liegts hauptsächlich an dem Komparatorinterrupt der 
so aussieht:
1
char zahl=0;
2
3
ISR(ANA_COMP_vect) 
4
5
{
6
7
   switch(zahl)
8
9
   {  case 0: ACSR = 0b00001010; //fallende flanke
10
        MotorStep(1);
11
        ADMUX=5; //phase C rückkopplung
12
        break;
13
      case 1: ACSR = 0b00001011; //steigende flanke
14
              MotorStep(2);
15
        ADMUX=0; //phase B rückkopplung
16
              break;
17
      case 2: ACSR = 0b00001010; //fallende flanke
18
              MotorStep(3);
19
           ADMUX=1; //phase A rückkopplung
20
           break;
21
      case 3: ACSR = 0b00001011; //steigende flanke
22
              MotorStep(4);
23
         ADMUX=5; //phase C rückkopplung
24
        break;
25
      case 4: ACSR = 0b00001010; //fallende flanke
26
              MotorStep(5);
27
         ADMUX=0; //phase B rückkopplung
28
              break;
29
      case 5: ACSR = 0b00001011; //steigende flanke
30
              MotorStep(6);
31
           ADMUX=1; //phase A rückkopplung
32
        break;
33
   }
34
35
   zahl++;
36
   if(zahl==6)
37
   zahl=0;
38
39
}

Also wird in dem Interrupt noch die Funktion "Motorstep()" aufgerufen 
die wiefolgt aussieht:
1
void MotorStep(unsigned char Stufe)
2
{  
3
    switch(Stufe)
4
    { 
5
    case 1:    phaseAClr;
6
         phaseBSet;
7
         phaseCTri;
8
         break;
9
10
    case 2:    phaseAClr;
11
         phaseBTri;
12
         phaseCSet;
13
         break;
14
15
    case 3:    phaseATri;
16
         phaseBClr;
17
         phaseCSet;
18
         break;
19
20
    case 4:    phaseASet;
21
         phaseBClr;
22
         phaseCTri;
23
         break;
24
25
    case 5:    phaseASet;
26
         phaseBTri;
27
         phaseCClr;
28
         break;
29
30
    case 6:    phaseATri;
31
               phaseBSet;
32
         phaseCClr;
33
         break;
34
    }
35
}

Die Funtion ruft nun wiederum defines auf:
1
#define phaseASet   PORTD |= (1 << PD0);\
2
        PORTD |= (1 << PD1);
3
#define phaseAClr   PORTD &= ~(1 << PD1);\
4
        PORTD &= ~(1 << PD0);
5
#define phaseATri   PORTD |= (1 << PD0);\
6
        PORTD &= ~(1 << PD1);
7
#define phaseBSet   PORTD |= (1 << PD2);\
8
        PORTD |= (1 << PD3);
9
#define phaseBClr   PORTD &= ~(1 << PD3);\
10
            PORTD &= ~(1 << PD2);
11
#define phaseBTri   PORTD |= (1 << PD2);\
12
           PORTD &= ~(1 << PD3);
13
#define phaseCSet   PORTD |= (1 << PD4);\
14
        PORTD |= (1 << PD5); 
15
#define phaseCClr   PORTD &= ~(1 << PD5);\
16
        PORTD &= ~(1 << PD4);
17
#define phaseCTri   PORTD |= (1 << PD4);\
18
        PORTD &= ~(1 << PD5);

Also man sieht schon der Ablauf des Komparator Interrupts dauert sehr 
lang, aber ich wüsste keine Verbesserung.

Vielleicht könntet ihr mir sagen, wie ich das besser angehe?

MfG

von B. L. (Gast)


Lesenswert?

Sorry wegen der schlechten übersicht, ich hatte alles auf gerade 
gerichtet, nach dem Absenden aber sah alles so aus!

von Flo (Gast)


Lesenswert?

Verzichte mal in der ISR auf die Funktionsaufrufe von Motorstep und 
schreib das zutreffende direkt rein, also z.B.

ISR case 0:
         phaseAClr;
         phaseBSet;
         phaseCTri;
        break;

usw

könnte schon einiges an Zeit sparen, da kein Funktionsaufruf und kein 
weiteres switch.

von Route_66 (Gast)


Lesenswert?

Hallo!
> Die Funtion ruft nun wiederum defines auf:

Defines fressen keine Zeit, sondern erleichtern die Lesbarkeit.

von P. S. (Gast)


Lesenswert?

Gib halt am Anfang der Comparator-Interrupt-Routine die Interrupts 
wieder frei. Dann kann der Timer-Interrupt den Comparator unterbrechen. 
Musst halt nur sicher sein, dass es keine Ueberlaeufe gibt oder den Code 
manuell mit einem Flag schuetzen.

von B. L. (Gast)


Lesenswert?

Hallo!

Peter, also ich habe die Interrupt nun am Anfang der Komparator ISR 
wieder freigegeben, nun funktioniert es so, ohne dass er einzelne Timer 
Interrupt "verliert"

Nur wie meinst du, dass ich sicher gehen muss das kein Überlauf 
stattfindet?

MfG

von B. L. (Gast)


Lesenswert?

Achja, das ganze ist für eine PWM Steuerung für einen Brushless Motor 
gedacht
Es sollte einmal so aussehen, aber funktionieren tut es leider so nicht:
1
char Stufe=0;
2
3
ISR (TIMER1_COMPA_vect)
4
{ var=~var;
5
  if(var)
6
  {   
7
  switch(Stufe)
8
    { 
9
    case 1:phaseAClr;
10
         phaseBSet;
11
         phaseCTri;
12
         break;
13
    case 2:phaseAClr;
14
         phaseBTri;
15
         phaseCSet;
16
         break;
17
    case 3:phaseATri;
18
         phaseBClr;
19
         phaseCSet;
20
         break;
21
    case 4:phaseASet;
22
         phaseBClr;
23
         phaseCTri;
24
         break;
25
    case 5:phaseASet;
26
         phaseBTri;
27
         phaseCClr;
28
         break;
29
    case 6:phaseATri;
30
           phaseBSet;
31
         phaseCClr;
32
         break;
33
    }
34
}
35
else
36
{   
37
  switch(Stufe)
38
    { 
39
    case 1:phaseASet;
40
         phaseBClr;
41
         phaseCTri;
42
         break;
43
    case 2:phaseASet;
44
         phaseBTri;
45
         phaseCClr;
46
         break;
47
    case 3:phaseATri;
48
         phaseBSet;
49
         phaseCClr;
50
         break;
51
    case 4:phaseAClr;
52
         phaseBSet;
53
         phaseCTri;
54
         break;
55
    case 5:phaseAClr;
56
         phaseBTri;
57
         phaseCSet;
58
         break;
59
    case 6:phaseATri;
60
           phaseBClr;
61
         phaseCSet;
62
         break;
63
    }
64
}
65
66
}
char zahl=0;

ISR(ANA_COMP_vect)

{  sei();

   switch(zahl)

   {  case 0: ACSR = 0b00001010; //fallende flanke
            Stufe=1;
            ADMUX=5; //phase C rückkopplung
            break;
      case 1: ACSR = 0b00001011; //steigende flanke
              Stufe=2;
            ADMUX=0; //phase B rückkopplung
              break;
      case 2: ACSR = 0b00001010; //fallende flanke
              Stufe=3;
               ADMUX=1; //phase A rückkopplung
               break;
      case 3: ACSR = 0b00001011; //steigende flanke
              Stufe=4;
             ADMUX=5; //phase C rückkopplung
            break;
      case 4: ACSR = 0b00001010; //fallende flanke
              Stufe=5;
             ADMUX=0; //phase B rückkopplung
            break;
      case 5: ACSR = 0b00001011; //steigende flanke
              Stufe=6;
               ADMUX=1; //phase A rückkopplung
            break;
   }

   zahl++;
   if(zahl==6)
   zahl=0;

}

von j=sqrt(-1) (Gast)


Lesenswert?

OPEL = OhnePowerEwigLetzter.

Dein Problem besteht wntweder in der Leistungfähigkeit des Prozessors, 
deinen anforderungen oder der Umsetzung/effizienz.

Lade doch mal das ganze Programm mit beschreibung hoch.

von j=sqrt(-1) (Gast)


Lesenswert?

Darf man fragen warum du für einen Motor eine so hohe regelfrequenz 
braucht ?

von B. L. (Gast)


Lesenswert?

naja, die Kommutierungsfrequenz liegt schon bei 2kHz!
Ich kommentiere das Programm noch etwas dann lade ich es gesamt hoch!

MfG

von Hauke S. (hauke)


Lesenswert?

Ich sähe folgende Lösung für das Problem.

ISR für Comparator Ereigniss:
  Abschalten des Comparator Interupts
  Setzen des Global Interrupt Enable (SEI)
    Abarbeiten der Comparator ISR
  Wiederanschalten des Comparator Interupts
Rücksprung

Dadurch kann die Comparator ISR nicht überlaufen und du verlierst keine 
Timer Interrupts.
Ein ganz anderes Problem ist jedoch wenn deine Timer ISR schon zu lang 
für die Zeit zwischen zwei Timer Interrupts ist.
Dann gibt es nur zwei Sachen:
- Schnellere CPU
- Optimieren,optimieren optimieren

cu
Hauke

von B. L. (Gast)


Lesenswert?

So hier der Gesamte Code, ich hoffe es ist einigermaßen Übersichtlich 
Kommentiert!
1
#include <avr/io.h>
2
#include <avr\interrupt.h>  
3
4
5
#define phaseASet   PORTD |= (1 << PD0);\
6
          PORTD |= (1 << PD1);
7
            //Am=0 Ap=1
8
#define phaseAClr   PORTD &= ~(1 << PD1);\
9
          PORTD &= ~(1 << PD0);
10
          //Ap=0 Am=1
11
#define phaseATri   PORTD |= (1 << PD0);\
12
          PORTD &= ~(1 << PD1);
13
          //Am=0 Ap=0
14
#define phaseBSet   PORTD |= (1 << PD2);\
15
          PORTD |= (1 << PD3);
16
          //Bm=0 Bp=1
17
#define phaseBClr   PORTD &= ~(1 << PD3);\
18
          PORTD &= ~(1 << PD2);
19
            //Bp=0 Bm=1
20
#define phaseBTri   PORTD |= (1 << PD2);\
21
          PORTD &= ~(1 << PD3);
22
          //Bm=0 Bp=0
23
#define phaseCSet   PORTD |= (1 << PD4);\
24
          PORTD |= (1 << PD5); 
25
          //Cm=0 Cp=1
26
#define phaseCClr   PORTD &= ~(1 << PD5);\
27
          PORTD &= ~(1 << PD4);
28
          //Cp=0 Cm=1
29
#define phaseCTri   PORTD |= (1 << PD4);\
30
          PORTD &= ~(1 << PD5);
31
          //Cm=0 Cp=0
32
33
void MotorStep(unsigned char);
34
void Hochfahren(void);
35
36
37
char zahl=0;
38
char Stufe=0;
39
char var=0;
40
41
42
ISR (TIMER1_COMPA_vect)
43
{ var=~var;
44
  if(var)
45
  {  switch(Stufe)
46
     { 
47
      case 1:phaseAClr;
48
            phaseBSet;
49
           phaseCTri;
50
           break;
51
      case 2:phaseAClr;
52
           phaseBTri;
53
           phaseCSet;
54
           break;
55
      case 3:phaseATri;
56
           phaseBClr;
57
           phaseCSet;
58
           break;
59
      case 4:phaseASet;
60
           phaseBClr;
61
           phaseCTri;
62
           break;
63
      case 5:phaseASet;
64
           phaseBTri;
65
           phaseCClr;
66
           break;
67
      case 6:phaseATri;
68
               phaseBSet;
69
           phaseCClr;
70
           break;
71
      } 
72
   }
73
74
   else
75
   {  switch(Stufe)
76
     { 
77
       case 1:phaseASet;
78
            phaseBClr;
79
            phaseCTri;
80
            break;
81
       case 2:phaseASet;
82
            phaseBTri;
83
            phaseCClr;
84
            break;
85
       case 3:phaseATri;
86
            phaseBSet;
87
            phaseCClr;
88
             break;
89
       case 4:phaseAClr;
90
            phaseBSet;
91
            phaseCTri;
92
            break;
93
       case 5:phaseAClr;
94
            phaseBTri;
95
            phaseCSet;
96
            break;
97
       case 6:phaseATri;
98
                 phaseBClr;
99
            phaseCSet;
100
            break;
101
     }
102
   }
103
104
}
105
 
106
void Timer_io_init(void)
107
{
108
  
109
  TCCR1A |= (1 << WGM11) | (0 << WGM10);
110
  TCCR1B |= (1 << WGM13) | (0 << WGM12); // phase correct mit ICR1 als TOP
111
 
112
 
113
  TCCR1B |= (0 << CS12)  | (0 << CS11)  | (1 << CS10); //CK
114
115
  ICR1=255; //TOP Wert
116
 
117
  OCR1A = 127; //Comparewert
118
 
119
  TIMSK = (1 << OCIE1A);
120
}
121
 
122
123
124
125
ISR(ANA_COMP_vect) 
126
127
{  sei();
128
129
   switch(zahl)
130
131
   {  case 0: ACSR = 0b00001010; //fallende flanke
132
            Stufe=1;
133
            ADMUX=5;           //phase C rückkopplung
134
            break;
135
      case 1: ACSR = 0b00001011; //steigende flanke
136
              Stufe=2;
137
            ADMUX=0;           //phase B rückkopplung
138
              break;
139
      case 2: ACSR = 0b00001010; //fallende flanke
140
              Stufe=3;
141
               ADMUX=1;           //phase A rückkopplung
142
               break;
143
      case 3: ACSR = 0b00001011; //steigende flanke
144
              Stufe=4;
145
             ADMUX=5;           //phase C rückkopplung
146
            break;
147
      case 4: ACSR = 0b00001010; //fallende flanke
148
              Stufe=5;
149
             ADMUX=0;           //phase B rückkopplung
150
            break;
151
      case 5: ACSR = 0b00001011; //steigende flanke
152
              Stufe=6;
153
               ADMUX=1;           //phase A rückkopplung
154
            break;
155
   }
156
157
   zahl++;
158
   if(zahl==6)
159
   zahl=0;
160
161
}
162
163
164
165
166
167
int main()
168
{   Timer_io_init();
169
170
    DDRD  = 0x3F; //Port D0 - D5 als Eingang
171
172
    SFIOR|=(1<<ACME); //Multiplexer aktiv
173
    
174
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
175
    ADMUX=1; //phase A rückkopplung
176
    
177
    
178
  Hochfahren();
179
180
    sei();
181
182
    while(1)
183
    {  
184
    }
185
186
187
}
188
189
void MotorStep(unsigned char Stufen)
190
{  
191
    switch(Stufen)
192
    { 
193
    case 1:phaseAClr;
194
         phaseBSet;
195
         phaseCTri;
196
         break;
197
    case 2:phaseAClr;
198
         phaseBTri;
199
         phaseCSet;
200
         break;
201
    case 3:phaseATri;
202
         phaseBClr;
203
         phaseCSet;
204
         break;
205
    case 4:phaseASet;
206
         phaseBClr;
207
         phaseCTri;
208
         break;
209
    case 5:phaseASet;
210
         phaseBTri;
211
         phaseCClr;
212
         break;
213
    case 6:phaseATri;
214
           phaseBSet;
215
         phaseCClr;
216
         break;
217
    }
218
}
219
220
void Hochfahren(void)
221
{   int i=0;
222
  for(int r=0;r<200;r++)
223
    {
224
       MotorStep(1);
225
       for(i=0;i<3000-10*r;i++)
226
        asm("nop");
227
  
228
     MotorStep(2);
229
   
230
     for(i=0;i<3000-10*r;i++)
231
     asm("nop");
232
233
     MotorStep(3);
234
     for(i=0;i<3000-10*r;i++)
235
     asm("nop");
236
  
237
238
     MotorStep(4);
239
   
240
     for(i=0;i<3000-10*r;i++)
241
     asm("nop");
242
243
     MotorStep(5);
244
   
245
     for(i=0;i<3000-10*r;i++)  
246
     asm("nop");
247
248
     MotorStep(6);
249
   
250
     for(i=0;i<3000-10*r;i++)
251
     asm("nop");
252
253
   }
254
}

von B. L. (Gast)


Lesenswert?

Hauke:
Ich verstehe den Sinn, von Abschalten und Rücksprung nicht, es ändert 
sich doch nichts an meinem jetzigen Programm? Denn irgendwie scheint es 
so als springst du aus der ISR raus und gleich wieder rein? Oder habe 
ich gerade einen enormen Denkfehler?

MfG

von Gastofatz (Gast)


Lesenswert?

Ich würde als erstes diese CASE-Konstruktion rauswerfen und das über ein 
banales Konstantenarray machen:
1
PORTD = PortDValue[Stufe]

wobei Du ins Array PortDValue schlicht die sechs Werte hinschreibst, auf 
die der Port bei Stufe x (x = 0, 1, 2, 3, 4, 5) gesetzt werden soll. Das 
reicht doch völlig aus.

>Hab nen AtMega8 µC der läuft auf 8MHz internen RC Oszillator.

>ich brauche eine variable die 8000 mal pro Sekunde umschaltet.

>  TCCR1B |= (0 << CS12)  | (0 << CS11)  | (1 << CS10); //CK
>  ICR1=255; //TOP Wert

Wie passt das zusammen? 8 MHz/(8000/s) sind 1000. Prescaler 1 mit 
TOP-Wert 255 wäre knapp viermal so schnell.

von j=sqrt(-1) (Gast)


Lesenswert?

0.
Optimierung beim Compiler eingeschaltet ?

1.
switch(Stufen)
    {
    case 1:phaseAClr;
         phaseBSet;
         phaseCTri;
         break;

Hier kann man doch bestimmt eleganter mit einem Bitmuster/Zustand 
arbeiten.
Es wird doch nur PORTD manipuliert.

Eine Zustandstabelle sollte da helfen.
Ev. lässt sich da noch was vereinfachen.


2.
Char als Flag ? Da ist eine unit8_t schöner, oder ?
(Geschmack wie auch immer)

3.

switch(zahl)

   {  case 0: ACSR = 0b00001010; //fallende flanke
            Stufe=1;
            ADMUX=5;           //phase C rückkopplung
            break;


Das ist wirklich blöd.... !!!!!

Erst bildest Du den Zustand in "Stufe" ab,
um ihn später in dem Timerinterrupt in die Wirklichkeit zu übertragen...

Speichere doch das entsprechende Bitmuster in Stufe oder nenne es 
Zustand und setzte den einfach in dem Timerinterrupt.

Du sprst auf jeden fall ein Case-Konstrukt.

von j=sqrt(-1) (Gast)


Lesenswert?

3.1 Auf Deutsch :

Soll heissen Speichere das entsprechende Bitmuster zum Manipulieren von 
PORTD bereits in Deinem Komparator-Interrupt.

Deine Bitmuster kannst Du ja noch als define in deinem Programm lassen.

Den Toggle kannst Du global als volatile "exportieren",
oder Du setzt immer auch das komplement.

Bei zwei möglichkeiten ist das nicht so schlimm.

von STK500-Besitzer (Gast)


Lesenswert?

Ich habe deinen Code nur überflogen.
Mir stellt sich folgende Frage:
Passiert auf dem Port D noch mehr als nur die Motoransteuerung?
Sonst könnte man die Zuweisungen in ein Array packen und einfach den 
Inhalt des jeweiligen Feldeintrags in Port D kopieren.
Damit wären diverse Abfragen einfach raus.
Wenn noch mehr auf Port D passieren soll, dann müsste man die übrigen 
Bist in einer/weiteren Variablen zwischenspeichern und diese dann alle 
miteinander verodern, bevor man Port D beschreibt.
Damit wäre die Switch-Case-Abfrage schon mal etwas kürzer...
Notfalls (da es ja unterschiedliche Switch-Case-Abfragen sind/zu sein 
scheinen), macht man das Array entsprechend größer, so dass man ein Mal 
die Werte für var und ein Mal für ~var hat.

Die Umschaltung der Analog-Converter-Flanke sollte man auch durch durch 
ein einfaches Togglen des untersten Bits erreichen können.
So wie ich das sehe, wird die Flankenrichtung bei jedem ISR-Aufruf 
geändert.
Entweder kann man direkt das ACSR ändern, oder man braucht noch eine 
Hilfsvariable:
Das Togglen würde so aussehen: ACSR ^= 1; (Hier darf auch gerne der 
Bit-Name mit der (1<<xy)-Schreibweise eingesetzt werden.
Wenn sich im ACSR noch andere Bits ändern, muss man auf eine 
Hilfsvariable zurückgreifen, die man genauso behandelt und dann ins ACSR 
schreibt.

Durch das Einsetzen von Arrays braucht man zwar mehr Speicher, ist dafür 
aber (wesentlich) schneller.

von B. L. (Gast)


Lesenswert?

j=sqrt(-1) schrieb:
> 0.
> Optimierung beim Compiler eingeschaltet ?
  -Os ist eingeschaltet.

> 2.
> Char als Flag ? Da ist eine unit8_t schöner, oder ?
> (Geschmack wie auch immer)
  Habs jetzt auf uint8_t!
> 3.
>
> switch(zahl)
>
>    {  case 0: ACSR = 0b00001010; //fallende flanke
>             Stufe=1;
>             ADMUX=5;           //phase C rückkopplung
>             break;
>
>
> Das ist wirklich blöd.... !!!!!
>
> Erst bildest Du den Zustand in "Stufe" ab,
> um ihn später in dem Timerinterrupt in die Wirklichkeit zu übertragen...
>
> Speichere doch das entsprechende Bitmuster in Stufe oder nenne es
> Zustand und setzte den einfach in dem Timerinterrupt.
>
> Du sprst auf jeden fall ein Case-Konstrukt.

Ich versteh nicht wie du das meinst, ich muss es deshalb im Interrupt in 
die Wirklichkeit übertragen, da im Interrupt der Ausgang noch getaktet 
wird zusätzlich.

Hier ist jetzt mein geänderter Code, sieht einiges eleganter aus:
1
#include <avr/io.h>
2
#include <avr\interrupt.h>  
3
4
void Hochfahren(void);
5
void Timer_io_init(void);
6
7
char zahl=0;
8
uint8_t Stufe=0;
9
char var=0;
10
const uint8_t PBvals[6]={0b00011100,
11
             0b00110100,
12
             0b00110001,
13
             0b00010011,
14
             0b00000111,
15
             0b00001101
16
              };
17
18
const uint8_t PBvalc[6]={0b00010011,
19
             0b00000111,
20
             0b00001101,
21
             0b00011100,
22
             0b00110100,
23
             0b00110001
24
              };
25
26
ISR (TIMER1_COMPA_vect)
27
{ var=~var;
28
  if(var)
29
  PORTB=PBvals[Stufe];
30
  else
31
  PORTB=PBvalc[Stufe];
32
}
33
34
ISR(ANA_COMP_vect) 
35
36
{  sei();
37
38
   switch(zahl)
39
40
   {  case 0: ACSR = 0b00001010; //fallende flanke
41
            Stufe=0;
42
            ADMUX=5;           //phase C rückkopplung
43
            break;
44
      case 1: ACSR = 0b00001011; //steigende flanke
45
              Stufe=1;
46
            ADMUX=0;           //phase B rückkopplung
47
              break;
48
      case 2: ACSR = 0b00001010; //fallende flanke
49
              Stufe=2;
50
               ADMUX=1;           //phase A rückkopplung
51
               break;
52
      case 3: ACSR = 0b00001011; //steigende flanke
53
              Stufe=3;
54
             ADMUX=5;           //phase C rückkopplung
55
            break;
56
      case 4: ACSR = 0b00001010; //fallende flanke
57
              Stufe=4;
58
             ADMUX=0;           //phase B rückkopplung
59
            break;
60
      case 5: ACSR = 0b00001011; //steigende flanke
61
              Stufe=5;
62
               ADMUX=1;           //phase A rückkopplung
63
            break;
64
   }
65
66
   zahl++;
67
   if(zahl==6)
68
   zahl=0;
69
70
}
71
72
73
74
75
76
int main()
77
{   Timer_io_init();
78
79
    DDRB  = 0x3F; //Port D0 - D5 als Eingang
80
81
    SFIOR|=(1<<ACME); //Multiplexer aktiv
82
    
83
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
84
    ADMUX=1; //phase A rückkopplung
85
    
86
    
87
  Hochfahren();
88
89
    sei();
90
91
    while(1)
92
    {  
93
    }
94
95
96
}
97
98
void Timer_io_init(void)
99
{
100
  
101
  TCCR1A |= (1 << WGM11) | (0 << WGM10);
102
  TCCR1B |= (1 << WGM13) | (0 << WGM12); // phase correct mit ICR1 als TOP
103
  TCCR1B |= (0 << CS12)  | (0 << CS11)  | (1 << CS10); //CK
104
105
  ICR1=500; //TOP Wert
106
 
107
  OCR1A = 400; //Comparewert
108
 
109
  TIMSK = (1 << OCIE1A);
110
}
111
 
112
void Hochfahren(void)
113
{   int i=0;
114
  for(int r=0;r<200;r++)
115
    {
116
       PORTB=PBvals[0];
117
       for(i=0;i<3000-10*r;i++)
118
        asm("nop");
119
  
120
     PORTB=PBvals[1];
121
     for(i=0;i<3000-10*r;i++)
122
     asm("nop");
123
124
     PORTB=PBvals[2];
125
     for(i=0;i<3000-10*r;i++)
126
     asm("nop");
127
  
128
       PORTB=PBvals[3];
129
     for(i=0;i<3000-10*r;i++)
130
     asm("nop");
131
132
     PORTB=PBvals[4];
133
     for(i=0;i<3000-10*r;i++)  
134
     asm("nop");
135
136
     PORTB=PBvals[5];
137
     for(i=0;i<3000-10*r;i++)
138
     asm("nop");
139
140
   }
141
}

MfG

von Gastofatz (Gast)


Lesenswert?

Dann würde ich dasselbe gleich auch mit dem zweiten CASE-Konstrukt 
machen.

>  switch(zahl)
>
>   {  case 0: ACSR = 0b00001010; //fallende flanke
>            Stufe=0;
>            ADMUX=5;           //phase C rückkopplung
>            break;
>      case 1: ACSR = 0b00001011; //steigende flanke
>              Stufe=1;
>            ADMUX=0;           //phase B rückkopplung
>              break;
>      .............
>      .............
>      .............

kannst Du ersetzen durch
1
Stufe = zahl
2
ACSR  = ACSR_DATA[Stufe]
3
ADMUX = ADMUX_DATA[Stufe]

und in den Konstantenarrays ACSR_DATA[6] und ADMUX_DATA[6] die Daten 
reinschreiben - fertig.

>var=~var;
>  if(var)
>  PORTB=PBvals[Stufe];
>  else
>  PORTB=PBvalc[Stufe];

Was soll die Umschaltung über var bezwecken?

In Assembler kannst Du die Sache übrigens mit genau 15 Taktzyklen 
erledigen, sofern die Stufe-Variable in einem eigenen Register s 
vorgehalten wird (ohne Berücksichtigung Deiner var-Umschaltung):
1
TimerInterrupt:
2
    in   SREGSave, SREG       ; 1 cycle
3
4
    ldi  ZL, Low (PORTDATA)   ; 1 cycle
5
    ldi  ZH, High(PORTDATA)   ; 1 cycle
6
    add  ZL, s                ; 1 cycle
7
    ld   r0, Z                ; 2 cycles
8
    out  PORTD, r0            ; 1 cycle
9
10
    subi s, 1                 ; 1 cycle
11
    brsh StufeNotNeg          ; 2 cycles
12
    ldi  s, 6-1
13
14
StufeNotNeg:
15
    out  SREG, SREGSave       ; 1 cycle
16
17
    reti                      ; 4 cycles

von B. L. (Gast)


Lesenswert?

Gastofatz schrieb:
> Dann würde ich dasselbe gleich auch mit dem zweiten CASE-Konstrukt
> machen.
>
>>  switch(zahl)
>>
>>   {  case 0: ACSR = 0b00001010; //fallende flanke
>>            Stufe=0;
>>            ADMUX=5;           //phase C rückkopplung
>>            break;
>>      case 1: ACSR = 0b00001011; //steigende flanke
>>              Stufe=1;
>>            ADMUX=0;           //phase B rückkopplung
>>              break;
>>      .............
>>      .............
>>      .............
>
> kannst Du ersetzen durch
> Stufe = zahl
> ACSR  = ACSR_DATA[Stufe]
> ADMUX = ADMUX_DATA[Stufe]
>
> und in den Konstantenarrays ACSR_DATA[6] und ADMUX_DATA[6] die Daten
> reinschreiben - fertig.


Welche Geschwindigkeitssteigerung würde das bringen?

Das vorgeschlagene ACSR ^=1; Funktioniert nicht!

>>var=~var;
>>  if(var)
>>  PORTB=PBvals[Stufe];
>>  else
>>  PORTB=PBvalc[Stufe];
>
> Was soll die Umschaltung über var bezwecken?

Das soll nur dazu da sein, dass ich entweder 0 oder 1 in der var 
variable habe, denn wenn ich jetzte 9:10 habe möchte ich gerne 9 Teile 
lang PBvals[] haben und 1 Teil PBvalc[]
weißt du wie ich mein

> In Assembler kannst Du die Sache übrigens mit genau 15 Taktzyklen
> erledigen, sofern die Stufe-Variable in einem eigenen Register s
> vorgehalten wird (ohne Berücksichtigung Deiner var-Umschaltung):
> TimerInterrupt:
>     in   SREGSave, SREG       ; 1 cycle
>
>     ldi  ZL, Low (PORTDATA)   ; 1 cycle
>     ldi  ZH, High(PORTDATA)   ; 1 cycle
>     add  ZL, s                ; 1 cycle
>     ld   r0, Z                ; 2 cycles
>     out  PORTD, r0            ; 1 cycle
>
>     subi s, 1                 ; 1 cycle
>     brsh StufeNotNeg          ; 2 cycles
>     ldi  s, 6-1
>
> StufeNotNeg:
>     out  SREG, SREGSave       ; 1 cycle
>
>     reti                      ; 4 cycles

Naja Assembler, hab ich absolut 0 Ahnung leider

von B. L. (Gast)


Lesenswert?

Ich vermute, da die Komparator Interrupt routine ja ständig vom Timer 
Interrupt unterbrochen wird, das das Toggeln nicht funktioniert, da 
irgendwas nicht past daraufhin?

MfG

von P. S. (Gast)


Lesenswert?

B. L. schrieb:

> Nur wie meinst du, dass ich sicher gehen muss das kein Überlauf stattfindet?

Wenn du den Interrupt wieder freigibst und deine Interruptroutine so 
lange dauert, dass der Interrupt schon wieder auftritt, bevor du fertig 
bist, hast du ein Problem. Klar, oder? Wenn du dir also bei einer deiner 
Interruptroutinen nicht sicher bist, ob sie schnell genug ist, kannst du 
an deren Anfang einfach ein Flag pruefen, das signalisiert, dass der 
letzte Aufruf noch laeuft.

volatile bool IsRunning = false;

void InterruptRoutine( void)
{
  if( IsRunning == true) return;

  IsRunning = true;

  DoSomething();

  IsRunning = false;
}

So in der Art. Ein klitzekleines Fenster ist natuerlich am Ende der 
Routine noch, wo die Routine noch akive, das Flag aber schon geloescht 
ist...

von Route_66 (Gast)


Lesenswert?

> Naja Assembler, hab ich absolut 0 Ahnung leider

Hallo!
Jungfrau und schwanger geht nicht gleichzeitig (von historischen 
Ausnahmen abgesehen).
So ist es auch mit der Programmiererei! Entweder bequem per Hochsprache 
ODER effizient. Beides geht nicht.
Zumindest die meisten Hochsprachen bieten deshalb den Weg, 
Assemblerteile direkt einzubinden. Das erfordert aber immer sowohl 
genaue Kenntnis des Prozessors, als auch des entsprechenden 
Hochsprachen-Compilers.

Ich habe schon oft bei meinen Lösungen in ..C, ..Forth, ..Pascal oder 
gar ..Basic hinterher den Eindruck gehabt, daß ich wahrscheinlich mit 
meinem bevorzugten Programmieren in Assembler schneller, effizienter und 
auch fehlerfreier zum Ziel gekommen wäre...

Vielleicht könntest Du dich mit dem Gedanken -Assembler- mal anfreunden?

von B. L. (Gast)


Lesenswert?

Hmm, dass mit Assembler Programmiertes effizienter ist, wusste ich 
schon, aber nunja Assembler scheint mir ein wenig seeeehr kompliziert zu 
sein.

Hier mein jetziges Programm, es funktioniert ... so lala kann man sagen:
1
#include <avr/io.h>
2
#include <avr\interrupt.h>  
3
4
void Hochfahren(void);
5
void Timer_io_init(void);
6
7
char zahl=0;
8
uint8_t Stufe=0;
9
char var=0;
10
const uint8_t PBvals[6]={0b00011100,
11
             0b00110100,
12
             0b00110001,
13
             0b00010011,
14
             0b00000111,
15
             0b00001101
16
              };
17
18
const uint8_t PBvalc[6]={0b00011101,
19
             0b00110101,
20
             0b00110101,
21
             0b00010111,
22
             0b00010111,
23
             0b00011101
24
              };
25
const uint8_t ACSR_DATA[6]={0b00001010,
26
                0b00001011,
27
                0b00001010,
28
                0b00001011,
29
                0b00001010,
30
                0b00001011
31
                 };
32
const uint8_t ADMUX_DATA[6]={0b00000101,
33
                 0b00000000,
34
                 0b00000001,
35
                 0b00000101,
36
                 0b00000000,
37
                 0b00000001
38
                  };
39
40
ISR (TIMER1_COMPA_vect)
41
{ var=~var;
42
  if(var)
43
  PORTB=PBvals[Stufe];
44
  else
45
  PORTB=PBvalc[Stufe];
46
}
47
48
ISR(ANA_COMP_vect) 
49
50
{  sei();
51
   Stufe = zahl;
52
   ACSR  = ACSR_DATA[Stufe];
53
   ADMUX = ADMUX_DATA[Stufe];
54
   
55
   zahl++;
56
   if(zahl==6)
57
   zahl=0;
58
59
}
60
61
62
63
64
65
int main()
66
{   Timer_io_init();
67
68
    DDRB  = 0x3F; //Port B0 - B5 als Eingang
69
70
    SFIOR|=(1<<ACME); //Multiplexer aktiv
71
    
72
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
73
    ADMUX=1; //phase A rückkopplung
74
    
75
    
76
  Hochfahren();
77
78
    sei();
79
80
    while(1)
81
    {  
82
    }
83
84
85
}
86
87
void Timer_io_init(void)
88
{
89
  
90
  TCCR1A |= (1 << WGM11) | (0 << WGM10);
91
  TCCR1B |= (1 << WGM13) | (0 << WGM12); // phase correct mit ICR1 als TOP
92
  TCCR1B |= (0 << CS12)  | (0 << CS11)  | (1 << CS10); //CK
93
94
  ICR1=255; //TOP Wert
95
 
96
  OCR1A = 210; //Comparewert
97
 
98
  TIMSK = (1 << OCIE1A);
99
}
100
 
101
void Hochfahren(void)
102
{   int i=0;
103
  for(int r=0;r<200;r++)
104
    {
105
       PORTB=PBvals[0];
106
       for(i=0;i<3000-10*r;i++)
107
        asm("nop");
108
  
109
     PORTB=PBvals[1];
110
     for(i=0;i<3000-10*r;i++)
111
     asm("nop");
112
113
     PORTB=PBvals[2];
114
     for(i=0;i<3000-10*r;i++)
115
     asm("nop");
116
  
117
       PORTB=PBvals[3];
118
     for(i=0;i<3000-10*r;i++)
119
     asm("nop");
120
121
     PORTB=PBvals[4];
122
     for(i=0;i<3000-10*r;i++)  
123
     asm("nop");
124
125
     PORTB=PBvals[5];
126
     for(i=0;i<3000-10*r;i++)
127
     asm("nop");
128
129
   }
130
}

von Hauke S. (hauke)


Lesenswert?

@B.L.
Mein Vorschlag war so gemeint:


Normaler Ablauf:
Compare ISR wird aus gelöst: (Alle weiteren werden Interrups 
unterbunden)
  Compare ISR wird abgearbeitet (Timer INT wird evt. "vergessen")
Rücksprung aus ISR (RETI) (Interrupts werden wieder aktiviert)

1. Verbesserung:
Compare ISR wird aus gelöst: (Alle weiteren werden Interrups 
unterbunden)
  Setzen des Global Interrupt Enable (SEI)
    Compare ISR wird abgearbeitet (Timer INT kann ausgelöst werden)
    (während der Abarbeitung kann aber auch ein weiterer Compare INT 
ausgelößt werden)
    (Der Compare INT überfährt sich sozusagen selbst =8( )
Rücksprung aus Subroutine (RET) (Interrupts bleiben aktiviert)

Meine Verbesserung:
Compare ISR wird aus gelöst: (Alle weiteren werden Interrups 
unterbunden)
  Abschalten des Comparator Interupts
  Setzen des Global Interrupt Enable (SEI)
    Abarbeiten der Comparator ISR
    (Timer INT kann ausgelöst werden)
    (Compare INT kann NICHT ausgelößt werden da abgeschaltet)
    (Der Compare INT kann sich also NICHT selbst überfahren)
  Wiederanschalten des Comparator Interupts
Rücksprung


Wenn man ganz sicher gehen will:
Compare ISR wird aus gelöst: (Alle weiteren werden Interrups 
unterbunden)
  Abschalten des Comparator Interupts
  Setzen des Global Interrupt Enable (SEI)
    Abarbeiten der Comparator ISR
  Löschen des Global Interrupt Enable (CLI)
  Wiederanschalten des Comparator Interupts
Rücksprung aus ISR (RETI) (Interrupts werden wieder aktiviert)

von Gastofatz (Gast)


Lesenswert?

>> und in den Konstantenarrays ACSR_DATA[6] und ADMUX_DATA[6] die Daten
>> reinschreiben - fertig.

>Welche Geschwindigkeitssteigerung würde das bringen?

Es steigert eher die Geschwindgkeit, mit der Du Dein Projekt 
fertigstellst, weil man kompakten Code leichter überblickt und versteht. 
Die dadurch gesparte Zeit kannst Du z. B. zum Assemblerlernen nutzen, 
anschließend damit die Timer-ISR handoptimieren und dann wird die Sache 
perfekt :-)

>Das soll nur dazu da sein, dass ich entweder 0 oder 1 in der var
>variable habe, denn wenn ich jetzte 9:10 habe möchte ich gerne 9 Teile
>lang PBvals[] haben und 1 Teil PBvalc[]
>weißt du wie ich mein

Äh... ehrlich gesagt: So ganz noch nicht.

>Assembler scheint mir ein wenig seeeehr kompliziert zu sein.

Der Code mag wirr und abschreckend aussehen, aber wenn Du Dich in 
kleinen Schritten damit vertraut machst, wirst Du feststellen, dass es 
gar nicht so wild ist. Was Route_66 im vorletzten Satz schreibt, kann 
ich übrigens bestens nachempfinden.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

1
for(i=0;i<3000-10*r;i++)
2
        asm("nop");
NOP-Schleifen finde ich immer irgendwie unelegant. Auch weiß ich nicht, 
ob der Compiler die Schleife nicht einfach wegoptimiert.

von B. L. (Gast)


Lesenswert?

Nops werden nicht wegoptimiert, das hat auch absolut nichts mit den 
besprochenen Problem zu tun.

Hauke:

Das Problem ist, der Comparator Interrupt ist sehr wichtig, da die Gegen 
EMK vom Motor einen Comparator Interrupt auslöst, und falls der nicht 
auslöst, kann es sein, das der Motor stoppt, und dabei kurzschlusstrom 
zieht.

Das ist das hauptsächliche Problem, denn irgendwie habe ich das gefühlt, 
dass der Comparator Interrupt nicht richtig ausgeführt wird, da er ja 
öfters von den Timern unterbrochen wird!

MfG

von Peter D. (peda)


Lesenswert?

Nur mal so als Tip:

Wenn man die Forenregeln lesen würde, würden sich auch mal mehr Leute 
den Code anschauen.
Ich verbrenne mir jedenfalls nicht den Finger beim Scrollen.
Was ist denn so schwer daran, nen Anhang zu senden?


Peter

von Werner B. (werner-b)


Lesenswert?

Kleiner Hinweis zu
1
#include <avr\interrupt.h>
Siehe Diskussion in
Beitrag "Header Dateien Groß/Kleinschreibung"
Darin geht es auch um die Verwendung von "\" beim Include.

von B. L. (Gast)


Lesenswert?

Also das ganze soll ja mal ungefähr sowas werden:
http://www.mikrokopter.de/ucwiki/BrushlessCtrl
http://mikrocontroller.cco-ev.de/mikrosvn/BL-Ctrl/
Er hat auch die Software zur verfügung gestellt, aber die Blicke ich 
nicht durch mit den paar hundert Zeilen nur für PWM

Am einfachsten wäre es doch wenn man einen Hardware PWM hätte und die 6 
Ausgänge die ich benutze mit dieser Hardware PWM zu verunden oder?

Es geht einfach darum, dass so wie hier das Programm jetzt arbeitet, der 
Kommutierungszeitpunkt für den Motor nicht mehr exakt past, da der Timer 
Interrupt den Komparatorinterrupt "unterbricht".

So wie ich das sehe, wurde in dem Mikrokopter Projekt die Hardware PWM 
Pins verwendet, aber nur für 3 Kanäle richtig?

Hieße das mit einem AT90PWM2 oder wie die alle heißen, könnte ich alle 6 
Kanäle per HardwarePWM so verwenden wie ich es bräuchte. Oder ist das 
absoluter schwachsinn und es würde überhaupt nicht funktionieren?

MfG

von B. L. (Gast)


Lesenswert?

Ich bin draufgekommen, dass es keinen Sinn hat das mit Software PWM zu 
machen, also bleibt mir nur HardwarePWM übrig.
Aber ich habe ein neues Problem, kann vielleicht jemand kurz 
drüberschauen:

Funktionierende ( unelegante ) Methode:
1
#include <avr/io.h>
2
 
3
#define phaseASet   PORTD |= (1 << PD0);\
4
          PORTD |= (1 << PD1);
5
            //Am=0 Ap=1
6
#define phaseAClr   PORTD &= ~(1 << PD1);\
7
          PORTD &= ~(1 << PD0);
8
          //Ap=0 Am=1
9
#define phaseATri   PORTD |= (1 << PD0);\
10
          PORTD &= ~(1 << PD1);
11
          //Am=0 Ap=0
12
#define phaseBSet   PORTD |= (1 << PD2);\
13
          PORTD |= (1 << PD3);
14
          //Bm=0 Bp=1
15
#define phaseBClr   PORTD &= ~(1 << PD3);\
16
          PORTD &= ~(1 << PD2);
17
            //Bp=0 Bm=1
18
#define phaseBTri   PORTD |= (1 << PD2);\
19
          PORTD &= ~(1 << PD3);
20
          //Bm=0 Bp=0
21
#define phaseCSet   PORTD |= (1 << PD4);\
22
          PORTD |= (1 << PD5); 
23
          //Cm=0 Cp=1
24
#define phaseCClr   PORTD &= ~(1 << PD5);\
25
          PORTD &= ~(1 << PD4);
26
          //Cp=0 Cm=1
27
#define phaseCTri   PORTD |= (1 << PD4);\
28
          PORTD &= ~(1 << PD5);
29
          //Cm=0 Cp=0
30
31
void MotorStep(unsigned char);
32
33
34
int main()
35
{   DDRD = 0x3F; 
36
    SFIOR|=(1<<ACME); //multiplexer aktiv  
37
    ACSR = 0x00 ; // komparator aktivieren 
38
  
39
 while(1)
40
 {  MotorStep(1);
41
    ADMUX=5;
42
  while(bit_is_set(ACSR, ACO))
43
  {}
44
  
45
  MotorStep(2);
46
    ADMUX=1;
47
  while(bit_is_clear(ACSR, ACO))
48
  {}
49
50
  MotorStep(3);
51
    ADMUX=0;
52
  while(bit_is_set(ACSR, ACO))
53
  {}
54
55
  MotorStep(4);
56
  ADMUX=5;
57
  while(bit_is_clear(ACSR, ACO))
58
  {}
59
    
60
  MotorStep(5);
61
  ADMUX=1;
62
  while(bit_is_set(ACSR, ACO))
63
  {}
64
65
  MotorStep(6);
66
    ADMUX=0;
67
  while(bit_is_clear(ACSR, ACO))
68
  {}
69
  
70
  }
71
72
73
}
74
75
76
void MotorStep(unsigned char Stufe)
77
{  
78
  switch(Stufe)
79
    { case 1:   phaseAClr;
80
        phaseBSet;
81
        phaseCTri;
82
        break;
83
    case 2:   phaseAClr;
84
        phaseBTri;
85
        phaseCSet;
86
        break;
87
    case 3:   phaseATri;
88
        phaseBClr;
89
        phaseCSet;
90
        break;
91
    case 4:   phaseASet;
92
        phaseBClr;
93
        phaseCTri;
94
        break;
95
    case 5:   phaseASet;
96
        phaseBTri;
97
        phaseCClr;
98
        break;
99
    case 6:   phaseATri;
100
        phaseBSet;
101
        phaseCClr;
102
        break;
103
   }
104
}
Nicht Funktionierende ( elegante ) Methode:
1
#include <avr/io.h>
2
#include <avr\interrupt.h>  
3
4
5
#define phaseASet   PORTD |= (1 << PD0);\
6
          PORTD |= (1 << PD1);
7
            //Am=0 Ap=1
8
#define phaseAClr   PORTD &= ~(1 << PD1);\
9
          PORTD &= ~(1 << PD0);
10
          //Ap=0 Am=1
11
#define phaseATri   PORTD |= (1 << PD0);\
12
          PORTD &= ~(1 << PD1);
13
          //Am=0 Ap=0
14
#define phaseBSet   PORTD |= (1 << PD2);\
15
          PORTD |= (1 << PD3);
16
          //Bm=0 Bp=1
17
#define phaseBClr   PORTD &= ~(1 << PD3);\
18
          PORTD &= ~(1 << PD2);
19
            //Bp=0 Bm=1
20
#define phaseBTri   PORTD |= (1 << PD2);\
21
          PORTD &= ~(1 << PD3);
22
          //Bm=0 Bp=0
23
#define phaseCSet   PORTD |= (1 << PD4);\
24
          PORTD |= (1 << PD5); 
25
          //Cm=0 Cp=1
26
#define phaseCClr   PORTD &= ~(1 << PD5);\
27
          PORTD &= ~(1 << PD4);
28
          //Cp=0 Cm=1
29
#define phaseCTri   PORTD |= (1 << PD4);\
30
          PORTD &= ~(1 << PD5);
31
          //Cm=0 Cp=0
32
33
34
void MotorStep(uint8_t);
35
uint8_t zahl=0;
36
37
ISR(ANA_COMP_vect) 
38
39
{  
40
41
   switch(zahl)
42
43
   {  case 0: ACSR = 0b00001010; //fallende flanke
44
            MotorStep(1);
45
            ADMUX=5; //phase C rückkopplung
46
            break;
47
      case 1: ACSR = 0b00001011; //steigende flanke
48
              MotorStep(2);
49
            ADMUX=1; //phase B rückkopplung
50
              break;
51
      case 2: ACSR = 0b00001010; //fallende flanke
52
              MotorStep(3);
53
               ADMUX=0; //phase A rückkopplung
54
               break;
55
      case 3: ACSR = 0b00001011; //steigende flanke
56
              MotorStep(4);
57
             ADMUX=5; //phase C rückkopplung
58
            break;
59
      case 4: ACSR = 0b00001010; //fallende flanke
60
              MotorStep(5);
61
             ADMUX=1; //phase B rückkopplung
62
            break;
63
      case 5: ACSR = 0b00001011; //steigende flanke
64
              MotorStep(6);
65
               ADMUX=ß; //phase A rückkopplung
66
            break;
67
   }
68
69
   zahl++;
70
   if(zahl==6)
71
   zahl=0;
72
73
}
74
75
int main()
76
{     
77
    DDRD  = 0x3F; //Port D0 - D5 als Eingang
78
    SFIOR|=(1<<ACME); //multiplexer aktiv
79
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
80
    ADMUX=0; //phase A rückkopplung
81
   
82
    sei();
83
    while(1)
84
    {  
85
    }
86
}
87
88
89
void MotorStep(uint8_t Stufe)
90
{  
91
  switch(Stufe)
92
    { case 1:   phaseAClr;
93
        phaseBSet;
94
        phaseCTri;
95
        break;
96
    case 2:   phaseAClr;
97
        phaseBTri;
98
        phaseCSet;
99
        break;
100
    case 3:   phaseATri;
101
        phaseBClr;
102
        phaseCSet;
103
        break;
104
    case 4:   phaseASet;
105
        phaseBClr;
106
        phaseCTri;
107
        break;
108
    case 5:   phaseASet;
109
        phaseBTri;
110
        phaseCClr;
111
        break;
112
    case 6:   phaseATri;
113
        phaseBSet;
114
        phaseCClr;
115
        break;
116
   }
117
}
Kann mir jemand sagen was daran anders ist?
Ich sitze seit knapp 10 Stunden dran, und komm auf den Fehler nicht 
drauf!

MfG

von B. L. (Gast)


Lesenswert?

1
 case 5: ACSR = 0b00001011; //steigende flanke
2
              MotorStep(6);
3
               ADMUX=ß; //phase A rückkopplung
4
            break;
Sorry das sollte ADMUX=0 heißen!

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.