C Ausbruch aus Schleifen oder Funktionen verkürzen

fanatiXalpha

Fleet Admiral
Registriert
Aug. 2011
Beiträge
13.558
Ich programmiere gerade einen µC der ein paar Motoren steuern soll usw.
Dabei müssen immer wieder die Pins eingelesen werden um z.B. einen Notaus zu detektieren oder andere Zustände.
Und wenn jetzt ein Notaus detektiert wurde, dann soll er an dem Punkt wo er gerade ist ausbrechen und in einen sicheren Zustand gehen. Gibt natürlich auch andere Situationen, wo er sich ähnlich zum Notaus verhalten soll.
Also wenn Pin X High dann gehe in den Zustand X.
Hoffe es ist verständlich :D

Das Abfragen der Pins habe ich natürlich in eine Funktion verpackt die ich halt immer wieder aufrufe(n muss, da nicht alle Pins per ISR abgefragt werden können).

Um aber aus der Schleife oder Funktion auszubrechen in der ich mich momentan befinde löse ich das bisher mit einer if-Abfrage für gesetzte Flags und einem entsprechenden return- oder break-Befehl.
Ist jetzt nicht wirklich viel Code der dann dahinter steckt, aber ist etwas nervig den jedes mal wieder an die nötigen Stellen zu kopieren.

Dachte ich könnte das auch in eine Funktion packen, da müsste ich dann ja nur anfangen zu tippen, er schlägt es mir vor, Enter und das wars dann.
Nur glaube ich nicht, dass das funktioniert...
break funktioniert ja nur wenn er sich unmittelbar in einer Schleife befindet und return springt aus der aktuellen Funktion raus.
Wenn ich also die Funktion zum Ausbrechen in einer anderen Funktion Y aufrufe, dann bleibe ich ja in Y oder?

Kennt ihr Möglichkeiten für mein Anliegen, oder muss ich dabei bleiben, das immer wieder einzutippen?


Der Code sieht schematisch aktuell ungefähr so aus:
Code:
Funktion_AB()
{
   while(c == 1)
   {
       Pinabfrage();
       if(Flag_x == 1)
       {
          //mach irgendwas
          break;
       }

       [... anderer Code der hier unwichtig ist ...]
    }

    if(Flag_x == 1)
    {
       //setze andere Flags z.B. oder sonstwas
       return;
     }

    [... anderer Code der hier unwichtig ist aber im Falle Flag_x == 1 übersprungen bzw. nicht ausgeführt werden soll ...]
}
 
Du könntest dir mit #define entsprechende Makros definieren, die dir dann die Tipparbeit ersparen.
 
Moin,

also mit dem break kannst du nur aus der aktuellen Funktion raus, also das hast du schon richtig vermutet.

Ich würde das ganze jedoch etwas anders Programmieren:

Code:
If (Pinabfrage() = 0) then
{

dein ganzer code der ausgeführt werden soll ohne dass der Knopf gerückt ist 
}

else 
{
was passiert sonst 
}
end if

Syntax fehler bitte einfach ignorieren, bin gerade mehr mit VBA zugange ;)

So hätte das ganze eben den Charm, dass du nicht mit breaks und Flags arbeiten musst (versuche ich immer zu vermeiden, zumindest bei breaks).

Grüße,
Nico

Edit: Dein neuer Comment klingt so als wärst du relativ neu mit Mikrocontrollern? Kann das sein?
 
Ist nicht so, als würde ich das seit 20 Jahren machen ;)
Ich studiere und mach grad ne Studienarbeit.
Total neu ist es für mich also nicht, aber der Umfang ist grad aktuell größer als es bisher der Fall war und ich hatte nicht konstant immer mal wieder was mit C gemacht sondern mal gelernt und dann eher nicht mehr benutzt^^
 
Also wenn du deine Abfrage verkürzen willst, um dir Tipp arbeit zu ersparen eben wie gesagt mit nem Rückgabewert arbeiten

also

If (Pinabfrage == True) then
{
dosomething
break;
}

So hättest du nur 4 Zeilen und eben nicht mehr die Flagge, nur musst du eben bedenken, dass du eben nicht mehr auf den Wert von Pinabfrage zugreifen kannst, bzw. eben immer den aktuellen wert von Pinabfrage zurück bekommst, also 1 MS später kann der Pin ja schon einen anderen Wert haben und dann wunderst du dich wieso dein Programm nicht mehr funktioniert...
Andere Ideen hätte ich spontan auch nicht, wobei ich auch erst im Oktober fertig geworden bin :p
Evtl kannst ja auch irgendwie einen Break als rückgabewert nutzen, wobei ich das nicht glaube...
 
mein Problem ist halt, sobald ich den Zustand wechseln will, darf/sollte/muss sich da nix mehr bewegen
das heißt bei "Abbruch" muss trotzdem noch der Befehl kommen die Motoren zu stoppen
somit könnte ich das if mit dem break Befehl substituieren, aber das if mit return kann ich glaube ich nicht ersetzen
weil sonst würde er ja einfach weiter machen und nicht den Zustand wechseln

ich fand es halt "sichrer" das mit dem Abbruch direkt nach der Pinabfrage zu setzen und nicht als Bedingung für while oder if
 
Du kannst dir wenn du willst eine Funktion schreiben, die die Überprüfung beinhaltet und dieser dann eben Handles auf beliebige andere Funktionen mitgeben. Also sowas in der Art:
Code:
void Function_call(void (*function_periodic)(), void (*function_end)()){
       while(c == 1)
       {
           Pinabfrage();
           if(Flag_x == 1)
           {
              //mach irgendwas
              break;
           }
	   function_periodic();
	}
     
        if(Flag_x == 1)
        {
           //setze andere Flags z.B. oder sonstwas
           return;
        }
        function_end();
}
Und die dann über
Code:
Function_call(&testfunction1, &testfunction2);
aufrufen. Wobei testfunction1 und testfunction2 nun deine beiden Zeilen 12 bzw. 21 enthalten.
 
Hm, okay, ich glaube ich sehe was du meinst
ich frag mich nur, ob das tatsächlich meinen Schreibaufwand reduziert bzw. das Ganze hübscher gestaltet
weil das, das was ich bei 12. und 21. geschrieben habe bzw. schreiben würde wiederholt sich nicht
das was sich wiederholt sind die Flag-Abzweigungen für den Abbruch


EDIT:
ist ja nix geheimes, hab mal den Code in den Spoiler gepackt
gibt noch zwei weitere Automatic-Funktionen wo ich das kürzen würde wenn es geht
vllt. fallen euch ja noch andere Sachen auf die ich falsch, schlecht oder umständlich mache
Code:
void Automatic_Mode_Endschalter_anfahren()
{
	//Fahre Z-Achse bzw. Spule hoch
	while(Endschalter6 == 1)	//Induktivsensor fehlt noch da "defekt"
	{
		GIO_input_survey();
		set_zMotor_Rotation_CW();
			
		if(emergency_stop_pressed == 1 || State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
		{
			set_zMotor_stop();
			set_xmotor_Dis();
			set_ymotor_Dis();
			break;
		}
	}
	set_zMotor_stop();	
			
	if(emergency_stop_pressed == 1)
	{
		Manual_Mode_Flag = 1;
		Automatic_Mode_Flag = 0;
		return;
	}
			
	if(State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
	{
		Manual_Mode_Flag = 0;
		Automatic_Mode_Flag = 0;
		return;
	}
			
	//Fahre an Punkt (0|0)
	while(Endschalter2 == 1 || Endschalter4 == 1)
	{
		GIO_input_survey();
		if(emergency_stop_pressed == 1 || State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
		{
			set_zMotor_stop();
			set_xmotor_Dis();
			set_ymotor_Dis();
			break;
		}
								
		if(Endschalter2 == 1)
		{
			set_ymotor_Direction(false);
			set_ymotor_En();
		}
		else 
		{
			set_ymotor_Dis();
			set_ymotor_Direction(true);
		}
				
		if(Endschalter4 == 1)
		{
			set_xmotor_Direction(false);
			set_xmotor_En();
		}
		else
		{
			set_xmotor_Dis();
			set_xmotor_Direction(true);
		}
				
	}
			
	if(emergency_stop_pressed == 1)
 	{
 		Manual_Mode_Flag = 1;
 		Automatic_Mode_Flag = 0;
 		return;
 	}
	 
	if(State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
	{
		Manual_Mode_Flag = 0;
		Automatic_Mode_Flag = 0;
		return;
	}	 
			
	//Fahre an Punkt(0|100)
	while(Endschalter == 1)
	{
		GIO_input_survey();
		if(emergency_stop_pressed == 1 || State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
		{
			set_zMotor_stop();
			set_xmotor_Dis();
			set_ymotor_Dis();
			break;
		}
				
		if(Endschalter == 1)
		{
			set_ymotor_Direction(true);
			set_ymotor_En();
		}
		else
		{
			set_ymotor_Dis();
			set_ymotor_Direction(false);
		}
	}
			
	if(emergency_stop_pressed == 1)
 	{
 		Manual_Mode_Flag = 1;
 		Automatic_Mode_Flag = 0;
 		return;
 	}
	
	if(State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
	{
		Manual_Mode_Flag = 0;
		Automatic_Mode_Flag = 0;
		return;
	}
			 
	//An Punkt (100|100) fahren
	while(Endschalter3 == 1)
	{
		GIO_input_survey();
		if(emergency_stop_pressed == 1 || State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
		{
			set_zMotor_stop();
			set_xmotor_Dis();
			set_ymotor_Dis();
			break;
		}
				
		if(Endschalter3 == 1)
		{
			set_xmotor_Direction(true);
			set_xmotor_En();
		}
		else
		{
			set_xmotor_Dis();
			set_xmotor_Direction(false);
		}				
	}
			
	if(emergency_stop_pressed == 1)
	{
		Manual_Mode_Flag = 1;
		Automatic_Mode_Flag = 0;
		return;
	}
	
	if(State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
	{
		Manual_Mode_Flag = 0;
		Automatic_Mode_Flag = 0;
		return;
	}	
			
	//An Punkt (100|0) fahren
	while(Endschalter2 == 1)
	{
		GIO_input_survey();
		if(emergency_stop_pressed == 1 || State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
		{
			set_zMotor_stop();
			set_xmotor_Dis();
			set_ymotor_Dis();
			break;
		}
				
		if(Endschalter2 == 1)
		{
			set_ymotor_Direction(false);
			set_ymotor_En();
		}				
		else
		{
			set_ymotor_Dis();
			set_ymotor_Direction(true);
			
		}
	}
			
	if(emergency_stop_pressed == 1)
 	{
 		Manual_Mode_Flag = 1;
 		Automatic_Mode_Flag = 0;
 		return;
 	}	
	 
	if(State_LED_Charging == 1 || State_LED_Temperature_Exceeded == 1 || State_LED_PFC_Incorrect == 1)
	{
		Manual_Mode_Flag = 0;
		Automatic_Mode_Flag = 0;
		return;
	}				
}
 
Zuletzt bearbeitet:
Hab gerade leider keine Zeit, mir deinen Code anzuschauen.
Ob dir durch meinen Vorschlag soviel Schreibarbeit abgenommen wird, kann ich nicht sagen. Der Punkt ist halt, dass du diese Überprüfung auf dein Flag nur einmal schreibst und sie nachher mit vielen verschiedenen testfunctions nutzen kannst. Du hast also bspw 200 verschiedene Funktionen, vor die jeweils die Überprüfung auf das Flag hin muss und rufst die dann alle mit
Code:
funktionmitüberprüfungaufrufen(&eigentlichefunktion)
auf.
Vorteil ist vielleicht wengiger der verringerte Schreibaufwand sondern eher, dass Änderungen an der Flag-Überprüfungsroutine nur einmal an einer Stelle durchzuführen sind.
 
Keine Ahnung, ob das das Lernzeil ist aber sowas wie Notaus realisiert man nicht hin und wieder durch eine Abfrage die man dann ständig passieren lässt sondern durch einen Interrupt - oder hattet ihr die nie?
Ansonsten kannst du natürlich auch in deiner Mainloop eine Funktion aufrufen die sowas prüft wie
"bool wurdeNotausBetaetigt() { ... }" und bei true entsprechend alles stoppt.
Dein nächstes Problem bei externen (echt-Welt) Schaltern werden dann Debouncer
 
Oben hatte ich geschrieben:
Das Abfragen der Pins habe ich natürlich in eine Funktion verpackt die ich halt immer wieder aufrufe(n muss, da nicht alle Pins per ISR abgefragt werden können).
Insofern hab ich mir das gespart, weil ich hätte zweigleisig fahren müssen.
Zumindest bin ich der Meinung, das auf dem AT90CAN128 nur 7 Pins per Interrupt abfragbar sind. Den Notaus könnte man noch umlegen, aber für die Endschalter oder das Einlesen von anderen Eingängen geht es nicht mehr und reicht auch nicht aus.
Theoretisch könnte ich noch Timer-Interrupts nutzen...
Aber das spart mir ja nicht die komplette Schreibarbeit.
Es würde "nur" das Abfragen der Pins automatisch erfolgen.
Das Ausbrechen muss ich ja dann doch an die entsprechenden Stellen setzen.
Ist ja alles sequenziell, Multi-Threaded auf nem Pi wäre das was anderes.

@simpsonfan:
ich schau es mir morgen nochmal genauer an und überlegs mir
Mit Debounce meinst du wahrscheinlich Entprellen?
Die Schalter werden in Hardware entprellt.
Gibt natürlich von einigen/vielen die Auffassung es sollte in SW entprellt werden, aber jetzt is es erstmal so
 
Zuletzt bearbeitet:
Zurück
Oben