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


von iGast (Gast)


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?

1
#include <avr/io.h>
2
#ifndef F_CPU
3
/* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert 
4
   (z.&nbsp;B. durch Übergabe als Parameter zum Compiler innerhalb 
5
   des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
6
   "nachträgliche" Definition hinweist */
7
//#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
8
#define F_CPU 8000000UL     /* Quarz mit 8.000 Mhz */
9
#endif
10
11
12
#include <avr/sleep.h>
13
#include <avr/interrupt.h>
14
#include <util/delay.h>
15
16
17
//////////Variablen//////////////
18
int modus; 
19
int off=0;
20
21
22
23
//////////////////Interrupt Service Routine///////////////////
24
ISR(INT0_vect)
25
{
26
  off=0;
27
  modus++;
28
  while ( !(PINB & (1<<PINB6)))
29
  {
30
    
31
    /////////////Kann ich von hier aus Springen und das IFlag manuell löschen?
32
    while (off<1000)
33
    {
34
      _delay_ms(1);
35
      off++;
36
    }    
37
  }
38
}
39
40
41
42
43
44
///////////LED Ansteuerung///////////////
45
void Reihe1(void)
46
{
47
  PORTA=0x96;
48
}
49
void Reihe2(void)
50
{
51
  PORTA=0xa6;
52
}
53
void Reihe3(void)
54
{
55
  PORTA=0xc6;
56
}
57
58
void LEDoff(void)
59
{
60
  PORTA=0x87;
61
}
62
void LEDallON(void)
63
{
64
  PORTA=0xf7;
65
}
66
67
///////////////Pausenzeit /////////////////////////
68
void pause ( uint8_t ms )
69
{
70
  if (off=1000)
71
  {
72
    modus=0;
73
    //////Springe von hier an die Stelle Marke in der Main
74
  }
75
  for(; ms > 0; ms--) _delay_ms(1);
76
}
77
78
79
80
81
82
83
int main(void)
84
{
85
  ///IO Konfiguartion
86
  DDRA=0xf7;
87
  DDRB=0x00;
88
  
89
  
90
  
91
  while(1)
92
  {
93
    ///Marke: Sprung aus dem Unterprogramm
94
    
95
    if (modus==0)
96
    {
97
      off=0;
98
      LEDoff();
99
    }
100
    if (modus==1)
101
    {
102
      LEDallON();
103
      pause(10);
104
      LEDoff();
105
      pause(10);
106
    }
107
    if (modus==2);
108
    {
109
      Reihe1();
110
      pause(10);
111
      Reihe2();
112
      pause(10);
113
      Reihe3();
114
      pause(10);
115
    }
116
    if (modus==3)
117
    {
118
      modus=0;
119
    }
120
  }
121
  return 0;
122
  
123
}

von Georg G. (df2au)


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)


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)


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)


Lesenswert?

Wie löst man sowas sauber?

von Rufus Τ. F. (rufus) Benutzerseite


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)


Lesenswert?

Okay, gibt es dazu ein gutes Tutorial über Zustandsautomaten?

von W.S. (Gast)


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)


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.

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.