Forum: Mikrocontroller und Digitale Elektronik String Ausgabe löst Reset aus


von Andreas H. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
Habe ein kleines Verständnis Problem. Programmiere momentan eine 
Regelung für ein Modelltriebwerk. Gerade bin ich beim Start. Ich lasse 
mir sekündlich die Temperatur und die Drehzahl des Triebwerks ausgeben. 
Der Anfang des Starts läuft ohne Probleme, komme ich jedoch in meine 
zweite while Schleife so bricht das Programm ab und der Mikrocontroller 
startet es komplett neu. In dieser Schleife lasse ich mir im gleichen 
String auch noch den aktuellen PWM-Wert ausgeben. Lasse ich den PWM-Wert 
in einem eigenen String ausgeben funktioniert das Programm wieder ohne 
Probleme. Kann es sein, dass der String durch die weiteren Zeichen zu 
lang wird und der Controller damit nicht umgehen kann?

Gruß Andreas

von Klaus W. (mfgkw)


Lesenswert?

1. ist das Programm nicht vollständig; das macht so keinen Spaß.

2. Wie willst du von der ersten in die zweite Schleife kommen, wenn die 
erste endlos ist? Hast du soviel Geduld?

von Klaus W. (mfgkw)


Lesenswert?

PS: sehe gerade, daß die erste while-Schleife ja gar nicht vor der 
zweiten endet; mein 2. Punkt ist also Blödsinn.
Dafür könntest du das Programm mal sinnvoll formatieren, damit man es 
verstehen kann :-)

von Lehrmann M. (ubimbo)


Lesenswert?

Sagt dir das Stichwort "Stack Overflow Reset" irgendwas? Wäre das eine 
Möglichkeit. Wie das jetzt genau bei deinem Mikrocontroller heißt weiß 
niemand - du sagst ja auch nicht welchen du verwendest.

- gesamter Schaltplan
- gesamter Sourcecode
- alle Fuses

von Klaus W. (mfgkw)


Lesenswert?

Selbst nach einem Formatieren ist das Programm ziemlich wirr.
Lesbar ist etwas anderes....

So ein Kommentar ist vollkommen sinnlos:
  while (1) //Unendliche Schleife
Dafür wären sinnvolle Kommentare hilfreich oder vernünftige Namen statt 
i und s.

Etwas wie:
  PORTF &= ~(1<<PF7);
könnte mit lesbaren Namen auch ziemlich gewinnen.

Es wäre erstmal dein Job, das Ganze verständlich zu machen, bevor hier 
jeder anfängt zu rätseln.

von Holger S. (holger_s30)


Lesenswert?

"programmteil 1":
// Wenn Triebwerk über 9000RPM, EGT über 100°C und Zündung erkannt 
Kerosinventil auf

bzw. folgendes soll scheinbar zur Programm-Termination führen

// Wenn Taster gedrückt gehe in Schleife
// 15ms warten
// Wenn Taster immernoch gedrückt dann Autostop einleiten

Danach folgt "programmteil 2"

// Wenn Taster gedrückt gehe in Schleife
// 15ms warten
// Wenn Taster immernoch gedrückt dann Autostop einleiten

bzw.

// Sicherung gegen Übertemperatur

o.

// Sicherung gegen hängengebliebenden Start

führen in "programmteil 2" zur Terminierung?!


Vermutung: deine Variable char s[45] wird überrant. Du solltest sie 
vielleicht auch mal clearen. Die Vermutung kommt dadurch das du jedesmal 
strcat (s ...also jedesmal nur anhängst.
Meine Vermutung wird gestärkt durch:

Andreas H. schrieb:
> Lasse ich den PWM-Wert
> in einem eigenen String ausgeben funktioniert das Programm wieder ohne
> Probleme.

Folglich ->

Lehrmann Michael schrieb:
> Sagt dir das Stichwort "Stack Overflow Reset" irgendwas?

von Karl H. (kbuchegg)


Lesenswert?

Die Anmerkungen, das alles ein wenig übersichtlicher zu machen, haben 
etwas für sich.

Ein paar5 Tips:

Es lohnt sich meistens, große Funktionalitätsblöcke in Funktionen 
auszulagern.

Du musst keinesfalls erst einmal alle deine Ausgaben in einen einzigen 
String zusammenpfriemeln, ehe du dann diese String irgendwo ausgibst. 
Die UART hat kein Problem damit, wenn du einfach nacheinander 
Einzelstrings ausgibst. Die Anzeige (Terminal) kann sowieso nicht 
unterscheiden, ob du jetzt im Programm alles in einem String 
zusammengepfercht hast oder ob der Text den es anzeigen soll aus 
meherern Ausgaben stammt

1
         char a [8]= " Stop1 ";
2
          uart_puts(a);
Du brauchst hier kein Zwischenarray. Es ist absolut kein Problem, den 
String einfach direkt an uart_puts zu übergeben
1
         uart_puts( " Stop1 " );
Aber wenn du solche Arrays hast, dann ist es am besten den Compiler die 
Zeichen zählen zu lassen. Die Arraygröße selbst anzugeben, wenn man es 
nicht muss, ist erstens langweilig und zweitens fehleranfällig. Der 
Compiler kann zuverlässiger zählen als du. Und er macht es bei jedesmal 
übersetzen wieder aufs neue.


Funktionen wurden schon angesprochen. Sie sind dein Werkzeug, mit der du 
scheinbare Komplexität aus dem Programm rausholen kannst. Wenn zb die 
Anzeigesequenz (also das was du ausgibst) immer gleich ist UND dann auch 
noch an 2 Stellen vorkommt, dann ist es eine gute Idee, dafür eine 
eigene Funktion zu machen. Zb der ganze Teil, der sich damit beschäftigt 
eine Temperatur auszugeben.


Brich dein Programm etwas auf, mach es übersichtlicher, keine 
Monsterfunktionen. Und du wirst sehen, dass sich einige Probleme durch 
die bessere Übersicht ganz von alleine in Luft auflösen. Das eigenartige 
ist nämlich: die Programmierer mit den unüberisichtlichsten Programmen 
sind oft auch die mit den seltsamsten Fehlern. In diesem Sinne ist ein 
optisch schöner und überischtlicher Quelltext nicht einfach nur 
Selbstzweck, sondern erfüllt durchaus eine praktische Funktion.

von Karl H. (kbuchegg)


Lesenswert?

Variablennamen sinnvoll wählen. Je kürzer ein Variablenname, desto 
'lokaler' soll die Variable sein.
Ein Variablenname von 'i' ist für eine Variable, die die Drehzahl hält 
nicht angemessen. i, j, k, l sind typische Variablennamen, wie man sie 
in (kurzen) for-Schleifen benutzt. Dort sind sie die Laufvariable, die 
irgendetwas durchzählt.

von Andreas H. (Gast)


Lesenswert?

Erstmal danke für eure Antworten.
Hatte nur einen Ausschnitt des Programms geposted um die Übersicht (ich 
weiß, dass die in meinem Programm sowieso schlecht ist) ein wenig besser 
zu machen.
An die Sache mit den Zwischenarrays und den Variablennamen hab ich mich 
schon gemacht und werde versuchen mich da in Zukunft zu bessern.
Einige Sachen in Funktionen auszulagern hatte ich auch schon geplant, 
bzw auch schon angefangen. Wollte nur erst versuchen ob das Programm so 
wie ich mir das wünsche überhaupt funktioniert.
Zur Sache mit dem Clearen. Kann mir einer kurz erklären wie das 
funktioniert?

Gruß Andreas

von Jean P. (fubu1000)


Lesenswert?

Hi,

Andreas H. schrieb:
> Zur Sache mit dem Clearen. Kann mir einer kurz erklären wie das
> funktioniert?
z.B so
1
s[0] = 0;

oder so
1
memset(s, 0, sizeof(s));

Gruß

von Karl H. (kbuchegg)


Lesenswert?

So wie ich das stichprobenartig gecheckt habe, ist das Stringproblem 
keines. Mit viel Geduld und Spucke findet man raus, dass du in der 
Squenz
1
      // Drehzahl in String umwandeln
2
      ultoa( i, s, 10 ); //Variable in Ascii-Zeichen umwandeln
3
      strcat (s, "[1/min] "); //Leerzeichen einfügen
4
      
5
      //Temperatur in String umwandeln
6
      if (tc_erkennung==1)
7
      {
8
        strcpy (temp, "Kein TC"); // Fehlermeldung wenn kein Thermoelemant angeschlossen
9
      }
10
      
11
      else
12
      {
13
        temp_to_string(temperature, temp); // In String umwandeln
14
      }
15
      
16
      strcat (s, temp); //Temperatur an String anfügen
17
      strcat (s, "[C] "); //Leerzeichen einfügen
18
  
19
      uart_puts(s); //Drehzahl und Temperatur ausgeben
20
      
21
      DrehTemp = 0; // Bestätigung das Ausgabe erfolgt ist
22
    }

als erstes ein ultoa machst, welches implizit dafür sorgt, dass der 
String wieder von vorne beschrieben wird. Aber eigentlich ist das 
unnötig, wenn du erst mal eine etwas sinnvollere Aufteilung in 
Funktionen machst. Ein nicht unerheblicher Teil der Entwicklungsarbeit 
besteht darin, sich sinnvolle Hilfsfunktionen zu schreiben.

von Jean P. (fubu1000)


Lesenswert?

Ui,
ich meinte natürlich
1
memset(s, 0, sizeof(s) / sizeof(char));
In deinem Fall macht die Version 1 und 2 keinen Unterschied, aber wenn 
z.B.
ein uint16_t array wäre, würdest du ausserhalb des Speicherbereichs 
schreiben.

Gruß

von asd (Gast)


Lesenswert?

Jean Player schrieb:
> ich meinte natürlich
>   memset(s, 0, sizeof(s) / sizeof(char));

Ein sizeof(char) is per Definition immer 1, ist also äquivalent zu dem 
oben geposteten.


> In deinem Fall macht die Version 1 und 2 keinen Unterschied, aber wenn
> z.B.
> ein uint16_t array wäre, würdest du ausserhalb des Speicherbereichs
> schreiben.

Nö? sizeof() liefert die Größe des Arrays in Bytes, memset() will die 
Größenangabe auch in Bytes, das sizeof(s) klappt also immer, egal ob ein 
char-Array oder uint16_t-Array.

von Karl H. (kbuchegg)


Lesenswert?

Jean Player schrieb:
> Ui,
> ich meinte natürlich
>
1
> memset(s, 0, sizeof(s) / sizeof(char));
2
>
> In deinem Fall macht die Version 1 und 2 keinen Unterschied, aber wenn
> z.B.
> ein uint16_t array wäre, würdest du ausserhalb des Speicherbereichs
> schreiben.

Kleiner Tip.
Wenn du das so universell wie möglich haben willst, dann schreib es so
1
  memset( s, 0, sizeof(s) / sizeof(*s) );

dann spielt es keine Rolle, welchen Datentyp s hat (solange es ein Array 
ist). Das erledigt dann der Compiler für dich.

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.