Forum: Mikrocontroller und Digitale Elektronik ATmega8 Reset/ Array Löschen / Laufzeitverhalten


von Tho W. (tommyprog)


Angehängte Dateien:

Lesenswert?

Grüß euch alle,

bei einem (nur bei diesem Codeausschnitt) habe ich ein Laufzeitproblem.
Der Code befindet sich im Anhang.

In meinen zwischenspeicher_array, welches maximal 4 Zeichen groß ist 
(nicht sichtbar im Codeschnitt) wird aus einen Empfangspuffer einer UART 
eine Zahl von 0-255 gespeichert.

Wird aber (wenn das überhaupt passiert) eine Zahl im dreistelligen 
Bereich, wie 100 auf einmal als PWM Signal signal in mein 
zwischenspeicher_array gespeichert, stürzt der µC ab.

Die Position der ersten Ziffer ist im Puffer "2", die zweite Ziffer "3", 
die dritte Ziffer "4".
Der Buchstabe P ist das Zeichen an Position "1".

bei den Löschen (also das Array komplett leeren) habe ich ein Problem, 
weil das Array den zuvorherigen Speicherwert annimmt. Veilleicht liegt 
es daran.

Hab das Array erst mit 
zwischenzustand_array[ZWISCHENZUSTAND_ARRAY_SIZE]={0}; versucht zu 
löschen.
Das Problem war noch da.

Dann hatte ich versucht mit zwischenzustand_array[0]='\0' das array zu 
löschen, indem ich ein Stringende zeichen vortäusche, was aber das 
Problem nicht behoben hat.

Könnte mir jemand bitte einen Anreiz geben?

von Peter II (Gast)


Lesenswert?

wie ist ZWISCHENZUSTAND_ARRAY_SIZE definiert?

von Tho W. (tommyprog)


Lesenswert?

Peter II schrieb:
> wie ist ZWISCHENZUSTAND_ARRAY_SIZE definiert?

Mit einen #define ZWISCHENZUSTAND_ARRAY_SIZE 4

von Peter II (Gast)


Lesenswert?

Tho Wes schrieb:
> Peter II schrieb:
>> wie ist ZWISCHENZUSTAND_ARRAY_SIZE definiert?
>
> Mit einen #define ZWISCHENZUSTAND_ARRAY_SIZE 4

gut, dann ist der Fehler in den code den wir nicht sehen.

von Tho W. (tommyprog)


Lesenswert?

danke dir peter, das reicht schon für eine gute Antwort aus.
Aber wie lösche ich eigentlich (also inhalte löschen) ein Array in C, 
das dann komplett neu befüllt werden soll, liege ich da wenigstens 
richtig?

Mfg,
tommyProg

von Eric B. (beric)


Lesenswert?

> zwischenzustand_array[ZWISCHENZUSTAND_ARRAY_SIZE] = { 0 };

Das ist Quatsch. Du brauchst entweder:
1
zwischenzustand_array[ZWISCHENZUSTAND_ARRAY_SIZE - 1] = 0;
oder
1
memset(zwischenzustand_array, 0, ZWISCHENZUSTAND_ARRAY_SIZE);

von Purzel H. (hacky)


Lesenswert?

a[0]=0;
a[1]=0;
a[2]=0;
a[3]=0;
Alles andere ist muehsamer, dauert laenger

von Peter II (Gast)


Lesenswert?

Eric B. schrieb:
>> zwischenzustand_array[ZWISCHENZUSTAND_ARRAY_SIZE] = { 0 };
>
> Das ist Quatsch. Du brauchst entweder:

warum sollte das Quatsch sein?

von Bitte einen Namen eingeben (nicht "Gast") oder ein (Gast)


Lesenswert?

Peter II schrieb:
> warum sollte das Quatsch sein?

Weil es halt Quatsch ist. Lies ein C-Buch.

von Le X. (lex_91)


Lesenswert?

Siebzehn Zu Fuenfzehn schrieb:
> a[0]=0;
> a[1]=0;
> a[2]=0;
> a[3]=0;
> Alles andere ist muehsamer, dauert laenger

Auf jeden Fall ist es wartungsintensiver wenn sich am Array was ändert.

Ohne es hier grad überprüfen zu können:
Mich würde es wundern wenn der Compiler bei einem hinreichend kleinem 
Array die Schleife, die sich irgendwo in memset befinden wird, nicht eh 
durch explizites Setzen jedes Bytes ersetzt.

von Peter D. (peda)


Lesenswert?

Tho Wes schrieb:
> Aber wie lösche ich eigentlich (also inhalte löschen) ein Array in C,

In der Regel garnicht.

Wenn man einen Datenstream empfängt, erfolgt dies nach einem Protokoll, 
damit man das Ende eines Frames erkennen kann.
Bei Textdaten fügt man in der Regel ein 0-Byte an und übergibt den 
String dann zur Auswertung.
Bei Binärdaten übergibt man zusätzlich die Länge des Datenfeldes, da 
dieses ja auch 0-Bytes enthalten kann.
Es gibt also nirgends den Zustand, daß vorher etwas gelöscht werden muß.

von Bitte einen Namen eingeben (nicht "Gast") oder ein (Gast)


Lesenswert?

Was ist überhaupt "löschen"?

von Bastler (Gast)


Lesenswert?

Ich lösche Arrays nicht im Betrieb, ich setzt nur meinen Pointer zum 
ein-/ auslesen neu und überschreibe.

von Karl H. (kbuchegg)


Lesenswert?

Der ganze Ansatz, erst mal die einlaiufenden Zeichen in einem weiteren 
char-Array zwischenzuspeichern, bis ein nicht-digit daher kommt, und das 
ganze dann atoi vorzuwerfen, ist schon Quatsch.

Eine Zahl wird um die jeweils nächste Stelle erweitert, indem man die 
Zahl mal 10 nimmt und dann die nächste Ziffer addiert. Genau mit diesem 
Mechanismus hängt man zb an die Zahl 86 die nächste Ziffer 5 an: 86 * 10 
macht 860. da dann noch die 5 addiert, ergibt 865

Sobald du das Kommando erkannt hast:
setzt die eine entsprechende int-Variable auf 0
für jedes weitere erkannte Zeichen, welches zur Ziffer gehört, wird dann 
die Zahl entsprechend um diese Ziffer erweitert
1
   int Zahl = 0;
2
3
   n = 2;
4
   while( isdigit( uart_empfangsbuffer[n] ) )
5
     Zahl = Zahl * 10 + ( uart_empfangsbuffer[n] - '0' );
6
7
   // ev. noch Prüfungen machen, ob zb die erwartete Zahl innerhalb
8
   // von vordefinierten Limits liegt
9
10
   // und dann setzen
11
12
   OCR2 = Zahl;

kein Mensch muss da Character umkopieren. Kostet nur Zeit und man läuft 
Gefahr Arrays zu überlaufen.


Man könnte auch atoi direkt auf den Empfangsbuffer ansetzen
1
  int Zahl = atoi( &uart_empfangsbuffer[2] );
2
  OCR2 = Zahl;

denn atoi macht ja grundsätzlich auch nichts anderes. In der 
eigenständigen Schleifenversion hat man den Vorteil, dass man auf 
eventuelle Fehler noch besser reagieren könnte, während man bei atoi 
erst mal am Ergebnis nicht ablesen kann, ob da zb überhaupt eine 'Zahl' 
im String enthalten war. Dafrü kann atoi selbstverständlich mit einem 
'-' umgehen, was man der Schleifenversion erst noch beibringen müsste, 
wenn das relevant ist.
Dafür kann man die Schleifenversion in einer etwas 'auseinander 
genommenen' Version auch wunderbar in einer Statemachine unterbringen.
1
...
2
3
  while( 1 )
4
  {
5
    char c = next Character from Uart if one exists
6
7
    switch( state )
8
    {
9
      case ExpectCommand:
10
        if( c = 'P' )
11
        {
12
          state = ExpectPWMNumber;
13
          PWMValue = 0;
14
        }
15
16
        break;
17
18
      case ExpectPWMNumber:
19
        if( isdigit( c ) )
20
          PWMValue = 10 * PWMValue + ( c - '0' );
21
22
        else
23
        {
24
          OCR2 = PWMValue;
25
          state = ExpectCommand;
26
        }
27
        break;
28
...
29
      }


Du hast da wieder zielsicher die komplizierteste Lösung rausgesucht.

von Peter II (Gast)


Lesenswert?

Bitte einen Namen eingeben (nicht "Gast") oder ein schrieb im Beitrag 
#3869491:
> Peter II schrieb:
>> warum sollte das Quatsch sein?
>
> Weil es halt Quatsch ist. Lies ein C-Buch.

habe ich, dort steht drin das damit das ganze Array mit 0 initialisiert 
wird.

von Bitte einen Namen eingeben (nicht "Gast") oder ein (Gast)


Lesenswert?

Peter II schrieb:
> dort steht drin das damit das ganze Array mit 0 initialisiert
> wird.

Ganz sicher nicht.

von Peter II (Gast)


Lesenswert?

Bitte einen Namen eingeben (nicht "Gast") oder ein schrieb im Beitrag 
#3869522:
> Peter II schrieb:
>> dort steht drin das damit das ganze Array mit 0 initialisiert
>> wird.
>
> Ganz sicher nicht.

doch ganz sicher. Eventuell sollte du mal nachlesen. Dort wo etwas über 
Initialisierung von Array steht.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Bitte einen Namen eingeben (nicht "Gast") oder ein schrieb im Beitrag
> #3869522:
>> Peter II schrieb:
>>> dort steht drin das damit das ganze Array mit 0 initialisiert
>>> wird.
>>
>> Ganz sicher nicht.
>
> doch ganz sicher.

Vorsicht. Wortwahl.

Das kann keine Initialisierung sein, weil hier keine Definition eines 
Arrays vorliegt. Das ist eine ganz normale Zuweisung.

von Bitte einen Namen eingeben (nicht "Gast") oder ein (Gast)


Lesenswert?

Peter II schrieb:
> doch ganz sicher.

Nein. Du verwechselst eine Initialisierung mit einer Zuweisung.
Hier handelt es sich um eine Zuweisung. Und die ist, wenn überhaupt 
gültig, außerhalb des Arrays.

von Peter II (Gast)


Lesenswert?

Karl Heinz schrieb:
> Vorsicht. Wortwahl.
>
> Das kann keine Initialisierung sein, weil hier keine Definition eines
> Arrays vorliegt. Das ist eine ganz normale Zuweisung.

oh, sorry mein fehler.

Ich hatte

[c]
uint8_t zwischenzustand_array [ZWISCHENZUSTAND_ARRAY_SIZE] = { 0 }
[\c]

für mich gelesen.

von Tho W. (tommyprog)


Lesenswert?

Eric B. schrieb:
>> zwischenzustand_array[ZWISCHENZUSTAND_ARRAY_SIZE] = { 0 };
>
> Das ist Quatsch. Du brauchst entweder:
>
>
1
zwischenzustand_array[ZWISCHENZUSTAND_ARRAY_SIZE - 1] = 0;
> oder
>
1
memset(zwischenzustand_array, 0, 
2
> ZWISCHENZUSTAND_ARRAY_SIZE);

Eric, das funktioniert beides nicht.
Das andere probiere ich noch aus.

von Tho W. (tommyprog)


Lesenswert?

Peter Dannegger schrieb:

> In der Regel garnicht.
>
> Wenn man einen Datenstream empfängt, erfolgt dies nach einem Protokoll,
> damit man das Ende eines Frames erkennen kann.
> Bei Textdaten fügt man in der Regel ein 0-Byte an und übergibt den
> String dann zur Auswertung.
> Bei Binärdaten übergibt man zusätzlich die Länge des Datenfeldes, da
> dieses ja auch 0-Bytes enthalten kann.
> Es gibt also nirgends den Zustand, daß vorher etwas gelöscht werden muß.


Oh ok.
Dieses Schema muss ich auch befolgen. Zuerst habe ich ein 0-Byte 
(startbyte), den String habe ich auch.
Aus diesen String muss ich aber gewisse Zeichen rauslesen, und diese 
Zeichen sind mein Wert für das PWM signal.

Mfg,
tommyProg

von Tho W. (tommyprog)


Lesenswert?

Bitte einen Namen eingeben (nicht "Gast") oder ein schrieb im Beitrag 
#3869501:
> Was ist überhaupt "löschen"?

In meinem Fall würde ich sagen, die Inhalte des Arrays komplett durch 
00ler verschieben, und anschließend das stringende Zeichen auf die 0te 
Position ganz links setzen.

Das würde ich jetzt übrigens auch ausprobieren, vielleicht liegt es am 
Stringende Zeichen.

Übrigens, ich hatte das Programm schon fertig, in einen 
Zustandsautomaten, dort lief es einwandfrei, und ich musst weder was 
ändern, noch ein Stringende zeichen hinzufügen.
Nur ist es mit ca. 15 Zuständen nicht besonders komfortabel lesbar.

Mfg (und noch am ausprobieren)
tommyProg

von Tho W. (tommyprog)


Lesenswert?

Siebzehn Zu Fuenfzehn schrieb:
> a[0]=0;
> a[1]=0;
> a[2]=0;
> a[3]=0;

Mit der Methode funktioniert es auch nicht.

von Tho W. (tommyprog)


Angehängte Dateien:

Lesenswert?

So, also ich habe nun ein Stringende Zeichen bei den passenden Stellen 
ergänzt, und nun funktionieren wenigstens die Werte von 1-99 einwandfrei 
und überschreiben sich nichtmehr.

Code im Anhang.

Die 4te Position habe ich allerdings noch nicht belegt.
Nun, höchstwahrscheinlich ist genau da der Fehler.
Ich muss ihn sagen, dass, wenn die 5te Position keine Zahl ist, schreibe 
ein Stringende Zeichen auf die 3te Position meines Arrays (4.stelle).

Danke Karl übrigens für die Idee, den unteren Code
mit
1
while( 1 )
2
  {
3
    char c = next Character from Uart if one exists
4
5
    switch( state )
6
    {
7
      case ExpectCommand:
8
        if( c = 'P' )
9
        {
10
          state = ExpectPWMNumber;
11
          PWMValue = 0;
12
         ...

kann ich aber garnicht lesen, ich weiß nicht zu 100% Sicherheit, was das 
if da auf meine Laufzeit bewirkt. (das schaue ich aber demnächst auch 
mal an, weil es schon viel kürzer ist) Aktuell prüfe ich jetzt noch mal 
die 5te stelle des arrays.
Danke übrigens euch allen für die schnellen Antworten ;)

Mfg,
tommyProg

von Tho W. (tommyprog)


Lesenswert?

Tho Wes schrieb:
> So, also ich habe nun ein Stringende Zeichen bei den passenden Stellen
> ergänzt, und nun funktionieren wenigstens die Werte von 1-99 einwandfrei
> und überschreiben sich nichtmehr.
>
> Code im Anhang.
>
> Die 4te Position habe ich allerdings noch nicht belegt.
> Nun, höchstwahrscheinlich ist genau da der Fehler.
> Ich muss ihn sagen, dass, wenn die 5te Position keine Zahl ist, schreibe
> ein Stringende Zeichen auf die 3te Position meines Arrays (4.stelle).
>
> Danke Karl übrigens für die Idee, den unteren Code
> mit
>
1
> while( 1 )
2
>   {
3
>     char c = next Character from Uart if one exists
4
> 
5
>     switch( state )
6
>     {
7
>       case ExpectCommand:
8
>         if( c = 'P' )
9
>         {
10
>           state = ExpectPWMNumber;
11
>           PWMValue = 0;
12
>          ...
13
>
>
> kann ich aber garnicht lesen, ich weiß nicht zu 100% Sicherheit, was das
> if da auf meine Laufzeit bewirkt. (das schaue ich aber demnächst auch
> mal an, weil es schon viel kürzer ist) Aktuell prüfe ich jetzt noch mal
> die 5te stelle des arrays.
> Danke übrigens euch allen für die schnellen Antworten ;)
>
> Mfg,
> tommyProg

So, also die Überprüfung auf die Stelle habe ich nun implementiert und 
getestet, und nun läufts einwanfrei, nur muss ich es noch vereinfachen.
Da hatte ich mal so eine schöne for-schleife...

Ehm, eine Frage von der Logik her:
Bei einem Zustandsautomaten mit 15 (fast einzelnen Zuständen) musste ich 
kein Stringende zeichen auf die jeweilige Position einfügen, und das 
Programm lief enormst stabil.

Nun ist es so, dass ich ein Stringende Zeichen einfügen muss, wenn ich 
12 Zustandsautomaten zu einen "reinen" programmcode mache.
Warum ist das so?

mfg,
tommyProg

von Eric B. (beric)


Lesenswert?

Peter II schrieb:
> Eric B. schrieb:
>>> zwischenzustand_array[ZWISCHENZUSTAND_ARRAY_SIZE] = { 0 };
>>
>> Das ist Quatsch. Du brauchst entweder:
>
> warum sollte das Quatsch sein?

Weil man ein einzelnes Element ausserhalb vom Array nicht ein 
komplettes Array zuweisen soll.

von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

>       case ExpectCommand:
>         if( c = 'P' )
>         {
>           state = ExpectPWMNumber;
>           PWMValue = 0;
>          ...
> [/c]
>
> kann ich aber garnicht lesen, ich weiß nicht zu 100% Sicherheit, was das
> if da auf meine Laufzeit bewirkt.

Das ist auch ein Fehler, der dem Tippen im Forum geschuldet ist.
Da sollte eigentlich ja auch
1
         if( c == 'P' )
stehen :-)

Und wegen Laufzeit.
Ganz ehrlich: Bei dem Käse, den du da zusammenprogrammierst, solltest du 
dir um Laufzeit überhaupt noch keine Sorgen machen. Denn egal was du als 
Alternative machst, noch schlimmer kann man das schon fast nicht mehr 
programmieren.

von Tho W. (tommyprog)


Lesenswert?

> Das ist auch ein Fehler, der dem Tippen im Forum geschuldet ist.
> Da sollte eigentlich ja auch
>
1
>          if( c == 'P' )
2
>
> stehen :-)

> Und wegen Laufzeit.
> Ganz ehrlich: Bei dem Käse, den du da zusammenprogrammierst, solltest du
> dir um Laufzeit überhaupt noch keine Sorgen machen. Denn egal was du als
> Alternative machst, noch schlimmer kann man das schon fast nicht mehr
> programmieren.

Okay, das sehe ich als kompliment an, weil dann heißt das ja, dass ich 
nurnoch besser werden kann xD.

Aber warum muss ich die Stringende Zeichen seperat ergänzen, wenn ich 
einen Zustandsautomaten "aufspalte"?

von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

> Aber warum muss ich die Stringende Zeichen seperat ergänzen, wenn ich
> einen Zustandsautomaten "aufspalte"?

Du musst das Stringende IMMER ergänzen, wenn du einen String aus 
einzelnen Zeichen zusammensetzt! Es sei denn in den Zeiten, die du 
zusammensetzt ist das Stringende-'\0' schon mit drinn. Trotzdem wird man 
eher auf Nummer sicher gehen. Die paar Taktzyklen kosten nichts.

> Okay, das sehe ich als kompliment an, weil dann heißt das ja, dass
> ich nurnoch besser werden kann xD.

Nimms nicht tragisch. Mein erster Sortieralgorithmus war auch furchtbar. 
Kryptisch, komplex unwartbar und wenn der Mond günstig gestanden ist, 
hat er sogar funktioniert. Allerdings hab ich dann schnell gelernt, wie 
man sowas richtig macht. Lange bevor ich mein erstes richtiges Projekt 
begonnen habe. Aber das macht nichts. Selbst für ein Übungsprogramm war 
er fuchtbar, kryptisch und unwartbar - sprich inakzeptabel. Nachdem ich 
gesehen habe, wie man sowas richtig und vernüftig angeht, war mir auch 
klar, dass mir noch viel fehlt, ehe ich an ein echtes Projekt auch nur 
denken kann.

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.