Forum: Compiler & IDEs Wie vorgehen beim String einlesen?


von Ludwig (Gast)


Lesenswert?

Hallo,

wie sollte ich vorgehen wenn ich einen String einlesen will.

z.B. der String in hex sieht so aus

AA BB 04 01 02 03 04 22

dabei ist
AA BB = Startzeichen
04 = die länge der daten
22 = checksumme

wie solle ich nun vorgenen wenn ich den String empfange.

Komplett einlesen und danach aus werten?

oder während des rinlesens auf AA BB prüfen und dann den rest erst 
weiterverwerten?

von Coder (Gast)


Lesenswert?

Pauschal würde ich sagen, mach es so wie es am besten passt. Haengt von 
deiner Software ab.

von TipTopTip (Gast)


Lesenswert?

Also ich würde so spontan gesehen auf AA BB warten, dann die Länge 
auswerten und Speicher für die Daten besorgen, um dann, wenn alle Daten 
empfangen sind, die Prüfsumme auzuwerten.

von Hmm (Gast)


Lesenswert?

Da AA BB auch in den Daten auftauchen kann (sieht jedenfalls so aus) 
dann ist das als Kennzeichen eine schlechte Wahl. Nimm lieber ein 
Zeichen das keine Hex-Ziffer ist.

von Ludwig (Gast)


Lesenswert?

ok, danke für die tipps

Habe jetzt mal weitergemacht und versuche nun den String komplett zu 
empfangen dann zu analysieren und auf Gültigkeit zu prüfen.

mit dem Warten auf AA BB hatte ich zu erst versucht bin dann aber nicht 
weitergekommen da beim Uart empfangen dann immer ein zeichen verschluckt 
wurde, da es kein ende zeichen gibt ist das doof.

Jetzt habe ich noch ein doofes anders problem. In dem String wird auch 
hex 00 empfangen.
Die Uart routine steckt mir aber nicht 00 in den string sondern einfach 
garnichts, was kann ich da machen?

von Hmm (Gast)


Lesenswert?

Nimm eine andere Empfangsroutine, die 0x00 nicht als 
Stringendekennzeichen interpretiert. Ggf. implementiere eine eigene.

von Hmm (Gast)


Lesenswert?

>...da beim Uart empfangen dann immer ein zeichen verschluckt wurde...

Es gibt keinen plausiblen Grund das hinzunehmen. Untersuche warum da 
Zeichen verschluckt werden. Das kann Dir nämlich auch sonst an anderen 
Stellen der Übertragung passieren.

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:

> Die Uart routine steckt mir aber nicht 00 in den string sondern einfach
> garnichts, was kann ich da machen?


Aus der UART kommt ganz sicher auch ein Zeichen mit dem Hex-Wert 00 
raus. Die Frage ist dann was du weiter damit machst. Bedenke auch, dass 
ein C-String immer nur bis zum Zeichen mit dem Hex-Wert 0x00 geht. D.h. 
alle C-Stringfunktionen werten das als String-Ende Zeichen.


Wie sieht jetzt eigentlich dein String wirklich aus? Hast du wirklich 
Strings (also Texte) oder dann doch eher im weitesten Sine einfach nur 
Byte-Folgen?

von Ludwig (Gast)


Lesenswert?

Es ist die hier aus dem Tutorial:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART

Unten die Interrupt routine.

Da wird das aber nicht ausgewertet,

Zum testen gebe ich den string per printf aus kann es sein das der mit 
das 00 wegfrisst?

printf("%s", uart_string);

von Ludwig (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wie sieht jetzt eigentlich dein String wirklich aus? Hast du wirklich
>
> Strings (also Texte) oder dann doch eher im weitesten Sine einfach nur
>
> Byte-Folgen?

Ich habe Byte folgen also AA BB CC ... FF als Hex werte auf der Leitung, 
keine ascii zeichen.

von Ludwig (Gast)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:

> Ich habe Byte folgen also AA BB CC ... FF als Hex werte auf der Leitung,
> keine ascii zeichen.

ALso keine Strings.

> Es ist die hier aus dem Tutorial:

Und was willst du mit der?
Die ist für Strings ausgelegt.

> printf("%s", uart_string);

Auch das ist auf Strings ausgelegt.


Du hast keine Strings!

Du musst schon die Dinge trennen. Nicht alles was man in einem 
char-Array speichert (oder in einem uart8_t Array) kann wie ein String 
behandelt werden. Wenn du keine Strings hast, dann hast du keine und es 
ist grundfalsch da mit Stringmethodik ranzugehen.

von Ludwig (Gast)


Lesenswert?

ok, also die Tut Routine empfängt das 0x00.

ich habe noch die zeile auskommentiert:
//uart_string[uart_str_count] = '\0';

und das char geändert.
volatile unsigned char uart_string[UART_MAXSTRLEN +1] = "";

Da drinnen liegen nun auch sauber die 00er

Die echte länge der empfangenen Zeichen weiß ich wenn ich erst alles 
empfangen will ja erst dann wenn ich alles empfangen habe, das 
uart_str_complete setzte ich einfach nach 20ms.

nun ist aber der String mit
#define UART_MAXSTRLEN 30
eingestellt und empfangene Zeichen sind es z.b. 18, es werden aber nie 
mehr als 30.

Kann ich nun uart_string irgendwie abschneiden auf die 18 oder müsste 
ich einen neue variable machen und die dann dementsprechenend lang 
machen und dann übergeben?

Das Problem ist das sizeof(uart_string) dann immer 30 ist.

von Hmm (Gast)


Lesenswert?

Das sind meiner Meinung nach nur Workarounds. Du musst bedenken, das 
diese Routinen dafür gedacht sind Bytefolgen mit Endekennzeichen zu 
empfangen.

Das einzige Kennzeichen für die Länge ist das Längenbyte.
Das einzige Kennzeichen für den Anfang ist 0xAA 0xBB.

Du musst also eine eigene Routine schreiben, die diese auswertet.
Dabei aber das Problem beachten, das ich schon oben genannt habe. 0xAA 
0xBB kann auch in den Daten vorkommen. Suche Dir ein anderes Zeichen für 
den Telegrammbeginn das in den Daten nicht vorkommt.

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:

> Die echte länge der empfangenen Zeichen weiß ich wenn ich erst alles
> empfangen will ja erst dann wenn ich alles empfangen habe

?

Steht doch in deinen Daten drinn!

> AA BB 04 01 02 03 04 22
>
> dabei ist
> AA BB = Startzeichen
> 04 = die länge der daten
> 22 = checksumme

Hier. Das 3.te Byte ist die Länge der Daten. Damit ist auch klar, 
wieviele Bytes danach noch kommen werden. Nämlich diese Anzahl und dann 
noch 1 Byte für die Checksumme.


> Kann ich nun uart_string irgendwie abschneiden auf die 18 oder müsste
> ich einen neue variable machen und die dann dementsprechenend lang
> machen und dann übergeben?

Du musst dir einfach nur eine zusätzliche Variable machen, in der du die 
Länge der Daten ablegst.

Bei Strings brauchst du das nicht, weil dir das \0 Byte in den Daten 
verrät, wie lang der String ist.
Aber - du errätst es schon - du hast keine Strings.

Also musst du 2 Informationen haben:
Einmal die Daten selbst, in dem sie in einem uint8_t Array abgelegt 
werden.
Und zum zweiten, wie lang diese Daten sind. Und wie lang die sind, das 
hat dir der Absender das Daten dankeswerterweise ja mitgeteilt.

> Das Problem ist das sizeof(uart_string) dann immer 30 ist.

Nein. Das Problem ist, dass du ganz dringend ein C-Buch brauchen 
würdest, aber keines hast.

von Hmm (Gast)


Lesenswert?

sizeof hat zwei Semantiken, die aber nichts mit dem momentanten Inhalt 
einer Variablen zu tun haben.

Was Du meinen würdest, wenn Du es wüsstest, ist strlen. Das aber kannst 
Du nicht gebrauchen, weil Du keine Strings verarbeitest.

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:
> ok, also die Tut Routine empfängt das 0x00.

Nochmal zum mitmeisseln:

Mit dieser Routine kannst du nichts anfangen. Die geht von ganz anderen 
Voraussetzungen aus.
Ob du willst oder nicht, aber du wirst dir wohl oder übel selbst was 
schreiben müssen. Es ist doch alles da, wo liegt denn das Problem dabei 
diese Pipifax-Empfangsroutine zu schreiben?

von Ludwig (Gast)


Lesenswert?

Ja das wäre sauberer, Bin dann aber leider nicht mehr weitergekommen.

Wie sollte ich vorgehen um das AA BB zu erkennen, wenn ich 
UART_MAXSTRLEN auf 2 setzte wir der 3. Wert weschluckt also der 3. 
aufruf des Interrupts.
Dann wollte ich den 3. Wert gleich in eine Variable stecken und 
UART_MAXSTRLEN auf den wert setzen, das gibt dann eine redefine warning 
im compiler (wie kann ich den String mit der Länge "herrichten").

Dann denke ich mir immer wenn ich während dem Empfangen mich so 
verkünstel und dann schon gleich nach AA BB das nächste Zeichen kommt 
der Prozessor mit dem "herrichten" der variable noch nicht fertig ist 
wenn der Interrupt kommt, oder kann das nicht passieren?
Empfangen wird mit 19200 der Mega32 läuft mit 14,7456MHz.

Wenn dann AA BB in den Daten kommt ich aber noch z.b. 5 werte lesen muß 
ist es ja klar das AA BB in den Werten ist.

von Ludwig (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es ist doch alles da, wo liegt denn das Problem dabei
>
> diese Pipifax-Empfangsroutine zu schreiben?

Wenn ich wüsste wie bräuchte ich nicht zu fragen. Ich weiß ja nichtmal 
wiso es mit der nicht gehen sollte.

von Hmm (Gast)


Lesenswert?

Du kannst schon ein Array fester Länge verwenden, falls Du weisst, das 
gültige_ Telegramme eine Maximallänge _nie überschreiten. Trotzdem 
prüfen ob die Länge auch passt und falls nicht den Rest ignorieren.

Du kannst eine Konstante im Programm nicht ändern.

>...gleich nach AA BB das nächste Zeichen kommt
>der Prozessor mit dem "herrichten" der variable noch nicht fertig ist
>wenn der Interrupt kommt

Das Problem hast Du im speziellen nicht, wenn Du ein Array fester Länge 
nimmst. Im allgemeinen hast Du es nicht, weil die UART Übertragung im 
Vergleich zur Ausführungsgeschwindigkeit eines malloc gähnend langsam 
ist.

>Wenn dann AA BB in den Daten kommt ich aber noch z.b. 5 werte lesen muß
>ist es ja klar das AA BB in den Werten ist.

Das ist zwar richtig, setzt aber voraus, das Du immer das anfängliche 
0xAA 0xBB mitbekommst. Aber es kann auch mal Übertragungsfehler geben. 
Dann ist das 0xAA 0xBB, das Du siehst eigentlich Teil der Nutzlast und 
wenn dann zufällig noch das Längenbyte und die Checksumme stimmt (was 
zugegebenermaßen wenig wahrscheinlich ist), dann hast Du den Salat.
Das ist kein guter Stil sich darauf zu verlassen, das schon alles gut 
wird.

Na, den Rest wird K.H. schon richten. :-)

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:

> Wie sollte ich vorgehen um das AA BB zu erkennen, wenn ich
> UART_MAXSTRLEN auf 2 setzte wir der 3. Wert weschluckt also der 3.
> aufruf des Interrupts.
> Dann wollte ich den 3. Wert gleich in eine Variable stecken und
> UART_MAXSTRLEN auf den wert setzen, das gibt dann eine redefine warning
> im compiler (wie kann ich den String mit der Länge "herrichten").

Oh Mann. Bei dir fehlts aber auch an allen Ecken und Enden an den 
Grundlagen.

Das Array lässt du auf den 30, die kannst du sowieso zur Laufzeit nicht 
ändern.
Dann machst du dir eine 2. Variable, die die Anzahl der gültigen Bytes 
im Array halten wird.

Weiters machst du dir einen Empfangsstatus. Den brauchst du, damit du 
auf den Datenanfang sauber synchronisieren kannst.
Am Anfang ist der Empfangscode im Status 'wartend'. Wird das 0xAA 
gesehen dann geht die ISR in den Status 'erstes Sync-Byte gesehen'. Ist 
das nächste Byte kein 0xBB dann geht der Status wieder zurück auf 
'wartend'. Ansonsten gehts weiter in den Status 'Längenbyte lesen'. Beim 
nächsten ISR Aufruf landet daher das nächste Byte in einer Variablen, 
die angibt, wieviele bytes ab jetzt noch kommen werden und die Daten 
bilden. Der Status wechselt zu 'Daten lesen'. Ab jetzt wird 1 Byte nach 
dem anderen ins Array geschrieben. Solange bis alle Datenbytes da sind. 
Nach Empfang des letzten Datenbytes geht der Status auf 'Checksumme'. 
Kommt dann das nächste Byte wird die Checksumme über die empfangenen 
Daten berechnet und mit der empfangenen Checksumme verglichen. Stimmen 
die beiden überein, dann werden die Daten im Array (samt zugehöriger 
Länge selbstverständlich) freigegeben und der Status wechselt wieder zu 
'wartend'.

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:


> Das ist zwar richtig, setzt aber voraus, das Du immer das anfängliche
> 0xAA 0xBB mitbekommst. Aber es kann auch mal Übertragungsfehler geben.
> Dann ist das 0xAA 0xBB, das Du siehst eigentlich Teil der Nutzlast und
> wenn dann zufällig noch das Längenbyte und die Checksumme stimmt (was
> zugegebenermaßen wenig wahrscheinlich ist), dann hast Du den Salat.
> Das ist kein guter Stil sich darauf zu verlassen, das schon alles gut
> wird.

Da hast du allerdings recht.

Daher die Frage: Wer sendet eigentlich die Daten? Wer hat das 
Übertragungsprotokoll festgelegt?
Kann man das ändern?

Wenn nicht, dann wird man wohl erst mal damit leben müssen.

(Hmm ... lass uns die Sache nicht zu kompliziert machen. Er hat momentan 
noch viel primitivere Probleme und mit 2 Sync-Bytes samt Checksumme ist 
die Wahrscheinlichkeit, wie du richtig sagst, nicht all zu hoch)

von Hmm (Gast)


Lesenswert?

>Ich weiß ja nichtmal wiso es mit der nicht gehen sollte.
Das wurde doch schon haarklein erklärt. Lies einfach nochmal die 
Antworten und frag nach wenn Du daran etwas nicht verstanden hast.

von Hmm (Gast)


Lesenswert?

@ K.H.
Ja gut. Lassen wir das erstmal weg. Hab mich schon gewundert, das Du 
darüber nichts schrubst.

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:

> Ich weiß ja nichtmal
> wiso es mit der nicht gehen sollte.

Weil du keine Strings hast!

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:
> @ K.H.
> Ja gut. Lassen wir das erstmal weg. Hab mich schon gewundert, das Du
> darüber nichts schrubst.

Jep. Ich seh auch ein, dass man nicht alles gleichzeitig lernen kann 
(obwohl ich es immer frustrierend finde, wenn ....   das erinnert mich 
immer an die Auswanderer-Serien im Fernsehen, in denen Leute ohne die 
Sprache zu können noch xxxx auswandern und sich dann wundern warum man 
sie nicht gleich von der Strasse weg .... lassen wird das).

Bist du einverstanden, mit dem Versuch mit ihm eine State-Machine 
aufzubauen. Irgendwann muss er ja schliesslich die Technik auch mal 
sehen. Da hat er dann wenigstens ein universelles Hilfsmittel, mit dem 
er auch in Zukunft viel erschlagen kann.

von Hmm (Gast)


Lesenswert?

@ K. H.

>...State-Machine...
Klar.
Mache ich in solchen Fällen fast immer so. Wenn auch in 
unterschiedlichen Varianten. In solchen Fällen (vier Zustände schätze 
ich mal) einfach nur ein kleiner switch oder auch nur if-then-else.

@ Ludwig
Bist Du eigentlich noch da? Hey, alles keine grosse Sache. Das haben wir 
alle mal durchgemacht. Nur Mut.

von Ludwig (Gast)


Lesenswert?

Ja, klar noch da, aber ich tue mich halt ewas schwerer, bin schon über 
35 ;)

Von der Logical-State-Machine hab ich schonmal was gehört, mehr aber 
auch nicht. Leider habe ich niemand im Bekanntenkreis der sich damit 
auskennen könnte.

von Hmm (Gast)


Lesenswert?

Also:

Nehmen wir mal an Du hättest die bittere Pille schon geschluckt, das es 
sich hier nicht um Strings handelt.

Karl Heinz hat Dir hier 
Beitrag "Re: Wie vorgehen beim String einlesen?" mal so einen Ablauf 
skizziert. Damit erschlägst Du eigentlich alle Fehlerfälle aber 
natürlich den gewünschten Fall auch. Ist das für Dich soweit 
verständlich? Wenn nicht, dann frage einfach.

von Ludwig (Gast)


Lesenswert?

Ich frage ja auch nicht nach ner fertiglösung, ich möchte mich schon 
sleber damit befassen. Habe auch das Kernighan und Dennis Ritchie C Buch 
hier, aber es ist halt nicht so einfach wie früher das C64 Basic.

von Hmm (Gast)


Lesenswert?

>...bin schon über 35 ;)

Lach. Ich bin 49. Alter ist keine Entschuldigung, mein Lieber.

>Von der Logical-State-Machine hab ich schonmal was gehört, mehr aber
>auch nicht. Leider habe ich niemand im Bekanntenkreis der sich damit
>auskennen könnte.

Das macht überhaupt nichts. Wir sprechen Dich da durch. Hast Du die 
Erklärung von Karl Heinz hier 
Beitrag "Re: Wie vorgehen beim String einlesen?" ein wenig verstehen 
können?

von Hmm (Gast)


Lesenswert?

>Ich frage ja auch nicht nach ner fertiglösung, ich möchte mich schon
>sleber damit befassen.

OK. Das sollst Du ja auch. Du wirst schon Dein Gehirnschmalz dafür 
brauchen.
Es ist halt so, das die Methoden die Du versucht hast, auf falschen 
Voraussetzungen basieren. Also musst Du was Neues lernen, oder?

von Hmm (Gast)


Lesenswert?

Scaramanga sucht auch immer neue Herausforderungen. Grins.

von Ludwig (Gast)


Lesenswert?

Hmm schrieb:
> Das macht überhaupt nichts. Wir sprechen Dich da durch. Hast Du die
>
> Erklärung von Karl Heinz hier
>
> Beitrag "Re: Wie vorgehen beim String einlesen?" ein wenig verstehen
>
> können?

Ja ich sage mal generell weiß ich wie es funktionieren soll, auch das 
Übertragungsfehler abgefangen werden sollten und die Logic an sich ist 
nicht das problem, nur wie ich das in C in ein Program bekomme ist 
schwierig für mich.

von Ludwig (Gast)


Lesenswert?

Eine Sende Routine konnte ich für mein Beispiel anpassen. Dort werden 
die Befehle die ich schicke so im Programm hinterlegt:
const unsigned char Cmd_GetCSN[]       ={0x00,0x00,0x00,0x02,0x02,0x00};

Das Senden an sich funktioniert, es wird einfach jedes Wort mit einem 
Pointer an das uart gegeben und gewartet bis das nächste darf, das geht 
solange bis die länge durch ist.

Wo ist aber nun der Unterschid zwischen einem String und dem oben 
Cmd_GetCSN is das dann ein Array?

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:
>>...bin schon über 35 ;)
>
> Lach. Ich bin 49. Alter ist keine Entschuldigung, mein Lieber.

:-)
50


>>Von der Logical-State-Machine hab ich schonmal was gehört, mehr aber
>>auch nicht. Leider habe ich niemand im Bekanntenkreis der sich damit
>>auskennen könnte.
>
> Das macht überhaupt nichts. Wir sprechen Dich da durch. Hast Du die
> Erklärung von Karl Heinz hier
> Beitrag "Re: Wie vorgehen beim String einlesen?" ein wenig verstehen
> können?


Ich denke, da braucht man noch eine Erläuterung dazu.
Denn die Beschreibungen klingen immer so hochtrabend. Aber eigentlich 
ist es ganz einfach.

Der Status ist einfach nur eine Variable. Da es nur wenige Zustände 
sind, ein uint8_t. Die die einzelnen Zustände sind verschiendene Werte, 
die die Variable annehmen kann.

Also zb
1
// die möglichen Zustände
2
#define WAITING    0
3
#define FRST_SYNC  1
4
#define LENGTH     2
5
#define DATA       3
6
#define CHECKSUM   4
7
8
volatile uint8_t uartDataBytes[30];
9
volatile uint8_t uartDataLength;
10
11
ISR( ... )
12
{
13
  // Am Anfang ist der Empfangscode im Status 'wartend'.
14
  static uint8_t uartStatus = WAITING;
15
  static uint8_t dataBytesToRead; 
16
17
  uint8_t nextByte = UDR;
18
19
  // Am Anfang ist der Empfangscode im Status 'wartend'.
20
  // Wird das 0xAA gesehen dann geht die ISR in den Status
21
  // 'erstes Sync-Byte gesehen'.
22
  if( uartStatus == WAITING && nextByte == 0xAA )
23
    uartStatus = FRST_SYNC;
24
25
  // Ist dann das nächste Byte kein 0xBB dann geht der Status
26
  // wieder zurück auf 'wartend'.
27
  // Ansonsten gehts weiter in den Status 'Längenbyte lesen'.
28
  else if( uartStatus == FRST_SYNC ) {
29
    if( nextByte == 0xBB )
30
      uartStatus = LENGTH;
31
    else
32
      uartStatus = WAITING;
33
  }
34
35
  // Beim nächsten ISR Aufruf landet daher das nächste Byte in
36
  // einer Variablen, die angibt, wieviele bytes ab jetzt noch
37
  // kommen werden und die Daten bilden. Der Status wechselt
38
  // zu 'Daten lesen'.
39
  else if( uartStatus == LENGTH )
40
    ....
41
42
  ....
43
}

Die Variable uartStatus ist der 'Status' in der sich die Maschine 
befindet. und die verschiedene Werte annehmen kann. Abhängig von diesem 
Status wird das empfangene Byte untersucht und ausgewertet. Je nach 
Auswertung kann es dann einen neuen Status geben bzw. passiert irgendwas 
mit diesem Byte.

Spiel einfach deine Folge durch die ISR durch, indem du sie in Gedanken 
mehrfach aufrufst und dir vorstellst, dass dann jeweils immer das 
nächste Byte aus UDR rauskommt. Was muss damit passieren, wie muss die 
Statemaschine darauf reagieren?

Ach ja. In uartDataBytes und uartDataLength kommt dann letzten Endes das 
Ergebnis raus.

Und schreck nicht davor zurück, weitere Variablen einzuführen, wenn du 
sie brauchst! Was du brauchst, das brauchst du.
(dataBytesToRead wirst du brauchen. Wenn der Teil 'daten lesen' beginnt, 
dann schreibst du dort rein, wieviele Bytes noch kommen müssen und bei 
jedem nächsten byte wird die Variable dann einfach um 1 runtergezählt. 
Wird sie 0, dann sind logischerweise alle Datenbytes da und als nächstes 
kommt dann die Checksumme in ihrem eigenen Zustand)

von Hmm (Gast)


Lesenswert?

>nur wie ich das in C in ein Program bekomme ist schwierig für mich.

Aha. Gehen wir mal Karl Heinz' Beschreibung durch.

>Weiters machst du dir einen Empfangsstatus. Den brauchst du, damit du
>auf den Datenanfang sauber synchronisieren kannst.
Das Schlüsselwort ist hier "Status".
Das ist einfach eine Variable. Sie speichert den Zustand (ein anderes 
Wort für Status) in dem die "Empfangsmimik" sich gerade befindet.

>Am Anfang ist der Empfangscode im Status 'wartend'.
OK. Wie "codierst" Du, wie schreibst Du den Status "wartend"?
Am einfachsten wäre ein "enum". Kennst Du? Oder? Da Du den K&R hast, 
lies einfach nochmal nach.
Wir wollten ja eine Variable für den Status. Die Variable soll unter 
anderen den Status "wartend" enthalten können.

In C sieht das dann so aus:
1
enum EnumStatus { Wartend, <hier folgen noch andere Stati> } Status;

>Wird das 0xAA gesehen dann geht die ISR in den Status 'erstes Sync-Byte gesehen'.

Hier hast Du zwei Dinge. Einen neuen Status "erstes Sync-Byte gesehen". 
Den bastelst Du Dir gleich in die Deklaration.
1
enum EnumStatus { Wartend, ErstesSyncEmpfangen, <hier folgen noch andere Stati> } Status;

Und eine Anweisung, was zu geschehen hat.
1
if (GelesenesZeichen == 0xAA)
2
  Status = ErstesSyncEmpfangen;

Aber das darf natürlich nicht immer geschehen, wenn 0xAA gelesen wird, 
da das ja auch in den Daten vorkommen kann. Das darf nur im Status 
"wartend" geschehen.
Also musst Du das noch prüfen.
1
if (Status == Warten)
2
  if (GelesenesZeichen == 0xAA)
3
    Status = ErstesSyncEmpfangen;

Versuche mal den nächsten Schritt einfzufügen, bitte.
>Ist das nächste Byte kein 0xBB dann geht der Status wieder zurück auf
'wartend'. Ansonsten gehts weiter in den Status 'Längenbyte lesen'.

Verdammt, bei der Vorschau sehe ich, das Karl Heinz auch schon was 
geschrieben hat. :-)

von Hmm (Gast)


Lesenswert?

@ Karl Heinz

>:-)
>50

Lach. Noch so ein alter Sack. :-)

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:


> Verdammt, bei der Vorschau sehe ich, das Karl Heinz auch schon was
> geschrieben hat. :-)

Ja, wir bewegen uns aufs gleiche hin. Die Variablen heissen anders und 
du hast einen enum benutzt. Aber das ist alles unter "ferner liefen."

Das Prinzip ist EXAKT dasselbe.
(Das sollte dir Ludwig durchaus etwas sagen :-)

(und auch ich habe natürlich nicht alles ausformuliert :-)

von Hmm (Gast)


Lesenswert?

Das mit den Defines für die Stati ist in gewisser Weise einfacher. Wenn 
Du es vorziehst, dann nimm das. Das Prinzip ist das selbe.

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:
> @ Karl Heinz
>
>>:-)
>>50
>
> Lach. Noch so ein alter Sack. :-)

ALso das 'alt' nimmst du zurück!
(Der Sack geht in Ordnung)

von Ludwig (Gast)


Lesenswert?

Ok, ich versuche es zu verstehen :)

> #define WAITING    0
Schreibt hier der (compiler/präprozessor) überall wo WAITING steht eine 
0 rein? Dient das also nur der Übersichtlichkeit?

Man setzt also Bedingungen geknüpft an einen neue Bedingung um in den 
nächsten Status zu kommen, ok denke verstanden.

Nun aber ab ins Bett.

von Ludwig (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Hmm schrieb:
>
>> @ Karl Heinz
> >>>:-)
>
>>>50
> >> Lach. Noch so ein alter Sack. :-)
> > ALso das 'alt' nimmst du zurück!
>
> (Der Sack geht in Ordnung)

Wenigstens weiß ich jetzt wie alt ich werden muss um es zu verstehen ;)

von Hmm (Gast)


Lesenswert?

>Schreibt hier der (compiler/präprozessor) überall wo WAITING steht eine
>0 rein? Dient das also nur der Übersichtlichkeit?

Ja. Genau so ist es.

>Man setzt also Bedingungen geknüpft an einen neue Bedingung um in den
>nächsten Status zu kommen, ok denke verstanden.

Im Prinzip ja. Leider nicht ganz exakt ausgedrückt, denn eine "neue" 
Bedingung gibt es hier nicht.

Besser wäre es wenn Du Dir folgendes denkst:

Du gehst davon aus, das ein gewisser Zustand besteht. Diese 
Voraussetzung schreibst Du auf und teilst sie dem Compiler mit, indem Du 
sie als bedingte Anweisung, eben ein "if" schreibst.

Von diesem Zustand aus gibt es unter bestimmten zusätzlichen Bedingungen 
Übergänge zu einem neuen Zustand. Auch das schreibst Du als bedingte 
Anweisung.

>Nun aber ab ins Bett.

Wie jetzt? Jetzt geht die Programmierernacht erst los. :-)

von Hmm (Gast)


Lesenswert?

@ Karl Heinz

>ALso das 'alt' nimmst du zurück!

Ist hiermit zurückgenommen. Nur ein alter und ein Sack hier :-)

von Hmm (Gast)


Lesenswert?

> Wenigstens weiß ich jetzt wie alt ich werden muss um es zu verstehen ;)

Naja. Vielleicht bin ich ja auch langsam.

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:
> Ok, ich versuche es zu verstehen :)
>
>> #define WAITING    0
> Schreibt hier der (compiler/präprozessor) überall wo WAITING steht eine
> 0 rein? Dient das also nur der Übersichtlichkeit?

Das sind Präprozessor Makros.
Und ja, das sind einfach nur Textersetzungen. So wie du in deinem Editor 
ein 'Ersetzen' hast. Der Clou ist, dass diese 'Textverarbeitung' vom 
'Compiler' gemacht wird und zwar bevor er sich dann das Ergebnis dieser 
Ersetzungen vorknöpft.

Du solltest wirklich deinen K&R durcharbeiten. So ungefähr bis zum 
ersten Drittel. Dieser Wissensumfang ist so ungefähr das Minimum dessen, 
was man beherrschen muss, wenn man echte Programme schreiben will (und 
nicht nur kleinere Übungen). Alles darunter ist im Grund indiskutabel. 
Das ist wie auswandern in die USA und nur 3 Worte Englisch können.


> Man setzt also Bedingungen geknüpft an einen neue Bedingung um in den
> nächsten Status zu kommen, ok denke verstanden.

Ganz genau.

Wie eine Maschine.
Die ist in einem Zustand. Dann passiert irgendwas (eine Münze wird 
eingeworfen, der Benutzer tritt gegen die Maschine, Hochwasser kommt, 
... also im weitesten Sinne: die Maschine bekommt Input) und als Folge 
davon macht die Maschine irgendwas (ein Türchen geht auf, die 
Cola-Flasche wird freigegeben, ein Licht geht an, .... sie produziert 
Output). Und die Maschine kann dann in einen anderen Zustand übergehen 
(muss sie aber nicht).


Wobei man auch den Begriff 'Maschine' sehr weit fassen kann. Auch ein 
Rollo kann eine Maschine sein. Es hat zb 4 Zustände.
Das Rolle kann
* oben sein
* gerade rauffahren
* unten sein
* gerade runtenfahren

Input in die Maschine, sind Benutzereingaben, mit denen der Benutzer 
mitteilt ob das Rollo rauf oder runter fahren soll. WEiters ist ein 
Input der Endschalter oben/unten, mit dem die Maschine feststellt, ob 
der Motor, der die ganze Zeit das Rollo nach oben gekurbelt hat, 
abgestellt werden muss und die Maschine von 'ich fahre gerade rauf' in 
den Zustand 'bin oben' übergeht.


Es geht einfch nur um die Organisation, die einen komplexeren 'Ablauf' 
in Zwischenstufen zerlegt. Dabei festlegt, durch welchen Input der 
Übergang von einer Zwischenstufe in die nächste erfolgen soll und welche 
Aktionen dabei passieren soll.

von Ludwig (Gast)


Lesenswert?

Hmm schrieb:
> Wie jetzt? Jetzt geht die Programmierernacht erst los. :-)

Ja ich weiß ein Tag hat 24 Stunden und wenn das nicht reicht nimmt noch 
die Nacht dazu :)

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:

>>Nun aber ab ins Bett.
>
> Wie jetzt? Jetzt geht die Programmierernacht erst los. :-)

Das junge Gemüse hält auch nichts mehr aus.
Ja, damals, als ich noch jung war .....
:-) :-) :-)

von Ludwig (Gast)


Lesenswert?

Was mir noch nicht gefällt, die States sollten zeitlich überwacht sein 
damit das ganze nicht auf einem State kleben bleibt und zufällig 
weiterhoppelt.

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:
> Was mir noch nicht gefällt, die States sollten zeitlich überwacht sein
> damit das ganze nicht auf einem State kleben bleibt und zufällig
> weiterhoppelt.


Immer langsam mit den jungen Pferden.

Jetzt bringen wirs erst mal zum Laufen
Und dann kümmern wir uns um Fehlerbehandlung.

Denn Fehlerbehandlung hat die Tendenz den Code unübersichtlich zu machen 
und die Prinizpien zu verschleiern.

Auch einer der Vorteile von State-Maschines. Durch die gute Organisation 
bleibt es übersichtlich und man kann auch im Nachhinein noch relativ gut 
neue States einfügen.

von Hmm (Gast)


Lesenswert?

>> Was mir noch nicht gefällt, die States sollten zeitlich überwacht sein
> damit das ganze nicht auf einem State kleben bleibt und zufällig
> weiterhoppelt.

Wie Karl Heinz schon schrieb. Darum kümmern wir uns später. Im Prinzip 
aber ist ein Zeitablauf nichts weiter als eine zusätzliche Bedingung und 
ein zusätzlicher Übergang in der State-Machine; wie ein neues 
empfangenes Zeichen. Aber wiegeschrieben: Das kommt am Schluss.

von Hmm (Gast)


Lesenswert?

"Zufällig" weiterhoppeln aber kann es nach der Methode nicht. Es gibt 
genau beschriebene Bedingungen. Anders kann das Ding nicht. Wenn das 
doch passiert dann liegt es am Input.

von Ludwig (Gast)


Lesenswert?

Moin, hoffe da waren keine plünderer am Werk da viel gelöscht ist :)


>>  else if( uartStatus == FRST_SYNC ) {
>>    if( nextByte == 0xBB )
>>    uartStatus = LENGTH;
>>    else
>>    uartStatus = WAITING;
>>

Bisher habe ich immer

if(wenn erfüllt){
  mach das;
  }
  else {
  ansonsten das;
  }

geschrieben. Brauhe ich die {} nur wenn es mehr sache zu tun gibt, also 
bei mehr Zeilen?

else if = wenn das erste if nicht erfüllt gilt else if?

von Hmm (Gast)


Lesenswert?

>Moin, hoffe da waren keine plünderer am Werk da viel gelöscht ist :)

Nein. Alles OK. Da hat nur jemand Off-Topic geschwatzt.
1
if(wenn erfüllt){
2
  mach das;
3
  }
4
  else {
5
  ansonsten das;
6
  }

>Brauhe ich die {} nur wenn es mehr sache zu tun gibt, also
>bei mehr Zeilen?

Ja. Genau.

Du brauchst nur:
1
if(wenn erfüllt)
2
  mach das;
3
else
4
  ansonsten das;

Im K&R, 2. Auflage 1990, Prentice Hill ist das auf den Seiten 55 und 56, 
Kapitel 3 "Kontrollstrukturen" gezeigt. Man muss wissen, das ein if 
selbst nur eine einzelne Anweisung ist, genau wie while oder do oder 
switch etc.
Im Anhang ist in den Abschnitten A9. A9.3, A9.4. das Ganze nochmal 
formal d

von Hmm (Gast)


Lesenswert?

Ooops. Da hat sich wer verschluckt.

Es muss heissen:

Im Anhang ist in den Abschnitten A9. A9.3, A9.4. das Ganze nochmal
formal dargestellt.

von Hmm (Gast)


Lesenswert?

>else if = wenn das erste if nicht erfüllt gilt else if?

Etwas unglücklich ausgedrückt, aber ich schreib mal: Ja.

Man kann aber nicht eigentlich sagen, daß das "else if" gilt .

Zunächst folgt auf das else einfach nur eine Anweisung. Die wird 
ausgeführt, aber sie "gilt" nicht. Wenn diese Anweisung nun wiederum ein 
if ist, dann wird eben die Bedingung geprüft, aber sie gilt nicht.

Ich weiss ich bin ein alter Besserwisser, aber es ist letztlich nützlich 
auch in Gedanken nahe an den wirklichen Verhältnissen zu bleiben. 
Ansonsten denkst Du noch zwei Wochen, das die Anweisung nach dem else 
"gilt", d.h. das die Bedingung wahr ist und nicht das die Anweisung 
ausgeführt, die Bedingung geprüft wird.

von Ludwig (Gast)


Lesenswert?

Gerade noch gesehen das ich doch keinen K&R habe :(, ein bekannter 
damals hat mir das Buch gegeben und gesagt das es besser zu lesen sei 
das von K&R.
Ich habe das vom Herbert Schildt aus dem OsborneMcGraw-Hill Verlag:
"C THE COMPLETE REFERENCE"
isbn 0-07-881263-1

von Hmm (Gast)


Lesenswert?

Wenn Du fertig bist mit lesen, dann nimm am besten den Code von Karl 
Heinz hier Beitrag "Re: Wie vorgehen beim String einlesen?" und 
versuche ihn zu vervollständigen; also die nächsten Zustände und 
Übergänge zu schreiben

von Hmm (Gast)


Lesenswert?

>"C THE COMPLETE REFERENCE"

Kenne ich nicht. Aber wenn es gut ist, dann ist es ohnehin nur eine 
Paraphrase auf den K&R. Jedenfalls sollte es ein Kapitel über 
Kontrollstrukturen (if, while, do, switch) enthalten und eine formale 
Syntaxbeschreibung. Seitenzahlen kann ich Dir natürlich nicht angeben. 
Versuch es mal damit.
Online gibt es noch: http://openbook.galileocomputing.de/c_von_a_bis_z/

Ansonsten gilt: Andere Bücher sind nur Nachahmungen. :-)

von Ludwig (Gast)


Lesenswert?

Hmm schrieb:
> und
>
> versuche ihn zu vervollständigen

Gerade dabei, wird schon :), danke

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:
>>"C THE COMPLETE REFERENCE"
>
> Kenne ich nicht. Aber wenn es gut ist, dann ist es ohnehin nur eine
> Paraphrase auf den K&R.

KOmmt drauf an.
Ich hab jetzt mal die PDF Version des Schildt überflogen. Das Buch 
erhebt ganz sicher nicht den Anspruch, ein Lehrbuch zu sein, welchem man 
sich anvertraut, und das einen dann von Beginn weg systematisch und 
sacht durch die Untiefen der Sprache führt. Der Name ist Programm: Es 
ist mehr ein Nachschlagewerk. D.h. du musst schon wissen, wonach du 
suchst um es zu finden. Und dann erschlägt dich als Anfänger die dazu 
gebotene Informationsfülle (wie nicht anders zu erwarten). Das Buch ist 
wie ein fachspezifisches Lexikon: von der ersten Seite weg müsstest du 
das Buch bereits gelesen haben um zu verstehen, worüber es auf der 
ersten Seite geht.
Es ist, als ob man versuchen würde, mit dem Brockhaus Biologie zu 
erlernen. Und so wie der Brockhaus seine Berechtigung hat, hat auch 
dieses Buch seine Berechtigung. Aber ob die ausgerechnet in der 
Ausbildung eines Neueinsteigers liegt - da habe ich so meine Zweifel.

Über die Qualität der dargebotenen Information kann ich nach einem 
kurzen Überfliegen wenig sagen, sie scheint aber nicht allzugut zu sein, 
wenn ich einigen Kommentaren trauen darf. Wobei die angekreideten Dinge 
(die ich gesehen habe) für einen Wissenden nicht allzu gravierend sind. 
Worin der Fehler in
  double t;
  printf( "%f", sizeof t );
besteht, sollte jetzt niemanden groß aus der Bahn werfen, der mal 
schnell die eher selten gebrauchten Optionen im Format-String 
nachschlagen muss.

von Hmm (Gast)


Lesenswert?

>Aber wenn es gut ist, dann ist es ohnehin nur eine
> Paraphrase auf den K&R.

Naja. Eine nicht ganz ernst gemeinte Übertreibung. Aber für den Anfänger 
missverständlich. Ich nehme sie zurück.

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:
>>Moin, hoffe da waren keine plünderer am Werk da viel gelöscht ist :)
>
> Nein. Alles OK. Da hat nur jemand Off-Topic geschwatzt.

Ich hoffe du bist mir nicht böse. Aber wir waren zum Schluss schon 
soweit weg vom Thema .... des kompletten Forums, dass ....
Du weißt was ich geschrieben habe und ich weiß was du geschrieben hast. 
Und ich denke, das genügt unter uns Klosterschwestern :-)

von Hmm (Gast)


Lesenswert?

>Ich hoffe du bist mir nicht böse.

Aber keinesfalls. Im Gegenteil war mir das durchaus recht.
Ich habe das schon in dem Moment mitbekommen, wo Du gelöscht hast.

von Ludwig (Gast)


Lesenswert?


von Hmm (Gast)


Lesenswert?

>Ok, is das das original?
Ich kenne die Datei. Soweit ich weiss, ja. Die Kapitelbezeichnungen und 
Nummern sind gleich der in der Ausgabe vom Hanser-Verlag. Nur die 
Seitenzahlen weichen ab. Habe das allerdings nie erschöpfend 
kontrolliert.

von Oliver R. (roliver)


Lesenswert?

Hi,

ich habe diesen Code gefunden, und der geht bis jetzt gut. Das 
Beginzeichen ist ein '!' in diesem Fall.
1
char buffer[7];
2
int buffer_pos = 0;
3
int befehl = 0;
4
volatile int address = 0;
5
volatile int befehl_fertig = 0;
6
7
SIGNAL (SIG_UART_RECV)
8
{
9
  char data;  
10
  data = UDR;
11
  if (data == '!')
12
   {
13
     befehl = 1;
14
     address = 0;
15
     return;
16
   }
17
  else
18
   {
19
     if(befehl == 1 && address == 0)
20
     if (data == 'c') //meine Adresse ?
21
       {
22
  buffer[buffer_pos] = data;
23
  buffer_pos++;
24
  address = 1;
25
  return;
26
       }
27
      else
28
       {
29
   befehl = 0;
30
   address = 0;
31
   return;
32
       };
33
    };  
34
    if(befehl == 1 && address == 1)
35
     {
36
  buffer[buffer_pos] = data;
37
  if (buffer_pos < 5)  //Frei im Buffer ?
38
   {
39
     buffer_pos++;  //Zeiger++
40
     return;
41
   }
42
  else
43
   {
44
     buffer_pos = 0; //Wenn Buffer voll, reset an Anfang 
45
     befehl = 0;     //Befehl fertig...
46
     address = 0;
47
     buffer[6] = '\0'; //Sing abschluss, meine befehle sind nur 5 Zeichenlang
48
           befehl_fertig = 1;
49
     return;
50
   };
51
     };
52
  };
53
};

in Main, warten auf befehl_fertig = 1;
1
viod main (void)
2
...
3
4
while[1]
5
if (befehl_fertig == 1)              
6
 {
7
   if(strcmp(buffer, "clmx00") == 0)        
8
    {                     
9
      itoa (read2ADC(0), outs, 10);
10
      strcat (outs, "OK\n");
11
      rs485_puts('a', outs);
12
    };  
13
befehl_fertig = 0;  
14
...

Gruss

Oliver

von Ludwig (Gast)


Lesenswert?

danke aber ich bin schon beim berechnen der checksumme, wird schon.

von Ludwig (Gast)


Lesenswert?

So hier nun das was schonmal das tut was es soll :)
1
ISR(USART_RXC_vect)
2
{
3
  // Am Anfang ist der Empfangscode im Status 'wartend'.
4
  static uint8_t uartStatus = WAITING;
5
  static uint8_t dataBytesToRead;
6
  uint8_t nextByte = UDR;
7
8
  // Am Anfang ist der Empfangscode im Status 'wartend'.
9
  // Wird das 0xAA gesehen dann geht die ISR in den Status
10
  // 'erstes Sync-Byte gesehen'.
11
  if( uartStatus == WAITING && nextByte == 0xAA )
12
  uartStatus = FRST_SYNC;
13
14
  // Ist dann das nächste Byte kein 0xBB dann geht der Status
15
  // wieder zurück auf 'wartend'.
16
  // Ansonsten gehts weiter in den Status 'Längenbyte lesen'.
17
  else if( uartStatus == FRST_SYNC ) {
18
    if( nextByte == 0xBB )
19
    uartStatus = LENGTH;
20
    else
21
    uartStatus = WAITING;
22
  }
23
24
  // Beim nächsten ISR Aufruf landet daher das nächste Byte in
25
  // einer Variablen, die angibt, wieviele bytes ab jetzt noch
26
  // kommen werden und die Daten bilden. Der Status wechselt
27
  // zu 'Daten lesen'.
28
  else if( uartStatus == LENGTH ){
29
    dataBytesToRead=nextByte;
30
    uartStatus=DATA;
31
  }
32
33
34
  else if( uartStatus == DATA && uartDataCount < dataBytesToRead ){
35
      uartDataBytes[uartDataCount]=nextByte;
36
      uartDataChkChk=uartDataChkChk^nextByte;
37
      uartDataCount++;
38
      if (uartDataCount == dataBytesToRead)
39
        uartStatus=CHECKSUM;
40
    }
41
    
42
  else if( uartStatus == CHECKSUM ){
43
    if (nextByte == uartDataChkChk){
44
      uartDataComplete=1;
45
      uartDataCount=0;
46
      uartDataChkChk=0;
47
      uartStatus=WAITING;
48
    }
49
    else{
50
      uartDataCount=0;
51
      uartDataChkChk=0;
52
      uartStatus=WAITING;
53
    }
54
  }
55
  
56
}

in der Main schleife habe ich zum testen:
1
if (uartDataComplete==1){
2
  printf("Daten gültig im uartDataBytes Array");
3
  uartDataComplete=0;
4
 }

Mir kommt es aber immer so vor als würde ich unnütz zuviele Variablen 
verbrauchen.

von Hmm (Gast)


Lesenswert?

Sehr schön. Leider nicht ganz korrekt aber schon sehr nett.

>Mir kommt es aber immer so vor als würde ich unnütz zuviele Variablen
>verbrauchen.
Ich bin nicht dieser Ansicht. Ein paar überflüssige Zuweisungen. Aber es 
geht. Vielleicht findest Du sie selbst.
Nun, falls Du uns erklärst was Dich konkret auf diesen Gedanken bringt, 
dann kann man darüber diskutieren.

Ich möchte Dir sehr empfehlen die Checksumme beim Übergang von LENGTH 
nach DATA zu initialisieren und Dich nicht darauf zu verlassen das das 
im übergeordneten Block passiert. Ähnlich mit uartDataCount.

Dann kannst Du Dir im letzten Zustand fast alles sparen.
1
  else if( uartStatus == CHECKSUM ){
2
    if (nextByte == uartDataChkChk){
3
      uartDataComplete=1;
4
    }
5
    uartStatus=WAITING;


Du hast da immer noch so was im Kopf mit dem if else.

Wenn zwei Variablen nicht gleich sind, dann können sie nur noch ungleich 
sein. Wenn Du aber in beiden Fällen die gleiche Operation ausführst, 
dann führst Du sie effektiv unabhängig davon aus, ob die Variablen 
gleich sind oder nicht. Also immer.

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:
> Sehr schön. Leider nicht ganz korrekt aber schon sehr nett.

Ja, find ich auch. Ich dachte eigentlich, dass die Sache mit der Anzahl 
der zu erwartenden Bytes noch ein Problem werden würde, weil das ja 
implizit eine Schleife ist und man das erst mal rausfinden muss, wie man 
die in der State-Maschine abbildet - aber, das hat er sauber 
hingekriegt.

> Ich bin nicht dieser Ansicht. Ein paar überflüssige Zuweisungen. Aber es
> geht. Vielleicht findest Du sie selbst.

Ludwig: Wie Hmm schon sagte: Ist aber nicht das große Problem

> Ich möchte Dir sehr empfehlen die Checksumme beim Übergang von LENGTH
> nach DATA zu initialisieren und Dich nicht darauf zu verlassen das das
> im übergeordneten Block passiert. Ähnlich mit uartDataCount.

Ja, diesen Gedanken unterstütze ich.
Er ist besser, als überall daran denken zu müssen, dass diese Variablen 
zurückgesetzt werden müssen.
Egal wie die State-Maschine in die Situation kommt, diesen Übergang 
machen zu müssen, setzt du sie hier zurück, dann passiert das auch immer 
hier. Speziell wenn im Zuge der Fehlererkennung es dann passiert, dass 
die Maschine wieder im Zustand WAITING anfangen muss, ohne jemals bei 
CHECKSUM gewesen zu sein, muss sicher gestellt sein, dass die Variablen 
dann wenn es darauf ankommt, korrekte Werte haben.



Aber alles in allem: keine schlechte Arbeit - weiter so!



> in der Main schleife habe ich zum testen:

mach da mal
1
  if (uartDataComplete==1){
2
    uint8_t i;
3
4
    printf("Daten gültig im uartDataBytes Array\n");
5
    printf( buffer, "Len %d\n", uartDataCount );
6
7
    for( i = 0; i < uartDataCount; i++ )
8
      printf( "%02x ", uartDataBytes[i]
9
10
    printf( "\n" );
11
12
    uartDataComplete=0;
13
 }

Da fällt mir was auf. Sieh dir in deinem Code an, was du mit 
uartDataCount machst! Den willst du nicht wirklich mit der CHecksumme 
auf 0 setzen! Denn: DU brauchst den Wert! Er ist deine einzige 
Verbindung, mit der du an anderer Stelle feststellen kannst, wieviele 
Bytes im Array gültig sind! D.h. den darfst du nicht vorzeitig 
verwerfen.

von Ludwig (Gast)


Lesenswert?

Ok, jetzt mal der Reihe nach.


>> Ich möchte Dir sehr empfehlen die Checksumme beim Übergang von LENGTH
>> nach DATA zu initialisieren und Dich nicht darauf zu verlassen das das
>> im übergeordneten Block passiert. Ähnlich mit uartDataCount.

Was ist mit Initialisieren gemeint, 0 zuweisen oder die variable 
erstellen?
Wenn die Variable im gesamten Programm da sein soll muß ich diese doch 
volatile machen oder?
uartDataChkChk = 0; zwischen den else if?
dann sind ja die daten die ich brauche weg.


wenn ich das letzte nun so mache
1
  else if( uartStatus == CHECKSUM ){
2
    if (nextByte == uartDataChkChk){
3
      uartDataComplete=1;
4
    }
5
    uartStatus=WAITING;

wo leere ich dann
 uartDataCount=0;
 uartDataChkChk=0;
?

Und ich will die ja nicht immer leeren doch nur wenns dann zum schluss 
so weit ist.

-----------------

Den Teil der Main teste ich gleich, danke.


>> Da fällt mir was auf. Sieh dir in deinem Code an, was du mit
>> uartDataCount machst! Den willst du nicht wirklich mit der CHecksumme
>> auf 0 setzen! Denn: DU brauchst den Wert! Er ist deine einzige
>> Verbindung, mit der du an anderer Stelle feststellen kannst, wieviele
>> Bytes im Array gültig sind! D.h. den darfst du nicht vorzeitig
>> verwerfen.

bekomme ich nicht die Länge mit:
sizeof(uartDataCount)
?

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:

>>> Ich möchte Dir sehr empfehlen die Checksumme beim Übergang von LENGTH
>>> nach DATA zu initialisieren und Dich nicht darauf zu verlassen das das
>>> im übergeordneten Block passiert. Ähnlich mit uartDataCount.
>
> Was ist mit Initialisieren gemeint, 0 zuweisen oder die variable
> erstellen?

Respekt.
Hmm meinte 0-setzen.
Denn Initialisieren geht ja nur bei der Definition einer Variablen. Gut, 
in C ist das oft Wortklauberei aber streng genommen hast du Recht. Das 
kann keine Initialisierung sein sondern muss eine Zuweisung sein.

> Wenn die Variable im gesamten Programm da sein soll muß ich diese doch
> volatile machen oder?

Nein. So pauschal kann man das nicht sagen
FAQ: Was hat es mit volatile auf sich

> uartDataChkChk = 0; zwischen den else if?
> dann sind ja die daten die ich brauche weg.

Wieso sollen die weg sein?
Ich denke wir reden da jetzt gerade aneinander vorbei.


> wenn ich das letzte nun so mache
>
1
>   else if( uartStatus == CHECKSUM ){
2
>     if (nextByte == uartDataChkChk){
3
>       uartDataComplete=1;
4
>     }
5
>     uartStatus=WAITING;
6
>
>
> wo leere ich dann
>  uartDataCount=0;
>  uartDataChkChk=0;
> ?

Im Status 'LENGTH', also unmittelbar vor dem Zeitpunkt an dem es spätest 
möglich ist.

> bekomme ich nicht die Länge mit:
> sizeof(uartDataCount)


Nein.
sizeof ist eine Compile-Time Operation. Damit kannst du den Compiler 
befragen, wie groß (in Bytes) er eine Variable gemacht hat. Ein Array, 
welches du mit 30 Bytes reserviert hast, wird immer 30 Bytes haben. Egal 
was drinnen steht. sizeof ist deine Möglichkeit, wie du im C Programm 
die Größe von Datentypen benutzen kannst, ohne konkrete Zahlen schreiben 
zu müssen.

von Hmm (Gast)


Lesenswert?

>Was ist mit Initialisieren gemeint, 0 zuweisen oder die variable
>erstellen?

Ja, aber...: Damit ist die Zuweisung eines "sinnvollen Anfangswertes" 
gmeint. Das kann eine 0 sein, ist es aber nicht immer. In diesem Fall 
aber schon.

Das "erstellen" einer Variable mit der Drechselbank wurde durch das 
dritte von-Neumann Konzil durch die "Deklaration" abgelöst. C. Babbage 
war zwar strikt dagegen, aber er wurde in einen Schal eingehäkelt und so 
mundtot gemacht. :-) Lady Ada spielt dabei ein nicht unbedeutende Rolle, 
die alte Häklerin.

>Wenn die Variable im gesamten Programm da sein soll muß ich diese doch
>volatile machen oder?
Nein. Der erste Teil des Satzes der sich auf das "Da-Sein" von Variablen 
bezieht hat mit dem zweiten Teil, dem "flüssig" sein nichts zu tun. Das 
zweite meint, das die Variable durch irgendwelche Umstände die der 
Compiler nicht selbst feststellen kann (hier ein Interrupt) geändert 
werden kann. D.h. der Compiler darf sich niemals darauf verlassen das 
der Wert etwa konstant ist oder seine letzte Lesung dieser Variablen 
noch gültig ist. Lies mal bitte in dem C-Buch.

>uartDataChkChk = 0; zwischen den else if? dann sind ja die daten die ich >brauche 
weg.
Hrm. Ich muss doch gleich mal Zigaretten holen. :-) Die Daten sind 
dadurch nicht weg. Wie sollten sie? Und die Information das die 
Checksumme korrekt ist, ist dann in der Regel schon erkannt worden.

Karl Heinz: Da müssen wir noch was tun, das er nicht noch bei der 
Verarbeitung der alten Daten ist, wenn schon neue ankommen. 
Synchronisation.


>sizeof(uartDataCount)

Nein. Das ist in zweifacher Hinsicht falsch. Bitte schau mal in das 
C-Buch was sizeof macht. In der zweiten Hinsich "ist" der Inhalt der 
Variablen uartDataCount schon die Länge.

Ich gehe mich jetzt ersäufen. Bin in einer Viertelstunde wieder da. :-)

von Hmm (Gast)


Lesenswert?

Das mit dem "Initialisieren" ist so eine Sache. Zum einen ist das 
Terminus der Sprache C. Insofern hat Karl Heinz recht, das man das nur 
einmal tun kann.

Aber das ist auch ein Terminus in Bezug auf Algorithmen wie etwa eine 
Prüfsumme zu ermitteln. Wenn sie wiederholt durchgeführt werden, dann 
muss man zwar eigentlich von "Re-Initialisieren" sprechen, aber so ganz 
falsch ist das nun nicht.

Tatsächlich habe ich mir falsch ausgedrückt. Für das Weglassen von "Re" 
verordne ich mir eine Zeile Logarithmentafel von Hand schreiben als 
Strafe.

von Hmm (Gast)


Lesenswert?

Und es muss auch "Definition" anstatt "Deklaration" heissen.

von Ludwig (Gast)


Lesenswert?

Ok, denke habe den größten teil verstanden.

Hmm schrieb:
> Karl Heinz: Da müssen wir noch was tun, das er nicht noch bei der
>
> Verarbeitung der alten Daten ist, wenn schon neue ankommen.
>
> Synchronisation.

Passiert eigentlich nicht da Daten nur kommen wenn ich zuvor das 
Kommando zum schicken gegeben habe.

>>  if (uartDataComplete==1){
>>    uint8_t i;
>>
>>    printf("Daten gültig im uartDataBytes Array\n");
>>    printf( buffer, "Len %d\n", uartDataCount );
>>
>>    for( i = 0; i < uartDataCount; i++ )
>>      printf( "%02x ", uartDataBytes[i]            //fehlt da eine klammer?
>>
>>    printf( "\n" );
>>
>>    uartDataComplete=0;
>> }

Was ist buffer?

von Karl H. (kbuchegg)


Lesenswert?

Hmm schrieb:

> Tatsächlich habe ich mir falsch ausgedrückt. Für das Weglassen von "Re"
> verordne ich mir eine Zeile Logarithmentafel von Hand schreiben als
> Strafe.

Sei nicht so streng mit dir. Tatsächlich mixen wir Menschen oft die 
Wörter durcheinander und trotzdem kennt sich jeder aus. Ich plädiere ja 
auch schon seit 15 Jahren dafür die Termini 'Adresse' und 'Pointer' 
nicht so durcheinander zu werfen. Trotzdem passiert es laufend und 
trotzdem kennen sich die meisten aus, was gemeint ist.

von Karl H. (kbuchegg)


Lesenswert?

Ludwig schrieb:

> Was ist buffer?

Autsch. Ein Überbleibsel.

Ursprünglich bin ich den Weg über sprintf gegangen, bis ich gemerkt 
habe, dass dein printf offenbar direkt an die Ausgabe gehen kann. An 
dieser Stelle habe ich dann vergessen, den 'buffer' rauszunehmen.

von Ludwig (Gast)


Lesenswert?

Ok, funktioniert :)

bei einem gülten Datensatz wie:
AA BB 05 12 34 56 78 90 98

bekomme ich:

Daten gültig im uartDataBytes Array
Len 5
12 34 56 78 90

von Oliver R. (roliver)


Lesenswert?

Hi,

die gesamte Routine wurde mich mal interessieren, denn das mit der 
Checksumme und der variablen Länge wäre auch beim meinem Projekt toll.

Cu Oliver

von Ludwig (Gast)


Lesenswert?

Die Empfangsroutine schaut im Moment so aus:
1
ISR(USART_RXC_vect)
2
{
3
  // Am Anfang ist der Empfangscode im Status 'wartend'.
4
  static uint8_t uartStatus = WAITING;
5
  static uint8_t dataBytesToRead;
6
  uint8_t nextByte = UDR;
7
8
  // Am Anfang ist der Empfangscode im Status 'wartend'.
9
  // Wird das 0xAA gesehen dann geht die ISR in den Status
10
  // 'erstes Sync-Byte gesehen'.
11
  if( uartStatus == WAITING && nextByte == 0xAA )
12
  uartStatus = FRST_SYNC;
13
14
  // Ist dann das nächste Byte kein 0xBB dann geht der Status
15
  // wieder zurück auf 'wartend'.
16
  // Ansonsten gehts weiter in den Status 'Längenbyte lesen'.
17
  else if( uartStatus == FRST_SYNC ) {
18
    if( nextByte == 0xBB )
19
    uartStatus = LENGTH;
20
    else
21
    uartStatus = WAITING;
22
  }
23
24
  // Beim nächsten ISR Aufruf landet daher das nächste Byte in
25
  // einer Variablen, die angibt, wieviele bytes ab jetzt noch
26
  // kommen werden und die Daten bilden. Der Status wechselt
27
  // zu 'Daten lesen'.
28
  else if( uartStatus == LENGTH ){
29
    dataBytesToRead=nextByte;
30
    uartStatus=DATA;
31
    uartDataCount=0;
32
    uartDataChkChk=0;
33
  }
34
35
36
  else if( uartStatus == DATA && uartDataCount < dataBytesToRead ){
37
      uartDataBytes[uartDataCount]=nextByte;
38
      uartDataChkChk=uartDataChkChk^nextByte;
39
      uartDataCount++;
40
      if (uartDataCount == dataBytesToRead)
41
        uartStatus=CHECKSUM;
42
    }
43
    
44
  else if( uartStatus == CHECKSUM ){
45
    if (nextByte == uartDataChkChk){
46
      uartDataComplete=1;
47
    }
48
    uartStatus=WAITING;
49
  }
50
  
51
}

von Karl H. (kbuchegg)


Lesenswert?

der Vergleich hier

  else if( uartStatus == DATA && uartDataCount < dataBytesToRead ){

ist noch etwas übertrieben.
Denn an dieser Stelle kann uartDataCount nicht gleich dataBytestoRead 
werden. Denn wenns zum Ende der Daten hin kommt, dann schaltet

      if (uartDataCount == dataBytesToRead)
        uartStatus=CHECKSUM;

zum nächsten Zustand weiter.

Ich weiß: Ich selbst war es, der mit solchen Dingen angefangen hat. 
Heute könnte ich mich dafür ....
Mach es dir zur Gewohnheit, an dieser Stelle immer nur den Status 
abzufragen. Denn: du musst dafür sorgen, dass auch im Fehlerfall die 
Zustandsweiterschaltungen passieren. Wenn dieser if bei dir nicht 
genommen wird, weil die Counter durcheinander laufen, dann hängt deine 
Zustandsmaschine auf immer und ewig im Zustand DATA und kommt da nicht 
mehr raus.


Was auf jeden Fall noch fehlt:
Dein Array hat eine begrenzte Länge. OK, ich weiß du wirst jetzt sagen, 
das reicht dicke, so lang sind meine Daten nicht.
Aber: Im Fehlerfall kann es passieren, dass du ein völlig falsches Byte 
als Länge auffasst, und dann kann es passieren, dass du hinten aus dem 
Array rausrauscht. Wichtig: du musst so tun, als ob du das Byte 
tatsächlich verarbeitest, schliesslich muss es ja auch irgendwann in den 
CHECKSUM Zustand gehen - das einzige was du nicht tun darfst, ist in 
diesem Fall das Array beschreiben, weil du dann irgendwas anderes im 
Speicher zerstörst.

d.h. deine erste Fehlerbehandlung ist es hier
1
  else if( uartStatus == DATA ){
2
    if( uartDataCount < sizeof( uartDataBytes )
3
      uartDataBytes[uartDataCount]=nextByte;
4
  
5
    uartDataChkChk=uartDataChkChk^nextByte;
6
    uartDataCount++;
7
8
    if (uartDataCount >= dataBytesToRead)
9
      uartStatus=CHECKSUM;
10
  }

gegen diesen Fall vorzusorgen.
In eine ähnliche Kategorie fällt der Austausch von == durch >= beim 
abschliessenden Vergleich zur Statusweiterschaltung. Das ist einfach 
defensives Programmieren.

von Karl H. (kbuchegg)


Lesenswert?

Und schreib nicht so dicht!
Seit du 6 Jahre alt bist, ist dein Gehirn darauf trainiert worden, dass 
zwischen den Wörtern ein Leerraum steht. Bei
1
    uartDataChkChk=uartDataChkChk^nextByte;
muss man erst mal innerhalb der Zeile identifizieren, wo ein Wort 
anfängt und wo es aufhört. Und erst dann kann man analysieren was da 
eigentlich steht. Schreibst du aber
1
    uartDataChkChk = uartDataChkChk ^ nextByte;
dann nutzt du dein Lesetraining aus. Die bewusste Wortanalyse fällt 
schon mal weg.

Nur weil du es so dicht schreiben darfst, bedeutet das nicht, dass du es 
musst.

von Ludwig (Gast)


Lesenswert?

Ok, danke für die Hinweise, das mit der Längenüberwachung baue ich noch 
ein.

Ich habe mir gedacht wenn ich jeden State zeitüberwache denn bei 19200 
muß das nächste Byte in absehbarer Zeit kommen, wenn nicht würde ich die 
Schnappermatik wieder zurücksetzten. Das muß ich mir aber noch ausdenken 
wie.

von Hmm (Gast)


Lesenswert?

Hier kommst Du in einen Bereich von dem wir noch garnicht gesprochen 
haben. Du musst eine Zeit abmessen. Hast Du schon eine Idee wie Du das 
machen kannst?

von Ludwig (Gast)


Lesenswert?

müsste gehen mit dem oszi, welche zeit? Zwischen anfrage und antwort? 
und oder zwischen den bytes warscheinlich.

von Hmm (Gast)


Lesenswert?

>müsste gehen mit dem oszi
Was meinst Du mit "Oszi"? Oszilloskop oder Oszillator?

>welche zeit?

Naja. Das musst Du ja eigentlich wissen. Welche Zeiten willst Du messen?
Sagen wir mal eine Zeit in der Grössenordnung der Bitlänge bei 19200 
Baud.
Also sagen wir mal 52us.

Das dient erstmal nur als Beispiel.
Es ist kaum sinnvoll schon nach einer Bitzeit oder auch einer Bytezeit 
schon von einem Timeout auszugehen. Es sei denn Du fügtst hier noch 
weitere Informationen zu den Geröten oder Protokollen hinzu.

Aber wie machst Du das grundsätzlich?
OK. Ehe wir jetzt noch drei Jahre um den heissen Brei rumreden: 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

von Michi (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Aber: Im Fehlerfall kann es passieren, dass du ein völlig falsches Byte
>
> als Länge auffasst, und dann kann es passieren, dass du hinten aus dem
>
> Array rausrauscht.

Habe ich so den Fehlerfall abgefangen?
1
  else if( uartStatus == DATA && uartDataCount < dataBytesToRead ){
2
      uartDataBytes[uartDataCount] = nextByte;
3
      uartDataChkChk= uartDataChkChk ^ nextByte;
4
      if (uartDataCount < sizeof(uartDataBytes))
5
        uartDataCount++;
6
        else uartStatus=WAITING;
7
      if (uartDataCount == dataBytesToRead)
8
        uartStatus=CHECKSUM;
9
    }

von Karl H. (kbuchegg)


Lesenswert?

Michi schrieb:
> Karl Heinz Buchegger schrieb:
>> Aber: Im Fehlerfall kann es passieren, dass du ein völlig falsches Byte
>>
>> als Länge auffasst, und dann kann es passieren, dass du hinten aus dem
>>
>> Array rausrauscht.
> Habe ich so den Fehlerfall abgefangen?

Kommt drauf an.
Solange du deine Timeouts nicht implementiert hast, hast du eine 
wunderbare "Endlosschleife" gebaut.

Ist deine Zustandsmaschine erst mal im Zustand "DATA" und ist der 
Fehlerfall eingetreten, kommt sie da ohne fremde Hilfe nicht mehr raus. 
Im schlimmsten Fall ist das dann ein Reset.

von Ludwig (Gast)


Lesenswert?

Kann die Echleife nicht erkennen, das ganze wird doch nur einmalig 
durchlaufen beim Interrupt oder nicht?

von Hmm (Gast)


Lesenswert?

Denk daran, das Du hier einen Fehler abfangen willst, der durch eine 
Begrenzung der Implementierung des Protokolls entstehen kann.

Das Protokoll, kann bis zu 255 Bytes empfangen. Nur Dein Buffer ist 
kleiner. Daher musst Du die Daten weiter annehmen, wenn Dein Buffer am 
Ende ist auch wenn Du sie nicht speicherst. Ausserdem musst Du dann in 
einen anderen Folgezustand, wenn die Checksumme kommt, denn das Telegram 
darf insgesamt dann nicht als korrekt angenommen werden. Du hättest ja 
nur einen Teil der Daten.

Ich denke nicht, dass Karl Heinz das gemeint hat, aber nimm einmal an, 
in Deinen Nutzdaten treten 0xAA 0xBB auf, nachdem Du einen Überlauf 
erkannt hast. Dann werden Nutzdatenbytes als Synchronisation erkannt 
obwohl sie das nicht sind.

von Ludwig (Gast)


Lesenswert?

Ah ok, denke verstanden, der Interrupt wird nicht dann ausgelöst wenn 
was esmpfangen wird sondern solange noch was im Buffer ist, deswegen 
muss es weiterlaufen bis der Buffer leer ist?

von Karl H. (kbuchegg)


Lesenswert?

Ok, die Sache mit der Endlosschleife war Blödsinn. Da hab ich deinen 
Code zu oberflächlich überflogen.

von Hmm (Gast)


Lesenswert?

>...der Interrupt wird nicht dann ausgelöst wenn
>was esmpfangen wird sondern solange noch was im Buffer ist, ...
Jein. Vermutlich muss man sogar sagen: Nein.

Der Interrupt wird ausgelöst, wenn ein Zeichen empfangen wurde. Das 
liegt natürlich einem Register, das man mit gutem Willen auch als Buffer 
bezeichnen kann. Deswegen das Jein. Vermutlich beziehst Du Dich aber auf 
den Buffer, den ich in meiner letzten Antwort gemeint habe, die Variable 
uartDataBytes; dann muss es ganz klar Nein heissen.

"Es" muss weiterlaufen, d.h. die Interrupts müssen weiter abgearbeitet 
werden bis das Telegramm beendet ist. Der Sender weiss ja nicht, das 
Du festgestellt, hast, das Dein Buffer namens uartDataBytes zu klein 
ist. In Deinem Protokoll ist nicht vorgesehen, das der Empfänger dem 
Sender sowas mitteilen kann. Daraus folgt, Du musst die Nachricht 
vollständig entgegennehmen als ob Du genug Platz hast. Du darfst sie 
aber nicht speichern (in uartDataBytes). Dennoch musst Du auch die 
Checksumme entgegennehmen. Du brauchst Sie nicht vergleichen. Du darfst 
auch nicht uartDataComplete = 1 setzen, weil Du eben das Telegramm nicht 
vollständig gespeichert hast. Du hast nur ein Fragment, das Du (solange 
Du nichts anderes sagst, muss man davon ausgehen) überhaupt nicht 
sinnvoll verarbeiten kannst.

Die Forderungen erfüllt aber Dein Fragment von hier 
Beitrag "Re: Wie vorgehen beim String einlesen?" nicht!

von Ludwig (Gast)


Lesenswert?

Ok, danke, dann muß ich mir das noch anschauen.

Im Moment hänge ich noch an der Zeitüberwachung, und das mir die 
Abfreage in einer while schleife welche eine Bedingung hat die von einem 
interrupt verändert wird, wegoptimiert wird.

Aber wie kann ich das verhindern?

beispiel:

Starte_Zeit(100);
while(( uartDataComplete == 0 ) && ( zeitvorbei == 0) ){}
Stoppe_Zeit();

in der Overflow Interrupt Routiene Zähle ich die Überläufe und wenn die 
Überläufe nach 100 vorbei ist wird zeitvorbei = 1

Ich habe bisher nur gefunden das es warscheinlich wegoptimiert wird aber 
nicht wie man das verhindern kann.

von Hmm (Gast)


Lesenswert?

>Ok, danke, dann muß ich mir das noch anschauen.

Mach das mal zuerst. Es macht, meiner Meinung nach, keinen Sinn nun mit 
etwas anderem zu beginnen. Das ist auch mein Fehler, muss ich zugeben.


>in der Overflow Interrupt Routiene Zähle ich die Überläufe und wenn die
>Überläufe nach 100 vorbei ist wird zeitvorbei = 1

Das ist schonmal gut gemacht.

Was das "wegoptimieren" betrifft, muss man das mal hinterfragen und wir 
kommen auch an einen Wendepunkt.

Zum einen musst Du ganz klar stellen, an welchen konkreten , 
objektiven Kriterien Du feststellst das da etwas wegoptimiert wird. 
Die einfache Vermutung reicht nicht, für konkrete Änderungen des 
Codes.

Was den Wendepunkt betrifft, so hast Du jetzt folgendes Problem: Der 
Interrupt für die Verarbeitung wird nur dann aufgerufen, wenn ein 
Zeichen empfangen wurde. (Das wir das irgendwann ändern müssen war klar, 
aber ich habe das so weiterlaufen lassen, weil es ohne Zeitüberwachung 
erstmal unwichtig war).

Das hat zur Folge, das Zeitüberschreitungen nur dann erkannt werden wenn 
ein Zeichen empfangen wurde. Das ist natürlich ein Widerspruch. Kommt 
ein Zeichen zu spät, dann wird das erst bei dem späten auftreten 
erkannt. Kommt es garnicht, dann wird das nie erkannt.

Nun kannst Du aber (beim AVR) einen Interrupt nicht durch einen weiteren 
Interrupt unterbrechen. Selbst wenn das (bei anderen CPUs ausnahmsweise 
geht - das hängt von weiteren Umständen ab - ist das keine allgemein 
empfehlenswerte Technik.

Du musst also zunächst Deinen Code aus dem Interrupt herauslösen. In dem 
neuen Interrupt wird nur das empfangene Zeichen in eine globale Variable 
gespeichert und ein globales Flag gesetzt. In dem neuen main wird dieses 
Flag abgefragt (es sagt nun, das ein Zeichen empfangen wurde) und die 
State-Machine anhand des empfangenen Zeichens weitergeschaltet.

Wenn Du das erledigt hast, kannst Du in dem Timer-Interrupt auch so 
einen Flag-Mechanismus implementieren. Wenn in main dieses Flag gesetzt 
ist, so kannst Du nach entsprechender Erweiterung auch damit die 
State-Machine weiterschalten.

von Hmm (Gast)


Lesenswert?

Denk an "volatile".

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.