Forum: Mikrocontroller und Digitale Elektronik Programmbeispiele für fortgeschrittene Programmierung


von Matthias W. (Gast)


Lesenswert?

Guten Abend,

ich suche Lösungsansätze für fortgeschrittene Programmierung, da ich 
eine größere Applikation schreiben möchte. Mir geht es z.B. um die 
sinnvolle Bearbeitung empfangener Daten. Wie prüfe ich diese, wie 
springe ich die entsprechenden Routinen zu den empfangenen Befehlen an, 
wie behandle ich Fehler usw. Kurz: Ein Beispiel einer größeren 
Applikation, die ein Befehlsprotokoll enthält, mit Fehlerprüfung 
(Kommunikationsfehler als auch "Parameter"-Fehler), Fehlerbearbeitung 
und Rückmeldung an den User usw.
Alles was mir mein Hirn gebracht hat, war irgendwie nur halbgar, 
vielleicht stell ichs mir zu kompliziert vor :-)
Kann hier jemand so eine Applikation posten? Das wär echt super!

Matze

von Gast (Gast)


Lesenswert?

Ich glaube eine richtig fertige App wirst du hier nicht unbedingt 
bekommen. Aber wenn du konkrete Fragen stellst, kann bestimmt jemand 
auch eine Antwort liefern, die dir hilft (im Gegensatz zu dieser hier 
;-)

Gast.

von Matthias W. (Gast)


Lesenswert?

@Gast:

Du hast bestimmt recht, im Prinzip wärs darauf hinausgelaufen, dass ich 
mir meine App aus verschiedenen fremden Apps zusammengestückelt hätte, 
und mich dann gefragt hätte, warums nicht tut...

Also mal sehen, ich möchte dem Controller Befehle senden. Der Aufbau der 
Befehle sieht etwa so aus:

BB[DD...DD]CR

BB = Befehlsbyte
DD = optionale Datenbytes
CR = Carriage Return

Das Befehlsbyte liegt im Bereich der darstellbaren Zeichen, also von 
0x20 bis 0x7F. Meistens handelt es sich um Buchstaben.
Die Datenbytes sind ausnahmslos ASCII-Hex-Zeichen.
Der Controller soll auf jeden Befehl antworten, und zwar so, dass der 
User im Fehlerfall erkennt, was der Fehler war (Bufferüberlauf, falsche 
Werte eingegeben, falsche Zeichen, etc.)

Ich habe eine Routine geschrieben, die die Daten empfängt, und in einem 
Buffer ablegt. Der Buffer ist gegen Überlauf geschützt, die Routine wird 
solange ausgeführt, bis das CR-Zeichen kommt, selbst wenn ein Überlauf 
auftrat. Ein Datenzähler enthält die Anzahl der empfangenen Daten.

Das heisst, nach dieser Funktion habe ich einen Buffer, der mindestens 
ein Befehlszeichen plus optionaler Daten enthält.

So und jetzt wirds für mich kribblig. Eine Wandlung der 
ASCII-Hex-Zeichen nach Hex bekomme ich noch hin, logischerweise sollte 
ich das machen, bevor ich einen Befehl ausführe, sonst kann ich in jeder 
Befehlsroutine konvertieren, das halte ich für ungünstig.

Aber wie löse ich z.B. das Anspringen der entsprechenden Befehlsroutinen 
abhängig vom Befehlsbyte? Ein Switch-Case-Konstrukt wird da sicher 
unübersichtlich. Hm... vielleicht Funktionspointer? Mir bildet sich da 
grad ne Idee... Die muss ich mir mal durchn Kopp gehen lassen...

Egal, was mich dann noch interessiert, wie behandle ich Fehler? 
Beispiel: Ich erkenne, dass die empfangenen Daten zwar ASCII-Hex-Zeichen 
sind, aber sie sind ausserhalb des Bereichs (also hat der Bediener 
gemurkst --> falschen Wert eingegeben). Wie löse ich es so, dass der 
User anhand der Antwort vom Controller den Fehler entdeckt, also ob er 
einen falschen, ungültigen Wert oder ob er ein "verbotenes" Zeichen 
gesendet hat? Oder ob der Buffer übergelaufen ist?
Fragen über Fragen...

Matze

von Bernd R. (Firma: Promaxx.net) (bigwumpus)


Lesenswert?

Also,
ich habe das mal mit einer State-Engine gelöst.

Da wurde auch der ganze Text empfangen und dann bearbeitet.
1
Do while
2
case State
3
State=0 ... warten auf Start-Code (Byte), dann State=1
4
State=1 ... Byte hat das richtige Format für Cmd ? Nein-Error
5
   Cmd=1 ? - State=$10
6
   Cmd=2 ? - State=$20
7
State=10 oder $20 ... HEX-Zeichen ? nein-Error
8
   Byte in Hex wandeln ... wenn x Bytes durch ... State=State+1
9
State=11 oder $21 ... Byte=CR ? nein-Error
10
   State=$11 ... Cmd 1 ausführen
11
   State=$21 ... Cmd 2 ausführen
12
end case
13
weiterrücken
14
loop

Da kann man dann eine Syntax prüfen und gleichzeitig einen Zustand $?1 
für mehrere Befehle nutzen (versch. Datenbytes) und es trotzdem kompakt 
halten.
Der Vorteil einer solchen State-Engine ist der starre und klare Aufbau 
(Übersicht). Man kann jeden Zustand fest einordnen und programmiert sich 
nicht zu Tode (Spagetti-Code). Aber man muß da mal etwas Gehirnschmalz 
einbringen. Ich arbeite gerne damit, weil es hilft, Programmierfehler 
(side-effects) zu vermeiden.
Klare abgeschlossene Zustände mit festen Regeln für den Wechsel in einen 
anderen Zustand (Ausgänge schalten etc.) sind der Vorteil, den man mit 
etwas Codespeicher bedingt durch die Nutzung der Compiler-Direktiven 
CASE erkauft. Aber der Speicher sollte heute nicht mehr so sehr wichtig 
sein. Zur Not kann man am Ende des Projekts noch etwas Handarbeit 
nachlegen um Code zu sparen.

von Karl H. (kbuchegg)


Lesenswert?

Matthias W. wrote:
> Also mal sehen, ich möchte dem Controller Befehle senden. Der Aufbau der
> Befehle sieht etwa so aus:
>
> BB[DD...DD]CR
>
> BB = Befehlsbyte
> DD = optionale Datenbytes
> CR = Carriage Return

sieht doch schon mal gut aus.

>
> Das Befehlsbyte liegt im Bereich der darstellbaren Zeichen, also von
> 0x20 bis 0x7F. Meistens handelt es sich um Buchstaben.
> Die Datenbytes sind ausnahmslos ASCII-Hex-Zeichen.

Gut

> Ich habe eine Routine geschrieben, die die Daten empfängt, und in einem
> Buffer ablegt. Der Buffer ist gegen Überlauf geschützt, die Routine wird
> solange ausgeführt, bis das CR-Zeichen kommt, selbst wenn ein Überlauf
> auftrat. Ein Datenzähler enthält die Anzahl der empfangenen Daten.

OK

> Das heisst, nach dieser Funktion habe ich einen Buffer, der mindestens
> ein Befehlszeichen plus optionaler Daten enthält.

OK

> So und jetzt wirds für mich kribblig. Eine Wandlung der
> ASCII-Hex-Zeichen nach Hex bekomme ich noch hin, logischerweise sollte
> ich das machen, bevor ich einen Befehl ausführe, sonst kann ich in jeder
> Befehlsroutine konvertieren, das halte ich für ungünstig.

Warum soll das ungünstig sein?
Letztendlich kann doch nur die Befehlsroutine wissen ob sie
jetzt eine 2 Byte Zahl oder eine 4 Byte Zahl haben möchte oder
ob die Zeichen vielleicht sogar direkt (also ohne Umwandlung)
benutzt werden sollen.

>
> Aber wie löse ich z.B. das Anspringen der entsprechenden Befehlsroutinen
> abhängig vom Befehlsbyte? Ein Switch-Case-Konstrukt wird da sicher
> unübersichtlich. Hm... vielleicht Funktionspointer? Mir bildet sich da
> grad ne Idee... Die muss ich mir mal durchn Kopp gehen lassen...

Guckst du mal hier
http://www.mikrocontroller.net/articles/FAQ#Men.C3.BCs_mit_Funktionszeigern

anstelle des Menüs benutzt du das empfangene Befehlsbyte um
den richtigen Eintrag zu finden.

>
> Egal, was mich dann noch interessiert, wie behandle ich Fehler?
> Beispiel: Ich erkenne, dass die empfangenen Daten zwar ASCII-Hex-Zeichen
> sind, aber sie sind ausserhalb des Bereichs (also hat der Bediener
> gemurkst --> falschen Wert eingegeben). Wie löse ich es so, dass der
> User anhand der Antwort vom Controller den Fehler entdeckt, also ob er
> einen falschen, ungültigen Wert oder ob er ein "verbotenes" Zeichen
> gesendet hat? Oder ob der Buffer übergelaufen ist?
> Fragen über Fragen...

Wie wäre es mit
Einen Klartext per UART zurücksenden, der den Benutzer
darüber aufklärt.
Was auch immer gut kommt: Zumindest etwas von der Eingabe
wieder ausgeben, damit der Benutzer erkennen kann, wo den
der Fehler aufgetreten ist.
Also etwas in der Form
** Fehler in B24FG76
**               *
** ungültiges Zeichen

von Matthias W. (Gast)


Lesenswert?

Hallo Bernd, hallo Karl-Heinz,

sorry für die späte Antwort. Danke euch beiden, ich werd das mal in 
aller Ruhe durchgehen. Mal sehen ob ich durch die State-Machine bzw. die 
geänderte Menü-Routine die App ans laufen bekomme.
Nochmals besten Dank.

Matze

von rene (Gast)


Lesenswert?

Matthias,
ein menschenlesbares Protokoll hat den Vorteil, dass man's an Hyperterm 
einhaemmern kann. Dann sollte man allerdings den CRC weglassen. Wenn das 
Protokoll mit einer Software abgearbeitet wird, macht man's anders. Dann 
muss es naemlich nicht lesbar sein, und auch nicht ASCII. Als Beispiel 
fuer ein Maschinenprotokol moege meine Seite dienen.
http://www.ibrtses.com/embedded/shortmsgprotocol.html

Rene

von Matthias W. (Gast)


Lesenswert?

Hallo Rene,

hab mir dein Protokoll mal angeguckt. Du arbeitest ohne 
Abschlusszeichen, soweit ich das sehen kann. Was passiert, wenn z.B. ein 
Zeichen verloren geht? Lässt du ein TimeOut laufen? Oder dient das 
Sync-Zeichen dazu, vorher unvollständig empfangene Daten zu verwerfen?

Matze

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.