www.mikrocontroller.net

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


Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Sascha (Gast)
Datum:

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

Autor: Gaast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> "abhilfe":

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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interruptflag sollte Abfragbar sein.

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

MfG

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Uwe ... (uwegw)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Siehe Interrupt

Autor: Juergen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> der Timer 1 Interrupt wird ca. alle 25µs aufgerufen

> Im Timer Interrupt ist es etwas Umfangreicher

Deine Interrupt-Routinen sind zu groß.

Autor: Sauger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin,

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

MfG

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also momentan ist in meinem Timer Interrupt ja nur der Toggle des 
Ausgangspins, also liegts hauptsächlich an dem Komparatorinterrupt der 
so aussieht:
char zahl=0;

ISR(ANA_COMP_vect) 

{

   switch(zahl)

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

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

}

Also wird in dem Interrupt noch die Funktion "Motorstep()" aufgerufen 
die wiefolgt aussieht:
void MotorStep(unsigned char Stufe)
{  
    switch(Stufe)
    { 
    case 1:    phaseAClr;
         phaseBSet;
         phaseCTri;
         break;

    case 2:    phaseAClr;
         phaseBTri;
         phaseCSet;
         break;

    case 3:    phaseATri;
         phaseBClr;
         phaseCSet;
         break;

    case 4:    phaseASet;
         phaseBClr;
         phaseCTri;
         break;

    case 5:    phaseASet;
         phaseBTri;
         phaseCClr;
         break;

    case 6:    phaseATri;
               phaseBSet;
         phaseCClr;
         break;
    }
}

Die Funtion ruft nun wiederum defines auf:
#define phaseASet   PORTD |= (1 << PD0);\
        PORTD |= (1 << PD1);
#define phaseAClr   PORTD &= ~(1 << PD1);\
        PORTD &= ~(1 << PD0);
#define phaseATri   PORTD |= (1 << PD0);\
        PORTD &= ~(1 << PD1);
#define phaseBSet   PORTD |= (1 << PD2);\
        PORTD |= (1 << PD3);
#define phaseBClr   PORTD &= ~(1 << PD3);\
            PORTD &= ~(1 << PD2);
#define phaseBTri   PORTD |= (1 << PD2);\
           PORTD &= ~(1 << PD3);
#define phaseCSet   PORTD |= (1 << PD4);\
        PORTD |= (1 << PD5); 
#define phaseCClr   PORTD &= ~(1 << PD5);\
        PORTD &= ~(1 << PD4);
#define phaseCTri   PORTD |= (1 << PD4);\
        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

Autor: B. L. (Gast)
Datum:

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

Autor: Flo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!
> Die Funtion ruft nun wiederum defines auf:

Defines fressen keine Zeit, sondern erleichtern die Lesbarkeit.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
char Stufe=0;

ISR (TIMER1_COMPA_vect)
{ var=~var;
  if(var)
  {   
  switch(Stufe)
    { 
    case 1:phaseAClr;
         phaseBSet;
         phaseCTri;
         break;
    case 2:phaseAClr;
         phaseBTri;
         phaseCSet;
         break;
    case 3:phaseATri;
         phaseBClr;
         phaseCSet;
         break;
    case 4:phaseASet;
         phaseBClr;
         phaseCTri;
         break;
    case 5:phaseASet;
         phaseBTri;
         phaseCClr;
         break;
    case 6:phaseATri;
           phaseBSet;
         phaseCClr;
         break;
    }
}
else
{   
  switch(Stufe)
    { 
    case 1:phaseASet;
         phaseBClr;
         phaseCTri;
         break;
    case 2:phaseASet;
         phaseBTri;
         phaseCClr;
         break;
    case 3:phaseATri;
         phaseBSet;
         phaseCClr;
         break;
    case 4:phaseAClr;
         phaseBSet;
         phaseCTri;
         break;
    case 5:phaseAClr;
         phaseBTri;
         phaseCSet;
         break;
    case 6:phaseATri;
           phaseBClr;
         phaseCSet;
         break;
    }
}

}
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;

}



Autor: j=sqrt(-1) (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: j=sqrt(-1) (Gast)
Datum:

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

Autor: B. L. (Gast)
Datum:

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

MfG

Autor: Hauke Sattler (hauke)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So hier der Gesamte Code, ich hoffe es ist einigermaßen Übersichtlich 
Kommentiert!
#include <avr/io.h>
#include <avr\interrupt.h>  


#define phaseASet   PORTD |= (1 << PD0);\
          PORTD |= (1 << PD1);
            //Am=0 Ap=1
#define phaseAClr   PORTD &= ~(1 << PD1);\
          PORTD &= ~(1 << PD0);
          //Ap=0 Am=1
#define phaseATri   PORTD |= (1 << PD0);\
          PORTD &= ~(1 << PD1);
          //Am=0 Ap=0
#define phaseBSet   PORTD |= (1 << PD2);\
          PORTD |= (1 << PD3);
          //Bm=0 Bp=1
#define phaseBClr   PORTD &= ~(1 << PD3);\
          PORTD &= ~(1 << PD2);
            //Bp=0 Bm=1
#define phaseBTri   PORTD |= (1 << PD2);\
          PORTD &= ~(1 << PD3);
          //Bm=0 Bp=0
#define phaseCSet   PORTD |= (1 << PD4);\
          PORTD |= (1 << PD5); 
          //Cm=0 Cp=1
#define phaseCClr   PORTD &= ~(1 << PD5);\
          PORTD &= ~(1 << PD4);
          //Cp=0 Cm=1
#define phaseCTri   PORTD |= (1 << PD4);\
          PORTD &= ~(1 << PD5);
          //Cm=0 Cp=0

void MotorStep(unsigned char);
void Hochfahren(void);


char zahl=0;
char Stufe=0;
char var=0;


ISR (TIMER1_COMPA_vect)
{ var=~var;
  if(var)
  {  switch(Stufe)
     { 
      case 1:phaseAClr;
            phaseBSet;
           phaseCTri;
           break;
      case 2:phaseAClr;
           phaseBTri;
           phaseCSet;
           break;
      case 3:phaseATri;
           phaseBClr;
           phaseCSet;
           break;
      case 4:phaseASet;
           phaseBClr;
           phaseCTri;
           break;
      case 5:phaseASet;
           phaseBTri;
           phaseCClr;
           break;
      case 6:phaseATri;
               phaseBSet;
           phaseCClr;
           break;
      } 
   }

   else
   {  switch(Stufe)
     { 
       case 1:phaseASet;
            phaseBClr;
            phaseCTri;
            break;
       case 2:phaseASet;
            phaseBTri;
            phaseCClr;
            break;
       case 3:phaseATri;
            phaseBSet;
            phaseCClr;
             break;
       case 4:phaseAClr;
            phaseBSet;
            phaseCTri;
            break;
       case 5:phaseAClr;
            phaseBTri;
            phaseCSet;
            break;
       case 6:phaseATri;
                 phaseBClr;
            phaseCSet;
            break;
     }
   }

}
 
void Timer_io_init(void)
{
  
  TCCR1A |= (1 << WGM11) | (0 << WGM10);
  TCCR1B |= (1 << WGM13) | (0 << WGM12); // phase correct mit ICR1 als TOP
 
 
  TCCR1B |= (0 << CS12)  | (0 << CS11)  | (1 << CS10); //CK

  ICR1=255; //TOP Wert
 
  OCR1A = 127; //Comparewert
 
  TIMSK = (1 << OCIE1A);
}
 



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;

}





int main()
{   Timer_io_init();

    DDRD  = 0x3F; //Port D0 - D5 als Eingang

    SFIOR|=(1<<ACME); //Multiplexer aktiv
    
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
    ADMUX=1; //phase A rückkopplung
    
    
  Hochfahren();

    sei();

    while(1)
    {  
    }


}

void MotorStep(unsigned char Stufen)
{  
    switch(Stufen)
    { 
    case 1:phaseAClr;
         phaseBSet;
         phaseCTri;
         break;
    case 2:phaseAClr;
         phaseBTri;
         phaseCSet;
         break;
    case 3:phaseATri;
         phaseBClr;
         phaseCSet;
         break;
    case 4:phaseASet;
         phaseBClr;
         phaseCTri;
         break;
    case 5:phaseASet;
         phaseBTri;
         phaseCClr;
         break;
    case 6:phaseATri;
           phaseBSet;
         phaseCClr;
         break;
    }
}

void Hochfahren(void)
{   int i=0;
  for(int r=0;r<200;r++)
    {
       MotorStep(1);
       for(i=0;i<3000-10*r;i++)
        asm("nop");
  
     MotorStep(2);
   
     for(i=0;i<3000-10*r;i++)
     asm("nop");

     MotorStep(3);
     for(i=0;i<3000-10*r;i++)
     asm("nop");
  

     MotorStep(4);
   
     for(i=0;i<3000-10*r;i++)
     asm("nop");

     MotorStep(5);
   
     for(i=0;i<3000-10*r;i++)  
     asm("nop");

     MotorStep(6);
   
     for(i=0;i<3000-10*r;i++)
     asm("nop");

   }
}

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gastofatz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde als erstes diese CASE-Konstruktion rauswerfen und das über ein 
banales Konstantenarray machen:
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.

Autor: j=sqrt(-1) (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: j=sqrt(-1) (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>
#include <avr\interrupt.h>  

void Hochfahren(void);
void Timer_io_init(void);

char zahl=0;
uint8_t Stufe=0;
char var=0;
const uint8_t PBvals[6]={0b00011100,
             0b00110100,
             0b00110001,
             0b00010011,
             0b00000111,
             0b00001101
              };

const uint8_t PBvalc[6]={0b00010011,
             0b00000111,
             0b00001101,
             0b00011100,
             0b00110100,
             0b00110001
              };

ISR (TIMER1_COMPA_vect)
{ var=~var;
  if(var)
  PORTB=PBvals[Stufe];
  else
  PORTB=PBvalc[Stufe];
}

ISR(ANA_COMP_vect) 

{  sei();

   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;
      case 2: ACSR = 0b00001010; //fallende flanke
              Stufe=2;
               ADMUX=1;           //phase A rückkopplung
               break;
      case 3: ACSR = 0b00001011; //steigende flanke
              Stufe=3;
             ADMUX=5;           //phase C rückkopplung
            break;
      case 4: ACSR = 0b00001010; //fallende flanke
              Stufe=4;
             ADMUX=0;           //phase B rückkopplung
            break;
      case 5: ACSR = 0b00001011; //steigende flanke
              Stufe=5;
               ADMUX=1;           //phase A rückkopplung
            break;
   }

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

}





int main()
{   Timer_io_init();

    DDRB  = 0x3F; //Port D0 - D5 als Eingang

    SFIOR|=(1<<ACME); //Multiplexer aktiv
    
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
    ADMUX=1; //phase A rückkopplung
    
    
  Hochfahren();

    sei();

    while(1)
    {  
    }


}

void Timer_io_init(void)
{
  
  TCCR1A |= (1 << WGM11) | (0 << WGM10);
  TCCR1B |= (1 << WGM13) | (0 << WGM12); // phase correct mit ICR1 als TOP
  TCCR1B |= (0 << CS12)  | (0 << CS11)  | (1 << CS10); //CK

  ICR1=500; //TOP Wert
 
  OCR1A = 400; //Comparewert
 
  TIMSK = (1 << OCIE1A);
}
 
void Hochfahren(void)
{   int i=0;
  for(int r=0;r<200;r++)
    {
       PORTB=PBvals[0];
       for(i=0;i<3000-10*r;i++)
        asm("nop");
  
     PORTB=PBvals[1];
     for(i=0;i<3000-10*r;i++)
     asm("nop");

     PORTB=PBvals[2];
     for(i=0;i<3000-10*r;i++)
     asm("nop");
  
       PORTB=PBvals[3];
     for(i=0;i<3000-10*r;i++)
     asm("nop");

     PORTB=PBvals[4];
     for(i=0;i<3000-10*r;i++)  
     asm("nop");

     PORTB=PBvals[5];
     for(i=0;i<3000-10*r;i++)
     asm("nop");

   }
}



MfG

Autor: Gastofatz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
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.

>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):
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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>
#include <avr\interrupt.h>  

void Hochfahren(void);
void Timer_io_init(void);

char zahl=0;
uint8_t Stufe=0;
char var=0;
const uint8_t PBvals[6]={0b00011100,
             0b00110100,
             0b00110001,
             0b00010011,
             0b00000111,
             0b00001101
              };

const uint8_t PBvalc[6]={0b00011101,
             0b00110101,
             0b00110101,
             0b00010111,
             0b00010111,
             0b00011101
              };
const uint8_t ACSR_DATA[6]={0b00001010,
                0b00001011,
                0b00001010,
                0b00001011,
                0b00001010,
                0b00001011
                 };
const uint8_t ADMUX_DATA[6]={0b00000101,
                 0b00000000,
                 0b00000001,
                 0b00000101,
                 0b00000000,
                 0b00000001
                  };

ISR (TIMER1_COMPA_vect)
{ var=~var;
  if(var)
  PORTB=PBvals[Stufe];
  else
  PORTB=PBvalc[Stufe];
}

ISR(ANA_COMP_vect) 

{  sei();
   Stufe = zahl;
   ACSR  = ACSR_DATA[Stufe];
   ADMUX = ADMUX_DATA[Stufe];
   
   zahl++;
   if(zahl==6)
   zahl=0;

}





int main()
{   Timer_io_init();

    DDRB  = 0x3F; //Port B0 - B5 als Eingang

    SFIOR|=(1<<ACME); //Multiplexer aktiv
    
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
    ADMUX=1; //phase A rückkopplung
    
    
  Hochfahren();

    sei();

    while(1)
    {  
    }


}

void Timer_io_init(void)
{
  
  TCCR1A |= (1 << WGM11) | (0 << WGM10);
  TCCR1B |= (1 << WGM13) | (0 << WGM12); // phase correct mit ICR1 als TOP
  TCCR1B |= (0 << CS12)  | (0 << CS11)  | (1 << CS10); //CK

  ICR1=255; //TOP Wert
 
  OCR1A = 210; //Comparewert
 
  TIMSK = (1 << OCIE1A);
}
 
void Hochfahren(void)
{   int i=0;
  for(int r=0;r<200;r++)
    {
       PORTB=PBvals[0];
       for(i=0;i<3000-10*r;i++)
        asm("nop");
  
     PORTB=PBvals[1];
     for(i=0;i<3000-10*r;i++)
     asm("nop");

     PORTB=PBvals[2];
     for(i=0;i<3000-10*r;i++)
     asm("nop");
  
       PORTB=PBvals[3];
     for(i=0;i<3000-10*r;i++)
     asm("nop");

     PORTB=PBvals[4];
     for(i=0;i<3000-10*r;i++)  
     asm("nop");

     PORTB=PBvals[5];
     for(i=0;i<3000-10*r;i++)
     asm("nop");

   }
}



Autor: Hauke Sattler (hauke)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Gastofatz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Werner B. (werner-b)
Datum:

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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: B. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>
 
#define phaseASet   PORTD |= (1 << PD0);\
          PORTD |= (1 << PD1);
            //Am=0 Ap=1
#define phaseAClr   PORTD &= ~(1 << PD1);\
          PORTD &= ~(1 << PD0);
          //Ap=0 Am=1
#define phaseATri   PORTD |= (1 << PD0);\
          PORTD &= ~(1 << PD1);
          //Am=0 Ap=0
#define phaseBSet   PORTD |= (1 << PD2);\
          PORTD |= (1 << PD3);
          //Bm=0 Bp=1
#define phaseBClr   PORTD &= ~(1 << PD3);\
          PORTD &= ~(1 << PD2);
            //Bp=0 Bm=1
#define phaseBTri   PORTD |= (1 << PD2);\
          PORTD &= ~(1 << PD3);
          //Bm=0 Bp=0
#define phaseCSet   PORTD |= (1 << PD4);\
          PORTD |= (1 << PD5); 
          //Cm=0 Cp=1
#define phaseCClr   PORTD &= ~(1 << PD5);\
          PORTD &= ~(1 << PD4);
          //Cp=0 Cm=1
#define phaseCTri   PORTD |= (1 << PD4);\
          PORTD &= ~(1 << PD5);
          //Cm=0 Cp=0

void MotorStep(unsigned char);


int main()
{   DDRD = 0x3F; 
    SFIOR|=(1<<ACME); //multiplexer aktiv  
    ACSR = 0x00 ; // komparator aktivieren 
  
 while(1)
 {  MotorStep(1);
    ADMUX=5;
  while(bit_is_set(ACSR, ACO))
  {}
  
  MotorStep(2);
    ADMUX=1;
  while(bit_is_clear(ACSR, ACO))
  {}

  MotorStep(3);
    ADMUX=0;
  while(bit_is_set(ACSR, ACO))
  {}

  MotorStep(4);
  ADMUX=5;
  while(bit_is_clear(ACSR, ACO))
  {}
    
  MotorStep(5);
  ADMUX=1;
  while(bit_is_set(ACSR, ACO))
  {}

  MotorStep(6);
    ADMUX=0;
  while(bit_is_clear(ACSR, ACO))
  {}
  
  }


}


void MotorStep(unsigned char Stufe)
{  
  switch(Stufe)
    { case 1:   phaseAClr;
        phaseBSet;
        phaseCTri;
        break;
    case 2:   phaseAClr;
        phaseBTri;
        phaseCSet;
        break;
    case 3:   phaseATri;
        phaseBClr;
        phaseCSet;
        break;
    case 4:   phaseASet;
        phaseBClr;
        phaseCTri;
        break;
    case 5:   phaseASet;
        phaseBTri;
        phaseCClr;
        break;
    case 6:   phaseATri;
        phaseBSet;
        phaseCClr;
        break;
   }
}


Nicht Funktionierende ( elegante ) Methode:
#include <avr/io.h>
#include <avr\interrupt.h>  


#define phaseASet   PORTD |= (1 << PD0);\
          PORTD |= (1 << PD1);
            //Am=0 Ap=1
#define phaseAClr   PORTD &= ~(1 << PD1);\
          PORTD &= ~(1 << PD0);
          //Ap=0 Am=1
#define phaseATri   PORTD |= (1 << PD0);\
          PORTD &= ~(1 << PD1);
          //Am=0 Ap=0
#define phaseBSet   PORTD |= (1 << PD2);\
          PORTD |= (1 << PD3);
          //Bm=0 Bp=1
#define phaseBClr   PORTD &= ~(1 << PD3);\
          PORTD &= ~(1 << PD2);
            //Bp=0 Bm=1
#define phaseBTri   PORTD |= (1 << PD2);\
          PORTD &= ~(1 << PD3);
          //Bm=0 Bp=0
#define phaseCSet   PORTD |= (1 << PD4);\
          PORTD |= (1 << PD5); 
          //Cm=0 Cp=1
#define phaseCClr   PORTD &= ~(1 << PD5);\
          PORTD &= ~(1 << PD4);
          //Cp=0 Cm=1
#define phaseCTri   PORTD |= (1 << PD4);\
          PORTD &= ~(1 << PD5);
          //Cm=0 Cp=0


void MotorStep(uint8_t);
uint8_t zahl=0;

ISR(ANA_COMP_vect) 

{  

   switch(zahl)

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

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

}

int main()
{     
    DDRD  = 0x3F; //Port D0 - D5 als Eingang
    SFIOR|=(1<<ACME); //multiplexer aktiv
    ACSR = 0b00001011; // komparator aktivieren  mit steigender flanke und interrupt aktiviert
    ADMUX=0; //phase A rückkopplung
   
    sei();
    while(1)
    {  
    }
}


void MotorStep(uint8_t Stufe)
{  
  switch(Stufe)
    { case 1:   phaseAClr;
        phaseBSet;
        phaseCTri;
        break;
    case 2:   phaseAClr;
        phaseBTri;
        phaseCSet;
        break;
    case 3:   phaseATri;
        phaseBClr;
        phaseCSet;
        break;
    case 4:   phaseASet;
        phaseBClr;
        phaseCTri;
        break;
    case 5:   phaseASet;
        phaseBTri;
        phaseCClr;
        break;
    case 6:   phaseATri;
        phaseBSet;
        phaseCClr;
        break;
   }
}

Kann mir jemand sagen was daran anders ist?
Ich sitze seit knapp 10 Stunden dran, und komm auf den Fehler nicht 
drauf!

MfG

Autor: B. L. (Gast)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.