Forum: Mikrocontroller und Digitale Elektronik Sprung aus Unterprogramm an eine bestimmte Stelle in der Main


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von iGast (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

bin noch kein Programmierprofi und habe folgendes Problem. Ich möchte 
das nach dem längeren Drücken der Taste des Interrupts (idealerweise 1s) 
das Programm in den Modus 0 springt.
Kann ich direkt aus der Interrupt Routine irgendwie an die "Marke" 
springen kann, oder ist der Weg über pause(); der richtigere Weg? Oder 
ist mein Ansatz komplett falsch?

#include <avr/io.h>
#ifndef F_CPU
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert 
   (z.&nbsp;B. durch Übergabe als Parameter zum Compiler innerhalb 
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
   "nachträgliche" Definition hinweist */
//#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
#define F_CPU 8000000UL     /* Quarz mit 8.000 Mhz */
#endif


#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <util/delay.h>


//////////Variablen//////////////
int modus; 
int off=0;



//////////////////Interrupt Service Routine///////////////////
ISR(INT0_vect)
{
  off=0;
  modus++;
  while ( !(PINB & (1<<PINB6)))
  {
    
    /////////////Kann ich von hier aus Springen und das IFlag manuell löschen?
    while (off<1000)
    {
      _delay_ms(1);
      off++;
    }    
  }
}





///////////LED Ansteuerung///////////////
void Reihe1(void)
{
  PORTA=0x96;
}
void Reihe2(void)
{
  PORTA=0xa6;
}
void Reihe3(void)
{
  PORTA=0xc6;
}

void LEDoff(void)
{
  PORTA=0x87;
}
void LEDallON(void)
{
  PORTA=0xf7;
}

///////////////Pausenzeit /////////////////////////
void pause ( uint8_t ms )
{
  if (off=1000)
  {
    modus=0;
    //////Springe von hier an die Stelle Marke in der Main
  }
  for(; ms > 0; ms--) _delay_ms(1);
}






int main(void)
{
  ///IO Konfiguartion
  DDRA=0xf7;
  DDRB=0x00;
  
  
  
  while(1)
  {
    ///Marke: Sprung aus dem Unterprogramm
    
    if (modus==0)
    {
      off=0;
      LEDoff();
    }
    if (modus==1)
    {
      LEDallON();
      pause(10);
      LEDoff();
      pause(10);
    }
    if (modus==2);
    {
      Reihe1();
      pause(10);
      Reihe2();
      pause(10);
      Reihe3();
      pause(10);
    }
    if (modus==3)
    {
      modus=0;
    }
  }
  return 0;
  
}


von Georg G. (df2au)


Bewertung
0 lesenswert
nicht lesenswert
Du kannst von überall aus springen, an beliebige Ziele. Es ist aber 
nicht sinnvoll. Und die Randeffekte sind auch nicht ohne. Lass es 
lieber.

von iGast (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Deshalb wollte ich aus der Pause in die Main springen, da ist der 
Interrupt sicher abgehandelt. Habe schon mit Goto versucht, aber das 
kann ja nicht gehen. Aber wie realisiert man einen sauberen Rücksprung? 
Ich denke, diese Problem tritt häufiger auf oder?

von rmu (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Also üblicherweise springt man in C-Programmen nicht wild über 
Funktionsgrenzen herum, das ist so in der Sprache auch nicht vorgesehen. 
Gehen tuts natürlich (setjmp/longjmp oder Interventionen in Assembler), 
aber man will das nicht.

Jede Art von delay in einer ISR ist ausserdem böse.

von iGast (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wie löst man sowas sauber?

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
iGast schrieb:
> Aber wie realisiert man einen sauberen Rücksprung?

Gar nicht. Solche Probleme löst man mit Zustandsautomaten, was aber eine 
etwas andere Herangehensweise an das Problem erfordert.

von iGast (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Okay, gibt es dazu ein gutes Tutorial über Zustandsautomaten?

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
iGast schrieb:
> Deshalb wollte ich aus der Pause in die Main springen, da...

Du bist gerade dabei, das Schlimmstmögliche veranstalten zu wollen.

Mein Rat:

1. denke zu allererst mal gründlich über eine vernünftige 
Programmstruktur nach

2. halte Interruptroutinen KURZ. Nee, nicht 'klein' im Sinne von 
möglichst wenigen Buchstaben, sondern kurz, also möglichst garkeine Zeit 
beanspruchend. Also definitiv KEINE Trampelschleifen im Interrupt.

3. realisiere Zeiten mit Countern/Timern und nicht mit dem Aufruf von 
AufDerStelleTret-Funktionen.

4. schreibe main() möglichst ohne ein return 0 oder so, denn erstens 
sollte bei einem µC main wohl niemals zurückkehren (oder nur dann, wenn 
man ein RTOS o,ä. hat) und zweitens führt sowas leicht zu Verwirrungen. 
Falls dein Compiler einen fehlenden Return moniert, dann versuch's mit 
void main - sofern der Compiler das nicht auch bemeckert (was ich stark 
befürchte) oder benutze alternativ einfach goto. Bei einem Goto dirkt 
vor der Endklammer meckert m.W. KEIN EINZIGER Compiler.

W.S.

von Bitflüsterer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ein ganz guter Anfang ist hier: 
http://www.mikrocontroller.net/articles/Statemachine beschrieben. Mit 
Beispielen.

Auf Dein Problem bezogen, lohnt sich vielleicht auch eine Beschäftigung 
mit Peter Danneggers Entprellcode hier im Forum.

Allerdings ist das, besonders wenn man ganz allgemein noch wenig 
programmiert hat (ich weiß nicht, ob und inwiefern das Dich zutrifft), 
recht harter Stoff. Ein paar Tage mit intensivem Experimentieren werden 
da schon nötig sein.

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.