Hallo an Alle,
ich kämpfe hier mit meinem Halbwissen und ein paar Dingen die ich mir
gar nicht erklären kann.
Ich habe einen Schrittmotor, dieser wird über eine Kombination von L297
und L298 angesteuert. Dabei benötige ich vom µC nur drei Signale,
Enable, Drehrichtung und Clockimpuls.
Der Schrittmotor läuft. Alelrdings habe ich ein paar unerklärliche
Probleme bei der Portansteuerung für Enable und Drehrichtung.
Bevor ich den Sourcecode poste, einmal eine grundsätzliche Frage.
wenn ich schreibe.
PORTB |=(Richtung<<PB1) ; bedeutet das für mich, dass der Pin1 des
PortsB auf eins gesetzt wird, die anderen bleiben so wie sie sind.
Oder sehe ich das falsch?
Was ist der Unterschied zu
PORTB =(Richtung<<PB1) ; // also ohne Or
Hier jetzt mal der Sourcecode mit dem Problem.
1
voidSchrittmotor()
2
{
3
lcd_clear();
4
lcd_setcursor(2,1);
5
lcd_string("Belichtungstest 1");
6
lcd_setcursor(7,3);
7
lcd_string(": min");
8
9
lcd_setcursor(6,3);
10
lcd_data(M+48);
11
lcd_setcursor(8,3);
12
lcd_data(S10+48);
13
lcd_setcursor(9,3);
14
lcd_data(S+48);
15
16
while(1)
17
{
18
if(M>=1)
19
Richtung=links;
20
else
21
Richtung=rechts;
22
23
PORTB|=(Richtung<<PB1);// Drehrichtung
24
25
if(Schritte<=1200)
26
{
27
PORTB=(1<<PB0);
28
29
_delay_ms(0.020);// SM Enable bevor Timer2 eingeschaltet wird
TIMSK=0x04;// Timer2 ausschalten wenn eingestellte Schritte erreicht sind.
35
_delay_ms(0.020);// Zeitschleife für Timer2 Enable ausschalten
36
PORTB=(0<<PB0);// SM Enable off kurz nach dem ausschalten des Timers2
37
Schritte=1;// Zurücksetzen von Schritte
38
Intervall=0;
39
Start();// Nach Bewegung des Schrittmotors zurück zu Start und den nächsten Intervall abwarten
40
}// Ende else
41
}// Ende while
42
43
}
44
45
46
ISR(TIMER2_OVF_vect)
47
48
{
49
50
Schritte++;
51
schritte++;
52
53
PORTB^=(1<<PB2);
54
TIFR=(1<<6);
55
}
Fällt Jemanden etwas auf in der Programmierung was die Portanschaltung
angeht.
Bei PB0 habe ich anstatt 5V nur 2,5V anliegen, bei der Drehrichtung 1,2V
wenn auf High geschalten.
Über Hilfe wäre ich sehr Dankbar.
René
Hi, ich habe deinen Quellcode nur so überflogen.
Mir ist aufgefallen, diese Konstruction ist doch etwas merkwürdig.
PORTB |=(Richtung<<PB1) ;
Wo ist rechts & links definiert?
Besser so:
PORTB |= (1 << 3); // Portleitung setzen
PORTB &= ~(1 << 3); // Portleitung löschen
René Geßner schrieb:> wenn ich schreibe.>> PORTB |=(Richtung<<PB1) ; bedeutet das für mich, dass der Pin1 des>> PortsB auf eins gesetzt wird, die anderen bleiben so wie sie sind.>> Oder sehe ich das falsch?
Aber nur, wenn Richtung 1 ist - wenn Richtung Null ist, ändert sich gar
nichts.
Und natürlich musst du im DDRB die Ports die du als Ausgang verwenden
willst setzen:
DDRB |= (1 << 7) | (1 << 5) | (1 << 3); // PB7, PB5, PB3 als Output
@ René Geßner (gess12)
>PORTB |=(Richtung<<PB1) ; bedeutet das für mich, dass der Pin1 des>PortsB auf eins gesetzt wird, die anderen bleiben so wie sie sind.>Oder sehe ich das falsch?
Falsche Syntax. Eher so.
1
PORTB|=(1<<Richtung);
Dann stimmt deine Aussage, siehe Bitmanipulation.
>Was ist der Unterschied zu>PORTB =(Richtung<<PB1) ; // also ohne Or
Das seht NUR das einzelen Bit, der Rest wird auf Null gesetz.
1
if(M>=1)
2
Richtung=links;
3
else
4
Richtung=rechts;
5
6
PORTB|=(Richtung<<PB1);// Drehrichtung
Funktioniert nicht. Eher so.
1
if(M>=1)
2
PORTB|=(1<<PB1);// links
3
else
4
PORTB&=~(1<<PB1);// rechts
Denn du musst das Bit expizit setzen UND löschen, je nach Richtung. Dazu
braucht man zwei verschiedene Logikoperationen, siehe
Bitmanipulation.
Das Konzept von deinem Programm ist auch konfus, das mit dem Timer macht
man anders.
Erst einmal vielen Dank für die reichlichen Antworten.
Nun versuche ich mal die offenen Fragen zu beantworten.
Was für ein µC und wo werden die Ports auf Ausgang geschaltet?
Es handelt sich um einen ATMega32, DDRB wird in der Main auf Ausgang
gesetzt.
DDRB = 0xff;
links und rechts sind natürlich definiert
#define links 0
#define rechts 1
Aus euren Antworten kann ich entnehmen das ich nicht so falsch lag. Wir
haben das leider etwas anders gelehrt bekommen, auf die altmodische Art.
z.B. PORTB = PORTB | 0x01
Jetzt habe ich allerdings ein anderes Problem.
Nachdem ich jetzt die entsprechenden Ausgänge für Enable und
Drehrichtung Verodert habe, funktioniert das. Dafür verschluckt sich
jetzt mein Schrittmotor während er sich dreht.
PORTB ^= (1<<PB2); Das ist ja XOR am Pin2 am PORTB
Bezieht sich das jetzt nur auf den PIN2 oder hat das auch Auswirkung auf
die anderen PINs wie bei PORTB = (1<<PB2).
Wenn ich z.B. das Enable- und Richtunssignal auf einen anderen PORT lege
gibt es beim Schrittmotor überhaupt keine Probleme, zumindest
verschluckt er sich nicht so massiv.
Kann mir da Jemand helfen?
Vielen Dank
René
René Geßner schrieb:> Aus euren Antworten kann ich entnehmen das ich nicht so falsch lag. Wir> haben das leider etwas anders gelehrt bekommen, auf die altmodische Art.> z.B. PORTB = PORTB | 0x01
Na dann.
xyz |= 0x01;
ist identisch zu
xyz = xyz | 0x01;
oder allgemeiner gilt für alle Zuweisungsoperatoren, die es auch mit
einem Prefix gibt
xyz op= expression;
ist identisch zu
xyz = (xyz) op (expression)
anstatt also den Ausdruck links vom = auf der rechten Seite noch mal
hinzuschreiben, genügt es dem Compiler dies auzutragen, indem man die
Zuweisung modifiziert.
> Jetzt habe ich allerdings ein anderes Problem.> Nachdem ich jetzt die entsprechenden Ausgänge für Enable und> Drehrichtung Verodert habe, funktioniert das. Dafür verschluckt sich> jetzt mein Schrittmotor während er sich dreht.>> PORTB ^= (1<<PB2); Das ist ja XOR am Pin2 am PORTB> Bezieht sich das jetzt nur auf den PIN2 oder hat das auch Auswirkung auf> die anderen PINs wie bei PORTB = (1<<PB2).
Das bezieht sich nur auf den einen Pin.
Alle Bit-Operationen arbeiten auf die 8-Bit eines Wertes einzeln!
Drum heissen sie auch Bitoperationen.
> Kann mir da Jemand helfen?
Hmm. Meine Glaskugel ist schon im Wochenende!
Wenn du allerdings deinen Code posten würdest, dann würde ich keine
Glaskugel brauchen. Alternativ kannst du auch deine Hand auf den Scanner
legen, dann lese ich dir aus der Hand. Ist aber nicht ganz so
zuverlässig wie eine Glaskugel.
Allerdings:
Wenn das im wesentlichen das Programm von da oben ist ... das wird so
nix.
Da sind ein paar ordentliche Denkfehler drinnen. So baut man kein
Programm auf. Die Endlosschleife hat da drinn schon mal überhaupt nichts
verloren und der Aufruf von Start() muss da auch raus.
Die Funktion ruft kein Start() auf. Die Funktion macht ihr Sache und
wenn sie fertig ist, dann returniert sie zum Aufrufer.
Und den Timere ... lass ihn in Ruhe einfach durchlaufen, ansatt ihn
dauern ein/aus zuschalten. Das ist ein Irrtum wenn man meint, man muss
Timer laufend ein/ausschalten. Meistens handelt man sich da mehr Fehler
ein, als wie wenn man in der ISR einfach prüft ob es etwas zu tun gibt
und falls es nichts zu tun gibt dann einfach ... nichts tut und den
Timer in Ruhe weiter zählen lässt.
Wenn dein Programm eine bestimmte Anzahl Schritte mittels Timer erzeugen
soll, dann geht das so
1
volatileuint16_tSchritte;
2
3
voidSchrittmotor()
4
{
5
uint16_ttemp;
6
7
// Richtung einstellem
8
if(M>=1)
9
PORTB|=(1<<PB1);
10
else
11
PORTB&=~(1<<PB1);
12
13
// Anzahl Schritte setzen
14
cli();
15
Schritte=1200*2;
16
sei();
17
18
// warten bis der Timer die entsprechenden Schritte abgearbeitet hat
19
do{
20
cli();
21
temp=Schritte;
22
sei();
23
}while(temp>0);
24
}
25
26
ISR(...)
27
{
28
if(Schritte>0){
29
Schritte--;
30
PORTB^=(1<<PB2);
31
}
32
}
fertig.
Da muss kein Timer gestartet oder gestoppt werden.
Ob du in der Funktion aktiv darauf wartest, bis die vorgeschriebenen
Schritte abgearbeitet sind, oder ob du in der Zwischenzeit was anderes
machst, ist dann dir überlassen. Fix ist: solange die Variable Schritte
einen Wert größer als 0 enthält, arbeitet der Timer noch die Schritte
ab. Daran kann man erkennen, ob die letzte Bewegung bereits vollständig
abgearbeitet wurde oder nicht.
@kbuchegg
Danke für deine Antwort.
Der Sourcecode ist der von weiter oben, dieser ist jetzt nur abgeändert
in dem ich das OR noch eingefügt habe.
Wenn ich perfekt programmieren würde, würde ich bestimmt nicht
nachfragen müssen.
Und das ich nicht perfekt programmiere weiß ich. Ich bin nach wie vor
Anfänger, aber ich lerne. Deinen Hinweis alles in Funktionen zu packen
habe ich konsequent umgesetzt und habe damit einigermaßen Struktur rein
bekommen.
Wenn sich das XOR nur auf den PIN2 auswirkt, was ist dann falsch am
Programm?
Der Motor dreht sich nicht korrekt wenn die beiden Signale Enable und
Drehrichtung mit auf dem selben PORT liegen. Also muss das Programm wohl
die Störung verursachen.
Das selbe Programm, nur Enable und Richtung auf PORTC gelegt,
funktioniert.
Was mache ich also falsch??
Ich springe in die Schrittmotorfunktion, wenn M<1 ist, ist Richtung auf
1
und der Timer2 wird eingeschaltet, durch die ISR wird Schritte
hochgezählt und in der ISR wird der Impuls auf PORTB2 gegeben.
Was läuft falsch???
1
voidSchrittmotor()
2
{
3
lcd_clear();
4
lcd_setcursor(2,1);
5
lcd_string("Belichtungstest 1");
6
lcd_setcursor(7,3);
7
lcd_string(": min");
8
9
lcd_setcursor(6,3);
10
lcd_data(M+48);
11
lcd_setcursor(8,3);
12
lcd_data(S10+48);
13
lcd_setcursor(9,3);
14
lcd_data(S+48);
15
16
while(1)
17
{
18
if(M>=1)
19
Richtung=links;
20
else
21
Richtung=rechts;
22
23
PORTC|=(Richtung<<1);// Drehrichtung
24
25
if(Schritte<=1200)
26
{
27
PORTC|=(1<<0);
28
29
_delay_ms(0.020);// SM Enable bevor Timer2 eingeschaltet wird
René Geßner schrieb:> Was mache ich also falsch??
Zum Beispiel das hier
> PORTC |=(Richtung<<1) ; // Drehrichtung>> Schritte=1; // Zurücksetzen von Schritte> Intervall=0;
Zum Beispiel das hier
> while(1)> {
Zum Beispiel das hier
> Start (); // Nach Bewegung des Schrittmotors> zurück zu Start und den nächsten Intervall abwarten
Du denkst noch zu sehr in Form von
mach das, dann mach das und dann spring irgendwo anders hin!
Das ist die falsche Ansicht!
Das main() gibt einen "Auftrag" an die Funktion, etwas zu machen. Und
wenn die Funktion damit fertig ist, dann kehrt sie auf ganz normalem Weg
zurück und springt nicht irgendwo hin. main() entscheidet wie es dann
weiter geht und nicht die Funktion!
Ich hab dir doch ein Beispiel geschrieben. Studier es und überleg dir,
wo da jetzt der wesentliche Unterschied liegt. Es ist ein
konzeptioneller Unterschied und nichts was man an 2 Anweisungen fest
machen kann. Der ganze konzeptionelle Aufbau ist anders!
@ kbuchegg
den zweiten Teil deiner Antwort hatte ich leider nicht gesehen.
Deswegen meine Antwort dazu jetzt.
Ich benutze den Timer um eine Frequenz zu erzeugen, die Notwendig ist um
den Schrittmotor drehen zu lassen.
1
volatileuint16_tSchritte;
2
3
voidSchrittmotor()
4
{
5
uint16_ttemp;
6
7
// Richtung einstellem
8
if(M>=1)
9
PORTB|=(1<<PB1);
10
else
11
PORTB&=~(1<<PB1);
12
13
// Anzahl Schritte setzen
14
cli();
15
Schritte=1200*2;
16
sei();
Diesen Teil verstehe und bedarf keiner Erklärung.
Dafür aber für den folgenden Teil.
1
// warten bis der Timer die entsprechenden Schritte abgearbeitet hat
2
do{
3
cli();
4
temp=Schritte;
5
sei();
6
}while(temp>0);
7
}
Ich schalte den Timer ein und aus, weil im Hintergrund noch ein zweiter
Timer läuft der für die Zeit verantwortlich ist. Mit cli() würde ich den
doch dann auch auschalten bzw. Interrups unterbinden? Oder???
René
René Geßner schrieb:> Diesen Teil verstehe und bedarf keiner Erklärung.> Dafür aber für den folgenden Teil.>>
1
>
2
>// warten bis der Timer die entsprechenden Schritte abgearbeitet hat
3
>do{
4
>cli();
5
>temp=Schritte;
6
>sei();
7
>}while(temp>0);
8
>}
9
>
>> Ich schalte den Timer ein und aus, weil im Hintergrund noch ein zweiter> Timer läuft der für die Zeit verantwortlich ist.
Und?
Der läuft ja weiter.
> Mit cli() würde ich den> doch dann auch auschalten bzw. Interrups unterbinden? Oder???
Nach dem Auslesen der Variable 'Schritte' folgt ja sofort wieder der
zugehörige sei(). Die Interrupts sind genau so lange gesperrt, wie es
dauert 2 Bytes aus dem Speicher zu lesen. Was denkst du was das für den
Rest des Programms bedeutet, wenn ein Interrupt mal um 0.1µs später
kommt als er kommen könnte?
Die Funktionen sind sozusagen verschachtelt.
Das Programm ist so umfangreich geworden das ich leider nicht alles
posten kann.
Ich springe in die Start() weil dort eine Zeit abläuft die auf einem
Display ausgegeben wird und nach 30 Sekunden wird der Schrittmotor um
eine bestimmte Anzahl Schritte bewegt und das geht so 6min lang. Von der
Start() springe ich sozusagen aller 30 Sekunden in die Schrittmotor()
und von da wieder zurück zur Start bis zum Ende.
René
René Geßner schrieb:> Die Funktionen sind sozusagen verschachtelt.
OK.
Dann bin ich raus.
Du wirst dann schon sehen, was alles passiert, wenn dir der Stack
überläuft.
Wer nicht hören will, muss es eben auf die harte Tour lernen.
@kbuchegg
Ich danke dir für deine Hilfe. Glaube mir, ich versuche deine
Gedankengänge zu verstehen und auch umzusetzen. Und unbelehrbar bin ich
nicht. Unwissend mit wenig Erfahrung trifft es besser.
Und genau aus diesem Grund habe ich mich in diesem Forum angemeldet, um
zu lernen von Leuten die wesentlich mehr Wissen und Erfahrung haben als
ich.
Du urteilst ziemlich schnell. Aber ich kann das verstehen.
Danke für deine Mühen.
Ich werde euch nicht mehr belästigen. Wenn hier nur Profis erwünscht
sind, dann bin ich hier falsch.
René
René Geßner schrieb:> Ich werde euch nicht mehr belästigen. Wenn hier nur Profis erwünscht> sind, dann bin ich hier falsch.
Keineswegs.
Aber was soll ich mit wem, der sowieso keinen Rat annimmt und lieber
seinen Stiefel weiterprogrammiert, weil er nicht wahrhaben will, dass
man klein anfangen muss. Die Zeit kann ich mir auch sparen.
Wie ich schon sagte, ich programmiere so wie es mein Wissen zulässt.
Wenn man aber einem Nichtschwimmer, der sich gerade mal über Wasser
halten kann, vom Beckenrand aus erzählt wie geschwommen werden muss um
bei Olympia dabei zu sein und er dann als unbelehrbar erklärt wird nur
weil er es nicht gleich so umsetzen kann.
Ich halte das etwas anders, ich bin ein gelernter Teamplayer, (ich war
mal Leistungssportler in einer Mannschaftssportart), und als solcher
stand und stehe ich noch heute denen bei die Probleme haben. Weil leider
eine Schwalbe nun mal keinen Sommer macht.
Und in diesem Fall bin ich der Nichtschwimmer und Derjenige der die
Probleme hat. Aber ich werde noch schwimmen lernen im übertragenen
Sinne.
René
> Wenn man aber einem Nichtschwimmer, der sich gerade mal über> Wasser halten kann, vom Beckenrand aus erzählt wie geschwommen> werden muss um bei Olympia dabei zu sein und er dann als> unbelehrbar erklärt wird nur> weil er es nicht gleich so umsetzen kann.
Du verwechselst da was.
Du magst der Nichtschwimmer sein.
Aber nicht ich bin es, der dir vom Beckenrand aus Anweisungen zuruft,
sondern du bist es, der sich nach seinem ersten 5 Meter im Hunderlstil
einbildet, er könne zu Olympia fahren und fragt, was er dazu tun müsse.
Du hast Halbwissen?
Tu was dagegen!
Aber nicht in der Form, dass du dir ein Projekt aufreisst, dass 10
Nummern zu groß für dich ist.
Sorry. Da mussten wir ALLE ausnahmslos durch. Jeder von uns hat klein
angefangen und nicht mehr vom Kuchen abgebissen als er schlucken konnte.
Und ja - das dauert seine Zeit. 2, 3 Jahre sind da gar nichts.
Aber es ist ok.
Wer radfahren lernen will, muss auch runterfallen.
Die selbst gemachte Erkenntnis 'so gehts nicht' ist oft mehr wert als
eine vorgekaute Lösung.
Der Mensch wächst mit seinen Aufgaben.
Mein Projekt ist mit Sicherheit nicht zu hoch angesiedelt.
Und wie ich dir schon einmal geschrieben habe, ich bin keine 18 mehr.
Ich weiß meine Fähigkeiten ganz gut einzuschätzen und auch nicht zu
überschätzen.
Ach, übrigens. Olympia war wirklich mal mein Ziel. Und ich bin nicht
daran zerbrochen das es nicht geklappt hat.
Wenn ich mal noch eine Frage los werden darf. Wie lange programmierst du
schon µC?
René
>Der Mensch wächst mit seinen Aufgaben.
Aber Du nicht. Wenn man Dir die Richtung zeigt in der Du wachsen
solltest, dann bestehst Du darauf klein zu sein.
Das ist der ganze Tenor, deiner letzten Beiträge.
Mach es einfach und diskutiere hier nicht 'rum.
Wenn Du vernünftig und bescheiden nachfragst, warum Du das so machen
sollst und nicht anders wird man Dir ebenso antworten.
Aber diese Rumgesülze, das Du es nicht besser kannst, ist nichts weiter
als das versteckte: Ich will nicht anders.
>Und wie ich dir schon einmal geschrieben habe, ich bin keine 18 mehr.
Was hat das für eine Relevanz?
>Ich weiß meine Fähigkeiten ganz gut einzuschätzen und auch nicht zu>überschätzen.
Im Gartenbau, oder in welchem Aufgabengebiet?
>Wenn ich mal noch eine Frage los werden darf. Wie lange programmierst du>schon µC?
Karl Heinz so gefühlte hundertmal solange wie Du! Da darfst Du ruhig
d'rauf wetten.
Mann, ich krieg echt 'nen Anfall, wenn ich lese wie Leute wie Karl Heinz
sich hier von irgendwelchen Möchtegerns ans Bein pinkeln lassen müssen.
Das ist nicht sein Problem, sondern DEINES! Kapier das endlich Du
Sülzkopf!
@Hmm
Schreib wenigsten deinen Namen drunter, wenn du schon mit Beleidigungen
um dich wirfst. So aus der Anonymität ist das recht einfach. Und wenn du
vom Sachverhalt keine Ahnung hast, sei einfach still. Ich möchte hier
niemanden ans Bein pissen, dem Karl Heinz schon gar nicht. Ich weiß wie
Respekt geschrieben wird und bringe diesen auch anderen Menschen
entgegen. Du ja wohl nicht.
René
>Ich weiß wie Respekt geschrieben wird...
Und Du meinst, wer es schreiben kann, versteht auch den Sinn? Du
respektierst ja nicht mal Dich selbst. Heulst hier herum wie so ein
kleines Kind.
Zum Thema keinen Beitrag aber beleidigen.
Ich frage mich wer hier Kuchen gesagt hat, das sich jetzt auf einmal die
Krümel melden.
Übrigens du hast einen Teil bei deinem Zitat vergessen.
>und bringe diesen auch anderen Menschen entgegen.
Wenn man schon zitiert sollte man es richtig tun und nicht nur heraus
picken was einem passt.
Und damit sollte Schluss sein mit dieser Diskusion, es bringt Niemanden
hier weiter.
René
>>Wenn ich mal noch eine Frage los werden darf. Wie lange programmierst du>>schon µC?>> Karl Heinz so gefühlte hundertmal solange wie Du! Da darfst Du ruhig> d'rauf wetten.
Weis ich nicht.
Meine ersten Programme (damals noch auf dem Papier, weil ich keinen
Computer zur Verfügung hatte) sind 1980 entstanden. Tatsächlich laufen
lassen konnte ich die ersten Programme 1981. In die
Industrieprogrammierung bin ich dann so um 1988 gekommen. Man könnte
also durchaus sagen: 7 Jahre Lehrzeit, wenn man so will. Obwohl sich das
jetzt dramatischer anhört als es war :-) AUf jeden Fall war die Zeit
damals nicht mit den Möglichkeiten vergleichbar, die man heute hat.
So um 2002 rum hatte ich das erste mal einen AVR in den Fingern.
Aber was hat das damit zu tun, dass dein Programmaufbau nicht stimmt?
Ein Programmaufbau, den man in mindestens 20 kleineren Programmen vorher
trainiert hat? Funktionen sind keine Hexerei. Und wenn man da auf die
übliche Weise in die Sache reinwächst, dann kommt man gar nicht auf die
Idee ein rekursives System nach dem Muster
1
voidfoo()
2
{
3
...
4
bar();
5
}
6
7
voidbar()
8
{
9
...
10
foo();
11
}
aufzubauen.
Solche (ähnliche) Konstruktionen gibt es zwar in der Informatik, das
nennt sich indirekt rekursive Funktionen, aber die sind mit Sicherheit
nichts für einen Anfänger. Die kann er nicht beherrschen.
Dein Problem sitzt an einer anderen Stelle. Du setzt 'Funktion aufrufen'
mit 'Mach dort weiter' gleich. Du ignorierst dabei, dass eine Funktion
auch wieder zurückkommen muss. Denn jeder Funktionsaufruf speichert sich
die Stelle von wo er aufgerufen wurde. Bei entsprechend vielen
Funktionsaufrufen, die nie mit einem Return abgeschlossen wurden, kommt
es dann eben dazu, dass diese gespeicherte Rückkehrinformation alles
andere 'überwuchert'. Und dann machts Peng.
Aber: All das steht in jedem noch so grindigem C-Buch drinnen. Das ist
nichts was man dir hier im Forum erklären muss bzw. müssen sollte. Und
wenn man dem Pfad eines Lehrbuchs folgt und seine Übungen dazu macht,
dann stellt sich diese Problematik das erste mal genau dann, wenn es um
rekursive Funktionen geht. Und nicht früher. Rekursive Funktionen würde
ich aber schon in den Bereich 'fortgeschrittener Programmierer'
einstufen. Das ist nichts worüber ein Neuling sich in den ersten 2
Jahren den Kopf zerbrechen muss oder soll.
> Mein Projekt ist mit Sicherheit nicht zu hoch angesiedelt.
Doch, das ist es.
Deine Probleme in deinem Programm stammen nicht daher, dass irgendein
Detail nicht stimmt oder dass du irgendwo einen dummen Fehler gemacht
hast. Deine Probleme (die du wahrscheinlich noch gar nicht bemeerkt
hast) stammen unter anderem daher, dass der ganze Unterbau, der ganze
Aufbau nicht stimmt. Das Problem beim schiefen Turm von Pisa ist nicht,
dass ganz oben ein paar Ziegeln schief eingesetzt wurden. Das Problem
beim schiefen Turm beginnt unten, im Fundament.