Forum: Mikrocontroller und Digitale Elektronik serielle datenübertragung pc <> AVR


von technikus (Gast)


Lesenswert?

Hallo,

folgende Ausgangssituation:

-Mikrocontroller ATMega168/USBtoUART Converter/Programmierung mit AVR 
GCC

-PC/USB Schnittstelle/Programmierung c#

Ich möchte zwischen Mikrocontroller und PC Daten austauschen.
Im Mikrocontrollerprogramm habe ich erfolgreich die UART Lib von Peter 
Fleury implementiert.
Auf der PC Seite läuft die Ankopplung auch soweit.

Es sollen nun eine Reihe 16 und 32 Bit UInt Werte übertragen werden.

Soweit so gut.

In der Hauptschleife des Mikrocontroller Programms lese ich nun, wie im 
Muster der Lib angegeben, den Empfangsbuffer aus. Eigentlich wollte ich 
ein Startbyte definieren um die Datenübertragung zu 
synchronisieren/starten , d.h. den Empfangsbuffer in ein Array packen 
und nach Empfang aller Zeichen entsprechend auslesen.
Da ich nun aber die 32/16Bit UInt als Absolutwerte übertrage (vorher 
entsprechend in Einzelbytes aueinander gebröselt) kann jede Kombination 
zwischen 0x00 und 0xFF auftreten. Ein "freies" Startbyte ist also so 
nicht möglich.
Wie löst man soetwas?

Habt Ihr Tipps für mich?


Vielen Dank
Ernst

von Bastler (Gast)


Lesenswert?

Daten eventuell als Ascii übertragen.
dauert länger, aber nur Daten 0x30 - 0x39


oder du versuchst es zu umgehen mit mehreren Startzeichen

von Volker S. (volkerschulz)


Lesenswert?

Umwandeln in ASCII ist schon ein bisschen krass. Du koenntest anstatt 
von 8N1 9N1 verwenden und das uebrige Bit als Start-Indikator verwenden. 
Oder Du machst es ueber die Zeit (Pause nach jeder kompletten 
Uebertragung).

Volker

von Karl H. (kbuchegg)


Lesenswert?

Man kann sich natürlich auch noch ein Startbyte freischaufeln.

zb. 0xFF wird nie in den Daten übertragen (oder irgendein anderer Wert 
der möglichst selten vorkommt. Oft ist es ja so, dass bestimmte Bytes 
häufig auftreten, andere wiederrum seltener)

0xFF ist das STartbyte
muss in den Daten 0xFF übertragen werden, so wird stattdessen zb 0xFE 
0x01 übertragen. Da jetzt 0xFE eine Sonderrolle zukommt, wird das 
ursprüngliche 0xFE als 0xFE 0x00 übertragen.
Baut man diese Substitution tief unten in die Softwarelayer ein, so ist 
das alles für darüberliegende Softwareschichten transparent und sie 
merken nichts davon.

von ich (Gast)


Lesenswert?

und was ist wenn man 0xFE 0x00 senden will?

von Karl H. (kbuchegg)


Lesenswert?

ich schrieb:
> und was ist wenn man 0xFE 0x00 senden will?

Was hinter dem 0xFE kommt tangiert ja die Substitution nicht.
0xFE wird durch 0xFE 0x00 ersetzt.

Angenommen der Sender möchte diese Bytesequenz auf den Weg bringen

  0xFF 0xFE 0x00

Seine Sendefunktion übernimmt die Substitution:
0xFF wird durch 0xFE 0x01 ersetzt, 0xFE wird durch 0xFE 0x00 ersetzt. 
Noch ein 0xFF als Startbyte davor.

Damit geht über die Leitung:

  0xFF 0xFE 0x01 0xFE 0x00 0x00

Beim Empfänger wird 0xFF als Startbyte aussortiert. Die Abfolge 0xFE 
0x01 wird durch 0xFF ersetzt, die Abfolge 0xFE 0x00 wird durch 0xFE 
ersetzt. Aus der Empfangsroutine purzeln also raus

  Start of Daten
  0xFF 0xFE 0x00

Also genau das, was der Sender seiner Senderoutine übergeben hat (+ eine 
Kennung für: ein neuer Datensatz hat angefangen)

von Thomas B. (escamoteur)


Lesenswert?

Hängt auch davon ab, was für Daten Du übertragen willst. Wenn es 
binärdaten sind, wirst Du ja ne feste Paketgröße verwenden, d.h. Du 
kannst ndein Paket mit einem ASCII Frame mit startund endzeichen 
einpacken, in dem als z.B. zweiter parameter die Länge des Binärblock 
kommt.

Falls nach dieser Länge nicht Dein endbyte kommt, rückmeldung an den PC 
bitte paket noch mal schicken.

Die 255 als Startbyte definiertst musst Du z.B. die 254 noch als 
Excapezeichen missbrauchen, soll heißen wenn Du eine 245 oder 255 senden 
willst musst Du z.B. 254 und danach eine 1, bzw. 254 und eine 2 oder was 
Du als Code eben nehmen willst senden.

Gruß

Tom

von Volker S. (volkerschulz)


Lesenswert?

Hehe...

Mit der Methode von Karl Heinz wird der Overhead ja ziemlich 
unkalkulierbar. Und wenn einem das nichts ausmacht, weil man sowieso 
keine festen Wiederholungraten braucht, kann man auch gleich die Option 
mit der Zwangspause zwischen zwei Uebertragungen nehmen. Ist vermutlich 
einfacher zu implementieren. ;) Hinzu kommt dass eine solche Pause zum 
Synchronisieren sowieso alle paar Bytes erfolgen sollte.

Abgesehen davon ist der Overhead bei Uebertragung von nur einer 16- und 
einer 32-Bit-Zahl mit relativ hoher Wahrscheinlichkeit schon groesser 
als bei der Methode mit dem zusaetzlichen Bit. Koennte man ja mal genau 
ausrechnen, wenn's wirklich auf jede Millisekunde ankommt.

Dann koennte man noch ueberlegen, eine zusaetzlichen Pin zu benutzen 
(auf der EIA-232-Seite hat man da ja eh welche, der Mikrocontroller 
koennte auch noch einen Pin frei haben), der den Beginn einer 
Uebertragung signalisiert.

Volker

von Volker S. (volkerschulz)


Lesenswert?

Thomas Burkhart schrieb:
> Hängt auch davon ab, was für Daten Du übertragen willst.
> [...]

Hat er doch geschrieben. Ein paar 16- und 32-Bit-Zahlen. Ansonsten siehe 
meinen vorherigen Beitrag. ;)

Volker

von technikus (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Man kann sich natürlich auch noch ein Startbyte freischaufeln.
>
> zb. 0xFF wird nie in den Daten übertragen (oder irgendein anderer Wert
> der möglichst selten vorkommt. Oft ist es ja so, dass bestimmte Bytes
> häufig auftreten, andere wiederrum seltener)
>
> 0xFF ist das STartbyte
> muss in den Daten 0xFF übertragen werden, so wird stattdessen zb 0xFE
> 0x01 übertragen. Da jetzt 0xFE eine Sonderrolle zukommt, wird das
> ursprüngliche 0xFE als 0xFE 0x00 übertragen.
> Baut man diese Substitution tief unten in die Softwarelayer ein, so ist
> das alles für darüberliegende Softwareschichten transparent und sie
> merken nichts davon.

Dadurch dass ich Werte von 0x00 ... 0xFF übertragen muss, gibt es da 
kein Zeichen welches weniger oft vorkommt. Wahrscheinlich verstehe ich 
den Zusammenhang nicht, aber müsste dann nicht ein anderes Zeichen 
"frei" sein um ein Zeichen frei zu schaufeln und damit habe ich wieder 
den Salat, da ja keins frei ist.

Ich hatte schon überlegt die Bytes in zwei Einzelbytes zu Splitten und 
danach wieder zusammen zu bauen. Also bei einem 0xFF einmal 0x0F und 
danach nochmal 0x0F zu übertragen. Somit hätte ich alle Werte über 0x0F 
frei (quasi als Kennungen).
Ist so etwas üblich?

Gruß
ernst

von Peter (Gast)


Lesenswert?

So wird es z.b. bei hldc gemacht

http://de.wikipedia.org/wiki/High-Level_Data_Link_Control

Um zu vermeiden, dass innerhalb des Datenbereichs oder der Prüfsumme das 
Opening flag bzw Closing flag auftritt, wird Bitstopfen (bit stuffing) 
oder zero insertion angewandt. Dies bedeutet, dass innerhalb des Rahmens 
nach fünfmaligem Auftauchen der '1' eine '0' eingefügt wird, um eine 
Verwechslung mit einem Flag zu verhindern. Auf Empfängerseite wird eine 
'0' nach fünfmaligem Auftreten der '1' einfach wieder gelöscht.

von Karl H. (kbuchegg)


Lesenswert?

Volker Schulz schrieb:
> Hehe...
>
> Mit der Methode von Karl Heinz wird der Overhead ja ziemlich
> unkalkulierbar.

Ich sagte doch, dass das nur dann Sinn macht, wenn man einige Bytewerte 
nur relativ selten braucht. Wenn jedes zweite Byte substituiert wird, 
macht es nicht viel Sinn.

> Und wenn einem das nichts ausmacht, weil man sowieso
> keine festen Wiederholungraten braucht, kann man auch gleich die Option
> mit der Zwangspause zwischen zwei Uebertragungen nehmen. Ist vermutlich
> einfacher zu implementieren. ;)

Kommt drauf an.
Da musst du wieder eine Uhr mitlaufen haben

von Karl H. (kbuchegg)


Lesenswert?

technikus schrieb:

>> 0xFF ist das STartbyte
>> muss in den Daten 0xFF übertragen werden, so wird stattdessen zb 0xFE
>> 0x01 übertragen. Da jetzt 0xFE eine Sonderrolle zukommt, wird das
>> ursprüngliche 0xFE als 0xFE 0x00 übertragen.
>> Baut man diese Substitution tief unten in die Softwarelayer ein, so ist
>> das alles für darüberliegende Softwareschichten transparent und sie
>> merken nichts davon.
>
> Dadurch dass ich Werte von 0x00 ... 0xFF übertragen muss, gibt es da
> kein Zeichen welches weniger oft vorkommt.

In den meisten Fällen gibt es das aber.
Und selbst wenn tatsächlich alle Bytewerte in gleicher Häufigkeit 
auftauchen, so frisst dir die Substitution nur 2/256-tel der 
Übertragungskapazität.

> den Zusammenhang nicht, aber müsste dann nicht ein anderes Zeichen
> "frei" sein um ein Zeichen frei zu schaufeln und damit habe ich wieder
> den Salat, da ja keins frei ist.

Nein.
Der Trick besteht darin, dass man eine definierte Sequenz von 2 Zeichen 
hintereinander als 1 Zeichen missbraucht.

> danach wieder zusammen zu bauen. Also bei einem 0xFF einmal 0x0F und
> danach nochmal 0x0F zu übertragen.

Und du machst dir Sorgen weil 2 speziell ausgesuchte Bytewerte länger 
zur Übertragung benötigen?

> Somit hätte ich alle Werte über 0x0F
> frei (quasi als Kennungen).

Da kannst du auch gleich ASCII übertragen. Hat dann den Vorteil, dass du 
mit einem Terminal auch mitlesen kannst.

von Volker S. (volkerschulz)


Lesenswert?

Karl heinz Buchegger schrieb:
> Volker Schulz schrieb:
>> Hehe...
>>
>> Mit der Methode von Karl Heinz wird der Overhead ja ziemlich
>> unkalkulierbar.
>
> Ich sagte doch, dass das nur dann Sinn macht, wenn man einige Bytewerte
> nur relativ selten braucht. Wenn jedes zweite Byte substituiert wird,
> macht es nicht viel Sinn.

Ich bezog mich ja auch auf des Fragestellers 16- oder 32-Bit-Ints. Und 
da reicht's schon wenn bei je einer Zahl nur ein Byte substituiert wird. 
Deine Loesung ist ja in der Datenkommunikation auch durchaus ueblich, 
hier wuerde ich aber einen anderen Ansatz verfolgen. War alles andere 
als boese gemein!

>
>> Und wenn einem das nichts ausmacht, weil man sowieso
>> keine festen Wiederholungraten braucht, kann man auch gleich die Option
>> mit der Zwangspause zwischen zwei Uebertragungen nehmen. Ist vermutlich
>> einfacher zu implementieren. ;)
>
> Kommt drauf an.
> Da musst du wieder eine Uhr mitlaufen haben

Nicht zwingend. Wenn man sowieso dauernd pollt ob Daten reingekommen 
sind, kann man auch einfach zaehlen wie oft das nicht der Fall war. Bei 
einem Interrupt "on receive" wird das natuerlich nix. ;)

Volker

von Volker S. (volkerschulz)


Lesenswert?

technikus schrieb:
> Ich hatte schon überlegt die Bytes in zwei Einzelbytes zu Splitten und
> danach wieder zusammen zu bauen. Also bei einem 0xFF einmal 0x0F und
> danach nochmal 0x0F zu übertragen. Somit hätte ich alle Werte über 0x0F
> frei (quasi als Kennungen).
> Ist so etwas üblich?

Neee.. damit verdoppelst Du ja das Datenvolumen und laesst pro Byte 3 
Bits voellig ungenutzt rumliegen. Dann doch lieber 9N1, oder?

Volker

von Thomas B. (escamoteur)


Lesenswert?

Ich würde ein festes Frameformat verwenden, was spricht denn dagegen?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Ich würde einfach Hex-Zeichen übertragen, dann wären die ganzen schönen 
ASCII-Steuerzeichen frei, jedes uint16 wäre 4 Zeichen und ein uint32 
wäre 8 zeichen lang.
Und nachdem hier noch kein Wort zur benötigten Bandbreite/Datenrate 
aufgetaucht ist, darf ich das ohne Einschränkung tun. Es ist m.E. immer 
Käse, wenn auf einer seriellen Schnitte binäre Daten rumtigern. Man tut 
sich dann beim Mithören via Terminal immer so schwer... ;-)

von spess53 (Gast)


Lesenswert?

Hi

>Dann doch lieber 9N1, oder?

Falls das der PC mitmacht.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Thomas Burkhart schrieb:
> Ich würde ein festes Frameformat verwenden, was spricht denn dagegen?

Im Grunde gar nichts :-)
Denn genau darum geht es ja: Wie synchronisierst du dich denn mit dem 
'fixen Frameformat'. Woran erkennst du 100% zuverlässig den Frameanfang. 
Und zwar auch dann, wenn zwischendurch mal der Stecker gezogen und 
wieder eingesteckt wird.

Ist man erst mal synchron, dann ist das alles sowieso Makulatur. 
Interessant sind die Fälle, in denen ein Benutzer sein Anzeigegerät 
irgendwo anstopselt und auch noch korrekte Daten erwartet.
"Zuerst Gerät A einschalten und dann erst Gerät B, alles andere ist 
Benutzerfehler" konnte man zuletzt in den 60-er Jahren des letzten 
Jahrhunderts in die Gebrauchsanweisung schreiben. Heutzutage erwarten 
Benutzer, dass sie sich ohne Abschalten einfach einstöpseln und Dinge in 
beliebiger Reihenfolge einschalten können. Und dann muss alles immer 
noch sauber funktionieren.

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:
> Es ist m.E. immer
> Käse, wenn auf einer seriellen Schnitte binäre Daten rumtigern. Man tut
> sich dann beim Mithören via Terminal immer so schwer... ;-)

d´accore

Ganz zu schweigen von der elenden Rumrechnerei auf Byteebene bei der 
Fehlersuche. Und dann noch Hi-Byte zuerst / Low Byte zuerst?

Wird eine Serielle eingesetzt, dann soll es auf ein paar ms auf oder ab 
nicht ankommen :-)

von Volker S. (volkerschulz)


Lesenswert?

Karl heinz Buchegger schrieb:
> Lothar Miller schrieb:
>> Es ist m.E. immer
>> Käse, wenn auf einer seriellen Schnitte binäre Daten rumtigern. Man tut
>> sich dann beim Mithören via Terminal immer so schwer... ;-)
>
> d´accore
>
> Ganz zu schweigen von der elenden Rumrechnerei auf Byteebene bei der
> Fehlersuche. Und dann noch Hi-Byte zuerst / Low Byte zuerst?
>
> Wird eine Serielle eingesetzt, dann soll es auf ein paar ms auf oder ab
> nicht ankommen :-)

Und so'n Hex-Zeichen wird natuerlich nicht binaer uebertragen, oder wie? 
Und byteweise auch nicht? Und wenn doch, ist die Reihenfolge der Bytes 
nochmal wo festgeschrieben? ;)

Aber ich glaube, wir koennen erst nach weiteren Angaben von technikus 
den ultimativen Loesungsvorschlag waehlen.

Volker

von Karl H. (kbuchegg)


Lesenswert?

Volker Schulz schrieb:
> Karl heinz Buchegger schrieb:
>> Lothar Miller schrieb:
>>> Es ist m.E. immer
>>> Käse, wenn auf einer seriellen Schnitte binäre Daten rumtigern. Man tut
>>> sich dann beim Mithören via Terminal immer so schwer... ;-)
>>
>> d´accore
>>
>> Ganz zu schweigen von der elenden Rumrechnerei auf Byteebene bei der
>> Fehlersuche. Und dann noch Hi-Byte zuerst / Low Byte zuerst?
>>
>> Wird eine Serielle eingesetzt, dann soll es auf ein paar ms auf oder ab
>> nicht ankommen :-)
>
> Und so'n Hex-Zeichen wird natuerlich nicht binaer uebertragen, oder wie?
> Und byteweise auch nicht? Und wenn doch, ist die Reihenfolge der Bytes
> nochmal wo festgeschrieben? ;)

Nun ja. Festgeschrieben nicht.
Aber die übliche Konvention ist es dann doch, dass der Text "123" als 
hundert drei und zwanzig zu lesen ist.
Insofern ist die Übertragung von
"PA358,876;"
schon sehr eindeutig und lässt relativ wenig Spielraum für 
Fehlinterpretation.

> Aber ich glaube, wir koennen erst nach weiteren Angaben von technikus
> den ultimativen Loesungsvorschlag waehlen.

Ganz abgesehen davon, dass es "Die ultimative Lösung" nicht gibt :-)

von technikus (Gast)


Lesenswert?

Hallo,

erst einmal vielen Dank für eure rege Beteidigung!
Ihr macht es einem Hobby Programmierer ja ganz schön schwer ;-)

Um es konkret zu machen:
Ich möchte
- 2x 32Bit UInt
- 4x 16Bit UInt
übertragen. Im Mikrocontrollerprogramm sollen die Werte dann in ein 
EEPROM geschrieben und ein Reset ausgelöst werden.

Auf Anforderung des PC´s sollen die Daten dann zum PC gesendet und im 
GUI angezeigt werden.

Die Werte werden alle paar Schaltjahre angepasst und sollen nur zur 
Konfiguration an die Umgebung dienen.

Volker Schulz schrieb:
>> Ich hatte schon überlegt die Bytes in zwei Einzelbytes zu Splitten und
>> danach wieder zusammen zu bauen. Also bei einem 0xFF einmal 0x0F und
>> danach nochmal 0x0F zu übertragen. Somit hätte ich alle Werte über 0x0F
>> frei (quasi als Kennungen).
>> Ist so etwas üblich?
>
> Neee.. damit verdoppelst Du ja das Datenvolumen und laesst pro Byte 3
> Bits voellig ungenutzt rumliegen. Dann doch lieber 9N1, oder?

und

Lothar Miller schrieb:
> Ich würde einfach Hex-Zeichen übertragen, dann wären die ganzen schönen
> ASCII-Steuerzeichen frei, jedes uint16 wäre 4 Zeichen und ein uint32
> wäre 8 zeichen lang.

schließt das eine nicht das andere aus? Wenn ich hex Zeichen übertrage, 
brauche ich doch für ein Byte, z.B. 0xFE, zwei hex Zeichen. Also 'F' und 
'E'.


Volker Schulz schrieb:
> Und so'n Hex-Zeichen wird natuerlich nicht binaer uebertragen, oder wie?
> Und byteweise auch nicht? Und wenn doch, ist die Reihenfolge der Bytes
> nochmal wo festgeschrieben? ;)
>
> Aber ich glaube, wir koennen erst nach weiteren Angaben von technikus
> den ultimativen Loesungsvorschlag waehlen.


Ich verstehe im Moment wohl zu wenig.
Fest steht, dass ich 16Bytes übertragen muss. Bei der Möglichkeit 1Byte 
in die oberen 4Bit und unteren 4Bit zu trennen, müsste ich demnach 
32Bytes übertragen. <---Meint ihr das mit??? > Ich würde einfach 
Hex-Zeichen übertragen
So hätte ich ne Menge anderer Zeichen, z.B. für die Anforderung Daten 
zum PC senden, frei.

Gruß
ersnt

von Volker S. (volkerschulz)


Lesenswert?

Karl heinz Buchegger schrieb:
> Nun ja. Festgeschrieben nicht.
> Aber die übliche Konvention ist es dann doch, dass der Text "123" als
> hundert drei und zwanzig zu lesen ist.

Hehe.. da stimme ich zu. Lothar, mit dem du d'accord gegangen bist, 
hatte aber vorgeschlagen HEX-ASCII zu uebertragen. Und da sind durchaus 
verschiedene Konventionen ueblich. Und bei der Byteorder gehoert es 
eigentlich zum guten Ton, sie der Bitorder gleichzustellen, aber es 
haelt sich eben noch lange nicht jeder daran.


> Ganz abgesehen davon, dass es "Die ultimative Lösung" nicht gibt :-)

Fuer genau ein Problem ist die Moeglichkeit der ultimativen Loesung aber 
zumindest gegeben... Obwohl ich mir da auch nicht mehr 100%-ig sicher 
bin, seit ich dieses Forum kenne. ;)

Auf jeden Fall macht's Spass mit Euch zu diskutieren.

Volker

von Volker S. (volkerschulz)


Lesenswert?

technikus schrieb:
> Volker Schulz schrieb:
>>> Ich hatte schon überlegt die Bytes in zwei Einzelbytes zu Splitten und
>>> danach wieder zusammen zu bauen. Also bei einem 0xFF einmal 0x0F und
>>> danach nochmal 0x0F zu übertragen. Somit hätte ich alle Werte über 0x0F
>>> frei (quasi als Kennungen).
>>> Ist so etwas üblich?
>>
>> Neee.. damit verdoppelst Du ja das Datenvolumen und laesst pro Byte 3
>> Bits voellig ungenutzt rumliegen. Dann doch lieber 9N1, oder?
>
> und
>
> Lothar Miller schrieb:
>> Ich würde einfach Hex-Zeichen übertragen, dann wären die ganzen schönen
>> ASCII-Steuerzeichen frei, jedes uint16 wäre 4 Zeichen und ein uint32
>> wäre 8 zeichen lang.
>
> schließt das eine nicht das andere aus? Wenn ich hex Zeichen übertrage,
> brauche ich doch für ein Byte, z.B. 0xFE, zwei hex Zeichen. Also 'F' und
> 'E'.

Juppa.. Das eine hab ja auch ich gesagt, das andere Lothar. Und wir 
schliessen uns anscheinend gerne gegenseitig aus. ;)

Der Vorschlag von Lothar ist im Prinzip das, worauf Du auch schon 
gekommen bist.

Die Loesung wird so auch funktionieren, sie verschwendet eben nur 3 Bit 
pro Byte. Wenn Du aber nur wenige Daten und die auch nicht besonders 
schnell uebertragen musst, ist's so das einfachste.

Viel Erfolg!

Volker

von Karl H. (kbuchegg)


Lesenswert?

technikus schrieb:

> Um es konkret zu machen:
> Ich möchte
> - 2x 32Bit UInt
> - 4x 16Bit UInt
> übertragen. Im Mikrocontrollerprogramm sollen die Werte dann in ein
> EEPROM geschrieben und ein Reset ausgelöst werden.
>
> Auf Anforderung des PC´s sollen die Daten dann zum PC gesendet und im
> GUI angezeigt werden.
>
> Die Werte werden alle paar Schaltjahre angepasst und sollen nur zur
> Konfiguration an die Umgebung dienen.

Ganz klar: per ASCII Zeichen übertragen.
Schon alleine aus dem Grund, weil nach ein paar Schaltjahren das 
Einstellprogramm nicht mehr auffindbar ist und es dann jedes 
Billigsdorfer Terminalprogramm auch tut. Zeitkritisch ist das ganze 
offenbar auch nicht.


Protokoll:
Einleitender Buchstabe, der bestimmt welche Aktion ausgeführt werden 
soll
Dann die Zahl (oder Zahlen, zb mit Komma getrennt - meinetwegen auch als 
Hex-Zahl) und hinten nach noch ein \n. So kann nichts passieren und zum 
Entwickeln muss das Frontend-GUI auch noch nicht fertig sein.
Der µC empfängt eine Befehlszeile als String, holt sich die Einzelteile 
raus, wandelt die Stringrepräsentierung der Zahlen in echte Zahlen um 
(das sind 4-Zeiler) und führt die Aktion aus, bzw. umgekehrt: er liefert 
seine Werte wieder als ASCII Zahl (itoa ist dein Freund).

Das bischen Aufwand der Textübertragung würde ich eingehen. Alleine die 
unabhängige Testbarkeit der µC Ebene und der PC Ebene wäre mir das schon 
wert.

von Volker S. (volkerschulz)


Lesenswert?

Zum besseren Verstaendnis:

Lothar wuerde HEX-ASCII uebertragen. Also anstatt 0x0F wuerde er den 
Buchstaben F uebertragen. Aber das shiftet im Prinzip nur Deinen 
Vorschlag nach oben.

Volker

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Lothar wuerde HEX-ASCII uebertragen.
> Also anstatt 0x0F wuerde er den Buchstaben F uebertragen.
Ich würde das nicht, ich mache das ;-)
Eben so, dass ich das mit jedem xyz-beliebigen Terminal anzeigen und 
mithorchen könnte (zur Not an einem mechanischen mit Glocke 7).
In C gibts für die "erlaubten" Zeichen die Funktionen/Makros isalnum() 
oder etwas entschärft isprint(). Alle Andere sind für mich Steuerzeichen 
;-)

von technikus (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ganz klar: per ASCII Zeichen übertragen.
> Schon alleine aus dem Grund, weil nach ein paar Schaltjahren das
> Einstellprogramm nicht mehr auffindbar ist und es dann jedes
> Billigsdorfer Terminalprogramm auch tut. Zeitkritisch ist das ganze
> offenbar auch nicht.
>
>
> Protokoll:
> Einleitender Buchstabe, der bestimmt welche Aktion ausgeführt werden
> soll
> Dann die Zahl (oder Zahlen, zb mit Komma getrennt - meinetwegen auch als
> Hex-Zahl) und hinten nach noch ein \n. So kann nichts passieren und zum
> Entwickeln muss das Frontend-GUI auch noch nicht fertig sein.
> Der µC empfängt eine Befehlszeile als String, holt sich die Einzelteile
> raus, wandelt die Stringrepräsentierung der Zahlen in echte Zahlen um
> (das sind 4-Zeiler) und führt die Aktion aus, bzw. umgekehrt: er liefert
> seine Werte wieder als ASCII Zahl (itoa ist dein Freund).


O.K. meine Idee war ja die oberen und unteren 4 Bit zu trennen.
Die Idee hatt eich nur, weil ich da weiß, wie ich das im Programm 
umsetzen könnte.

Die c# Seite habe ich nun entsprechend angepasst. Erst wird ein 
Startzeichen gesendet. Darauf hin sende ich die Daten als Hex in 
Einzelzeichen.
Z.B.

'#'  'F'  'F'

was ja 255 entspricht. Wie baue ich denn jetzt die Daten so zusammen, 
dass ich ein Byte im EEPROM füllen kann?
1
//zusammen 255 dezimal
2
empfangspuffer[0]; //Inhalt 'F'
3
empfangspuffer[1]; //Inhalt 'F'



Gruß
ernst

von Volker S. (volkerschulz)


Lesenswert?

Ich nehme mal an, dass empfangspuffer ein Array vom Typ Byte und nicht 
vom Typ Char ist. Also ist der Inhalt von empfangspuffer[0] nicht 'F' 
(der Buchstabe) sondern 0x0F (der Hex-Wert), oder?

Binaer sieht der Inhalt dann so aus: 0b00001111.

Analog gilt das natuerlich auch fuer empfangspuffer[1].

Nun nimmst Du das Byte mit den 4 hoeherwertigen Bits und machst einen 
left shift um 4 Stellen. Nehmen wir mal an, empfangspuffer[0] hat die 
hoeherwertigen Bits, dann: empfangspuffer[0] << 4. Und nun werden die 
beiden noch ver-odert um die niederwertigen Bits anzuhaegen: 
empfangspuffer[0] | empfangspuffer[1]. Heraus kommt dann 0xFF bzw. 
0b11111111.

Fertig.

Volker

von Karl H. (kbuchegg)


Lesenswert?

technikus schrieb:

> Die c# Seite habe ich nun entsprechend angepasst. Erst wird ein
> Startzeichen gesendet. Darauf hin sende ich die Daten als Hex in
> Einzelzeichen.
> Z.B.
>
> '#'  'F'  'F'
>
> was ja 255 entspricht. Wie baue ich denn jetzt die Daten so zusammen,
> dass ich ein Byte im EEPROM füllen kann?
>
>
1
> //zusammen 255 dezimal
2
> empfangspuffer[0]; //Inhalt 'F'
3
> empfangspuffer[1]; //Inhalt 'F'
4
>

Mach dir eine Funktion, die einen 'Buchstaben' wieder in sein 
numerisches Äquivalent umwandelt
1
unsigned char ToNum( char digit )
2
{
3
  if( digit <= '9' )
4
    return digit - '0';
5
6
  return digit - 'A' + 10;
7
}

damit sollte es jetzt nicht weiter schwer sein, die Zahl wieder 
zusammenzusetzen
1
unsigned char ToNumber( char digit1, char digit2 )
2
{
3
  return ( ToNum( digit1 ) * 16 ) + ToNum( digit2 );
4
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Das Beispiel 0xFF ist jetzt ein wenig blöd, weil man High und Low-Nibble 
nicht mehr unterscheiden kann... :-/

Nehmen wir mal 0xA5 = 165dez --> ASCII '#' 'A' '5' --> in C
1
empfangspuffer[0]; // Inhalt 'A' Hex-Zahl in Großbuchstaben!!
2
empfangspuffer[1]; // Inhalt '5'
3
zahl  = empfangspuffer[0]-(empfangspuffer[0]<='9'?'0':'A'+10);
4
zahl <<= 4;
5
zahl += empfangspuffer[1]-(empfangspuffer[1]<='9'?'0':'A'+10);

von technikus (Gast)


Lesenswert?

Volker Schulz schrieb:
> Ich nehme mal an, dass empfangspuffer ein Array vom Typ Byte und nicht
> vom Typ Char ist. Also ist der Inhalt von empfangspuffer[0] nicht 'F'
> (der Buchstabe) sondern 0x0F (der Hex-Wert), oder?

O.K. das war mein erster Ansatz, hier war mir klar wie ich das erledige 
;-)

Durch oben stehende Diskussion wollte ich aber jetzt das Datenpaket als 
Zeichen '0'...'9' 'A'...'F' senden. Das heißt als Char
z.B. '0' = 48 ; 'A' = 65

ich müsste also aus
1
//zusammen 255 dezimal
2
empfangspuffer[0]; //Inhalt 'F'
3
empfangspuffer[1]; //Inhalt 'F'

255 dezimal "bauen".

HILFEEEEE ;-)

von technikus (Gast)


Lesenswert?

Bitte meine letzten Thread gedanklich zwei Beiträge zurückschieben  ;-)

Danke Leute, gucke ich mir morgen mit einem klaren Kopf an.


gruß
ernst

von Volker S. (volkerschulz)


Lesenswert?

technikus schrieb:
> Volker Schulz schrieb:
>> Ich nehme mal an, dass empfangspuffer ein Array vom Typ Byte und nicht
>> vom Typ Char ist. Also ist der Inhalt von empfangspuffer[0] nicht 'F'
>> (der Buchstabe) sondern 0x0F (der Hex-Wert), oder?
>
> O.K. das war mein erster Ansatz, hier war mir klar wie ich das erledige
> ;-)
>
> Durch oben stehende Diskussion wollte ich aber jetzt das Datenpaket als
> Zeichen '0'...'9' 'A'...'F' senden. Das heißt als Char

Du bist ja leicht zu beeinflussen! Und das Frame-Start-Bit hat auch 
gleich ein eigenes Byte bekommen! Ihr seid ja alle so dekadent! Koennen 
wir ja auf 5N1 runtergehen... ;)

Aber zum Zurueckkonvertieren aus HEXASCII wurde ja alles Wichtige 
gesagt. Zum besseren Verstaendnis schauste hier:

http://www.asciitable.com/

Freut mich dass wir eine Loesung gefunden haben, auch wenn's nicht meine 
war. Aber eine ultimative, sozusagen! ;)

Volker

von Volker S. (volkerschulz)


Lesenswert?

Karl heinz Buchegger schrieb:
> [...]
> damit sollte es jetzt nicht weiter schwer sein, die Zahl wieder
> zusammenzusetzen
>
>
1
> unsigned char ToNumber( char digit1, char digit2 )
2
> {
3
>   return ( ToNum( digit1 ) * 16 ) + ToNum( digit2 );
4
> }
5
>

Ah, das interessiert mich jetzt doch noch. Nicht dass hier einer der 
Beteiligten Wert auf Effizienz legen wuerde ;), aber ich programmiere 
die AVRs generell in ASM, daher ruehrt die Frage:

Was macht der C-Compiler aus
1
ToNum( digit1 ) * 16
?
Einen echten Shift oder multipliziert der tatsaechlich zu Fuss? Und wie 
sieht das auf einem AVR ohne Hardware-Multiplizierer aus?

Volker

von Karl H. (kbuchegg)


Lesenswert?

Volker Schulz schrieb:

> Was macht der C-Compiler aus
>
1
> ToNum( digit1 ) * 16
2
>
> ?
> Einen echten Shift

Du kannst dich darauf verlassen, dass der Compilerbauer seinem Kindchen 
die Fähigkeit mitgegeben hat, einfache Multiplikationen mit 2-er 
Potenzen zu erkennen und durch Shifts zu ersetzen, wenn es möglich und 
schneller ist. Aber Compiler erkennen auch komplexere Fälle und ersetzen 
diese durch Shift-Additionssequenzen, wenn dies möglich UND tatsächlich 
schneller ist.

(zb: 10 * x  <==>  ( ( x << 2 ) + x ) << 1 )

Wenn ein Compiler diese simple Optimierung nicht kann, besteht die 
Lösung nicht darin, selber Hand anzulegen sondern den Compiler zu 
wechseln. Denn dann ist er Müll.

Fazit: Solche Low-Level Optimierungen überlasst man besser dem Compiler. 
Als Programmierer schreibt man so, wie es für den Programmierer am 
besten zu lesen ist und wie es der Situation am besten entspricht.

Bei obigem ist es so ein Grenzfall:
Logisch gesehen wäre beides akzeptabel.
Die Sichtweise: Die Zahl ergibt sich, indem das Nibble zurechtegschoben 
wird
Aber auch die Sichtweise: Bei einer Zahl zur Basis 16 unterscheiden sich 
die einzelnen Stellen durch einen Faktor 16.
Ursprünglich hatte ich einen Shift, hab dann aber umgedreht, als in 
seiner letzten Anfrage die Frage auftauchte, wie man aus 'F' 'F' die 
Dezimalzahl 255 zusammenbaut.

von Volker S. (volkerschulz)


Lesenswert?

Karl heinz Buchegger schrieb:
> Volker Schulz schrieb:
>
>> Was macht der C-Compiler aus
>>
1
>> ToNum( digit1 ) * 16
2
>>
>> ?
>> Einen echten Shift

Das ist ja schonmal gut. Kann man in C auch einen SWAP veranlassen? Dann 
muesste man ja nochmal 75% der cycles einsparen...

Ich weiss, ich bin pedantisch.... Aber einer muss ja mal fragen! ;)

Volker

von Karl H. (kbuchegg)


Lesenswert?

Volker Schulz schrieb:

> Das ist ja schonmal gut. Kann man in C auch einen SWAP veranlassen?

Das musst du ausprobieren.
AUf Hochsprachenebene gibt es keine einzelne Operation, die einem SWAP 
entsprechen würde. Das geht nur mit einer Kombination. Von daher halte 
ich die Chance eher für gering. Aber wie heißt es so schön: Du sollst 
dich nicht täuschen.

von Volker S. (volkerschulz)


Angehängte Dateien:

Lesenswert?

Thanks for the info!

Volker

von Karl H. (kbuchegg)


Lesenswert?

Hmm. Einen Kaffee später

Die Operation
  uint8_t i;

  i = 16*i;

könnte man ja mit der Assemblersequenz

  swap  i
  and   i, 0xF0

implementieren. Wenn der Optimizer das so sieht, steigen die Chance auf 
deinen Swap wieder.

Bei einem reinen AVR Compiler würde ich das als gar nicht mal so 
schlecht sehen.
Das Problem:
C fordert, dass 16*i in int gerechnet wird. Der gcc als 
Universalcompiler für alle Maschinen, hält sich natürlich daran. D.h. er 
hat das zusätzliche Problem, dass sich zwischendurch die Berechnung (in 
diesem Fall unnötigerweise) auf 16 Bit aufbläst um dann vom Optimizer 
wieder auf 8 Bit zurechtgestutzt zu werden. Und wir wissen, dass dieses 
Zurechtstutzen schon manchmal in die Hose geht :-(

(Und nein. Letztes Problem würde auch dann auftauchen, wenn da ein 
expliziter Shift stehen würde)

von Volker S. (volkerschulz)


Lesenswert?

Und in diesem spieziellen Fall waere ja sogar nur der SWAP noetig und 
man koennte sich das AND sparen, da das obere Nibble (dank der 
dekandenten Uebertragungsweise) ja sowieso nichts anderes als 0 sein 
kann. Aber das kann der Compiler natuerlich nicht wissen. ;)

Volker

von Thomas B. (escamoteur)


Lesenswert?

Noch mal zur ursprünglichen Fragestellung. Wozu der aufwand mit 
Codierung von start/stoppzeichen wenn ich ein frameformat verwenden kann 
in dem jeweils drin steht wie lange mein Datenblock ist.

Gruß
Tom

von Volker S. (volkerschulz)


Lesenswert?

Thomas Burkhart schrieb:
> Noch mal zur ursprünglichen Fragestellung. Wozu der aufwand mit
> Codierung von start/stoppzeichen wenn ich ein frameformat verwenden kann
> in dem jeweils drin steht wie lange mein Datenblock ist.

Weil der Empfaenger im Zweifel nicht weiss wo der Frame anfaengt... Und 
somit natuerlich auch nicht, wo die Laenge steht.

Volker

von Karl H. (kbuchegg)


Lesenswert?

Thomas Burkhart schrieb:
> Noch mal zur ursprünglichen Fragestellung. Wozu der aufwand mit
> Codierung von start/stoppzeichen wenn ich ein frameformat verwenden kann
> in dem jeweils drin steht wie lange mein Datenblock ist.


Und als Beispiel:
Du klinkst dich in eine Übertragung ein und empfängst

04 00 03 05 02 01 08 56 03 ...

welches ist die richtige Interpretation?
Du weißt nicht, was vor dem 04 kam. Sind diese 04 die letzten Bytes 
eines vorhergehenden Datensatzes oder sind sie dein Längenbyte?

ist das zb so zu lesen

     .. 04 00     // wird verworfen
 03  05 02 01
 08  56 03 ....

oder vielleicht so

     .. 04 00 03
 05  02 01 08 56 03
 ...

oder eventuell so

     .. 04 00 03 05
 02  01 08
 56  03 ...

oder eventuell gar
 04  00 03 05 02
 01  08
 56  03  ...

Je nachdem ergeben sich ganz unterschiedliche Interpretationen, wenn man 
nicht sicher sein kann, dass das erste Byte, welches empfangen wird, 
auch tatsächlich das erste Byte deines Frames ist.

Wenn alles glatt läuft und der Empfänger aufnahmebereit ist ehe der 
Sender zu senden anfängt, hast du den Fall nicht. Aber im Fehlerfall 
kommt das schon vor. zb: Die Übertragung läuft schon, wenn sich der 
Empfänger aufschaltet, Kabel wird von der Putzfrau abgezogen und wieder 
aufgesteckt. Der Empfänger war durch Berechnungen zu lange beschäftigt 
und hat ein Byte verschlafen, Bufferüberlauf beim Empfänger, etc...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> wenn ich ein frameformat verwenden kann
> in dem jeweils drin steht wie lange mein Datenblock ist.
Wozu ein aufwendiges Frameformat (incl. entsprechend aufwendiger 
Auswertung) definieren, wenn es einfacher geht? Was könnte einfacher 
sein als nur auf das Ende-Zeichen zu warten, und dann die vorhergehenden 
Zeichen auszuwerten?
1
    if(UCSRA&(1<<RXC)) { // Zeichen über SIO angekommen?
2
        char ch=UDR;
3
        if(ch==STX) {    // Wenn STX: Schreibzeiger zurücksetzen
4
           idx=0;
5
        }
6
        else {
7
           if(ch==ETX) { // Endezeichen -- in 0 umwandeln zur Stringterminierung
8
              ch=0;
9
              datavalid=1;
10
           }
11
           buf[idx]=ch;
12
           if(idx<MAXCHAR-1) idx++; // Schutz vor Pufferüberlauf
13
           else              overflow=1;
14
        }
15
    }

von Volker S. (volkerschulz)


Lesenswert?

Lothar Miller schrieb:
>> wenn ich ein frameformat verwenden kann
>> in dem jeweils drin steht wie lange mein Datenblock ist.
> Wozu ein aufwendiges Frameformat (incl. entsprechend aufwendiger
> Auswertung) definieren, wenn es einfacher geht? Was könnte einfacher
> sein als nur auf das Ende-Zeichen zu warten, und dann die vorhergehenden
> Zeichen auszuwerten?

Darum ging es ja die ganze Zeit: Es sollten volle 8 Bit uebertragen 
werden und es war kein Platz fuer Steuerzeichen da. ;)


Karl heinz Buchegger schrieb:
> [...]
> Und als Beispiel:
> Du klinkst dich in eine Übertragung ein und empfängst
> [...]

Fairerweise muss man aber auch anmerken dass das "Einklinken" bei 
serieller Uebertragung ohnehin nicht ganz unproblematisch ist. Das kann 
immerhin auch in der Mitte von einem Byte passieren und synchronisieren 
kann sich der Empfaenger erst nach einer entsprechenden Pause zwischen 2 
Bytes (die so aber in der Spec nirgendwo explizit gefordert wird).

Volker

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Volker Schulz schrieb:
> Darum ging es ja die ganze Zeit: Es sollten volle 8 Bit uebertragen
> werden und es war kein Platz fuer Steuerzeichen da. ;)
Aber davon sind wir doch aus pragmatischen Gründen schon lange 
abgekommen, dekadent wie wir sind... ;-)

von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:

> sein als nur auf das Ende-Zeichen zu warten, und dann die vorhergehenden
> Zeichen auszuwerten?
>
1
>     if(UCSRA&(1<<RXC)) { // Zeichen über SIO angekommen?
2
>         char ch=UDR;
3
>         if(ch==STX) {    // Wenn STX: Schreibzeiger zurücksetzen
4
>            idx=0;
5
>         }
6
>         else {
7
>            if(ch==ETX) { // Endezeichen -- in 0 umwandeln zur
8
> Stringterminierung
9
>               ch=0;
10
>               datavalid=1;
11
>            }
12
>            buf[idx]=ch;
13
>            if(idx<MAXCHAR-1) idx++; // Schutz vor Pufferüberlauf
14
>            else              overflow=1;
15
>         }
16
>     }
17
>

Fast.
Ich würde hier

>            if(ch==ETX) { // Endezeichen -- in 0 umwandeln zur
> Stringterminierung
>               ch=0;
>               datavalid=1;
>            }

noch eine Überprüfung reinsetzen, ob das STX überhaupt gesehen wurde und 
den Datensatz erst dann freigeben (und die STX-gesehen Kennung wieder 
zurücksetzen).

von Volker S. (volkerschulz)


Lesenswert?

Lothar Miller schrieb:
> Volker Schulz schrieb:
>> Darum ging es ja die ganze Zeit: Es sollten volle 8 Bit uebertragen
>> werden und es war kein Platz fuer Steuerzeichen da. ;)
> Aber davon sind wir doch aus pragmatischen Gründen schon lange
> abgekommen, dekadent wie wir sind... ;-)

Jaja... ICH hab das ja auch nicht wieder aufgewaermt... :)

Volker

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Ich würde hier... noch eine Überprüfung reinsetzen, ob das STX überhaupt
> gesehen wurde und den Datensatz erst dann freigeben (und die STX-gesehen
> Kennung wieder zurücksetzen).
Das ist in meiner Original-Routine schon drin. Es werden die STX und die 
ETX mitgezählt, und nur bei Gleichstand gilt das Telegramm als gültig. 
Dazu kommt dann noch eine Kontrolle der Prüfsumme und eine Längenprüfung 
des gesamten Telegramms  (über den idx)...  ;-)

von technikus (Gast)


Lesenswert?

Volker Schulz schrieb:
> Du bist ja leicht zu beeinflussen! Und das Frame-Start-Bit hat auch
> gleich ein eigenes Byte bekommen!

Ich bin eben nur Hobby Programmierer und bei meinen Spielereien  auf 
euch angewiesen. Deswegen auch schnell beeinflussbar ;-)
Ob jetzt 10 oder 30 Bytes übertragen werden ist bei meiner Anwendung 
auch egal.

Die Mikrocontroller Seite programmiere ich die Tage, PC (c#) Seite 
steht.

Ein interessanter Beitrag ist das hier geworden!

Tolles Forum ;-)
Ich danke allen Beteiligten!

Gruß
ernst

von Thomas B. (escamoteur)


Lesenswert?

Volker Schulz schrieb:
> Jaja... ICH hab das ja auch nicht wieder aufgewaermt... :)
>
> Volker

Ok,ok, ich hatte nicht mitbekommen, dass Ihr jetzt komplett in Hex 
übertragt. Dachte Ihr seid noch am wilden escapen.

Das Problem mit dem Aufsetzen war mir schon klar. Nur wenn ich weiß wie 
lang meine Pakete sind (geht natürlich nur wenn das immer gleich ist) 
dann weiß ich nach wie vielen Bytes spätestens wieder mein Header kommen 
müsste und wenn der da nicht kommt, dann muss bei Sender nachgefragt 
werden.

Aber wie ihr schon gesagt habt, wir sind dekadent und wollen am Analyser 
ja mitlesen können :-)

Gruß
Tom

von Karl H. (kbuchegg)


Lesenswert?

Thomas Burkhart schrieb:

> Ok,ok, ich hatte nicht mitbekommen, dass Ihr jetzt komplett in Hex
> übertragt. Dachte Ihr seid noch am wilden escapen.

ASCII ist das Schlüsselwort. Ob da jetzt Hex-Zahlen hin und her 
flutschen oder Dezimalzahlen spielt keine Rolle. Hauptsache als Text 
(wodurch die restlichen Buchstaben des Alphabets als Steuerzeichen frei 
werden)

> Das Problem mit dem Aufsetzen war mir schon klar. Nur wenn ich weiß wie
> lang meine Pakete sind (geht natürlich nur wenn das immer gleich ist)

damit haben wir schon Voraussetzung Nummer 1

> dann weiß ich nach wie vielen Bytes spätestens wieder mein Header kommen
> müsste und wenn der da nicht kommt, dann muss bei Sender nachgefragt
> werden.

und das ist dann Voraussetzung Nummer 2

Und wie gehst du das Problem an, dass du ein falsches Byte als Start 
deines Headers (woran erkennst du denn den?) fehlinterpretierst?

Und dann kommt da noch Voraussetzung Nummer 3:

Der Sender muss in der Lage sein auf dich zu hören, seine aktuelle 
Übertragung abzubrechen und dir garantiert einen Frameanfang 
vorzusetzen.

Mit dezidierten Start/Stop Sequenzen, die eindeutig erkennbar sind, 
braucht es all diese Voraussetzungen nicht. Der Sender schickt einfach 
raus und der Empfänger kann eindeutig, auch nach einem Fehler, den 
Frameanfang im Datenstrom finden.


> Aber wie ihr schon gesagt habt, wir sind dekadent und wollen am Analyser
> ja mitlesen können :-)

Und falls wir das nicht wollen, sind wir auch dekadent genug, den 
Datenstrom so aufzubereiten, dass der Empfänger keine Rückfragen braucht 
:-) Wir sind nämlich nicht nur dekadent sondern auch faul :-) Wird 
Funktionalität nicht benötigt (weil überflüssig), muss sie im Sender 
auch nicht implementiert werden. Der Empfänger muss keine wilden 
Verrenkungen machen um festzustellen ob nicht eigentlich schon ein 
Header vorliegen müsste etc.
Im Vergleich dazu ist die Auswertung von Start /Stopp Bytes im Empfänger 
geradezu ein Spaziergang.

Ein kleiner Schritt für Sender/Empfänger. Ein großer Schritt für die 
Interpretationssicherheit beim Empfänger.

von technikus (Gast)


Lesenswert?

Hallo,


es läuft  :-))

Folgende Funktion rufe ich jetzt in der Hauptschleife auf:
1
uint8_t dataRead(void)
2
{
3
  uint16_t c;
4
  static uint8_t i;
5
  
6
    c = uart_getc();          //UART Datenempfang
7
    
8
        if (!( c & UART_NO_DATA ))      //Daten wurden Empfangen
9
    {
10
    
11
      if ((unsigned char)c=='#'){    //Startzeichen vorhanden?
12
        i=0;
13
        }
14
      else{
15
        buffer[i]=(unsigned char)c;  //Empfangenes zeichen speichern
16
        i++;
17
        }    
18
    }
19
20
    //22 Byte angekommen?
21
    if (i==22)
22
      return 1;
23
    else
24
      return 0;
25
26
}

Nachdem die 22 Bytes gefüllt wurden, schreibe ich die Variablen 
entsprechend oben genanntem Beispiel.
1
frequenz1.value8.b4=ToNumber(buffer[0],buffer[1]);      
2
3
frequenz1.value8.b3=ToNumber(buffer[2],buffer[3]);      
4
5
frequenz1.value8.b2=ToNumber(buffer[4],buffer[5]);      
6
7
frequenz1.value8.b1=ToNumber(buffer[6],buffer[7]);

Für 11Bytes Nutzdaten sende ich jetzt 22+1Byte(Startzeichen). Dafür habe 
ich jetzt noch einige Zeichen frei um andere Aktionen im Controller 
auszuführen.



Gruß
ernst

von Volker S. (volkerschulz)


Lesenswert?

technikus schrieb:
> es läuft  :-))

Das freut mich!


>
1
>     //22 Byte angekommen?
2
>     if (i==22)
3
>       return 1;
4
>     else
5
>       return 0;
6
> 
7
>

Es waere vielleicht noch sinnvoll, das innerhalb des aeusseren If-Blocks 
zu packen und danach die funktion zu verlassen. Denn:

1.) wird i ja nur zu 22 wenn auch vorher ein Zeichen empfangen wurde

und

2.) bleibt i ja 22 bis dann wieder ein neues Start-Byte empfangen wurde.

und wenn es gar nicht erst in den If-Block geht, kannste ja immer 0 
zurueckgeben.


>
1
> frequenz1.value8.b4=ToNumber(buffer[0],buffer[1]);
2
> 
3
> frequenz1.value8.b3=ToNumber(buffer[2],buffer[3]);
4
> 
5
> frequenz1.value8.b2=ToNumber(buffer[4],buffer[5]);
6
> 
7
> frequenz1.value8.b1=ToNumber(buffer[6],buffer[7]);
8
>

Wenn es das gewuenschte Ergebnis liefert: Gut. Aber woher weiss 
"ToNumber" denn wie es das konvertieren soll?


Volker

von technikus (Gast)


Lesenswert?

Volker Schulz schrieb:
> Es waere vielleicht noch sinnvoll, das innerhalb des aeusseren If-Blocks
> zu packen und danach die funktion zu verlassen. Denn:
>
> 1.) wird i ja nur zu 22 wenn auch vorher ein Zeichen empfangen wurde
>
> und
>
> 2.) bleibt i ja 22 bis dann wieder ein neues Start-Byte empfangen wurde.
>
> und wenn es gar nicht erst in den If-Block geht, kannste ja immer 0
> zurueckgeben.

1
uint8_t dataRead(void)
2
{
3
  uint16_t c;
4
  static uint8_t i;
5
  
6
    c = uart_getc();          //UART Datenempfang
7
    
8
        if (!( c & UART_NO_DATA ))      //Daten wurden Empfangen
9
    {
10
    
11
      if ((unsigned char)c=='#'){    //Startzeichen vorhanden?
12
        i=0;
13
        }
14
      else{
15
        buffer[i]=(unsigned char)c;  //Empfangenes zeichen speichern
16
        i++;
17
        }  
18
        
19
    //22 Byte angekommen?
20
    if (i==22)
21
      return 1;
22
  
23
    }
24
25
    
26
    return 0;
27
}


Also so?

Das oben gepostete Beispiel hatte ich "mal eben" so zusammen getippt. 
Der Fehler ist nicht aufgefallen, da ich, nachdem ein kompletter Frame 
angekommen ist, einen Reset des Controllers ausführe indem der Watchdog 
angeschmissen wird und in eine Endlosschleife verharrt. Nach einem Reset 
ist i ja wieder 0...trotzdem blöd...




Volker Schulz schrieb:
> Wenn es das gewuenschte Ergebnis liefert: Gut. Aber woher weiss
> "ToNumber" denn wie es das konvertieren soll?
1
unsigned char ToNumber( char digit1, char digit2 )
2
{
3
  return ( ToNum( digit1 ) * 16 ) + ToNum( digit2 );
4
}
5
6
7
unsigned char ToNumber( char digit1, char digit2 )
8
{
9
  return ( ToNum( digit1 ) * 16 ) + ToNum( digit2 );
10
}

=> Hatte ich ja oben von Karl Heinz "geklaut".


Gruß
Ernst

von Volker S. (volkerschulz)


Lesenswert?

technikus schrieb:
> Volker Schulz schrieb:
>> Es waere vielleicht noch sinnvoll, das innerhalb des aeusseren If-Blocks
>> zu packen und danach die funktion zu verlassen. Denn:
>>
>> 1.) wird i ja nur zu 22 wenn auch vorher ein Zeichen empfangen wurde
>>
>> und
>>
>> 2.) bleibt i ja 22 bis dann wieder ein neues Start-Byte empfangen wurde.
>>
>> und wenn es gar nicht erst in den If-Block geht, kannste ja immer 0
>> zurueckgeben.
>
> [...]
>
> Also so?
>
> Das oben gepostete Beispiel hatte ich "mal eben" so zusammen getippt.
> Der Fehler ist nicht aufgefallen, da ich, nachdem ein kompletter Frame
> angekommen ist, einen Reset des Controllers ausführe indem der Watchdog
> angeschmissen wird und in eine Endlosschleife verharrt. Nach einem Reset
> ist i ja wieder 0...trotzdem blöd...

Ja, so hatte ich mir das gedacht. Haette ja sonst im besten Falle nur 
Zeit gekostet, im schlimmsten Falle haettest Du aber einen Datensatz X 
Mal ausgewertet. Aber bei einem Reset faellt das natuerlich nicht auf. 
;)


> Volker Schulz schrieb:
>> Wenn es das gewuenschte Ergebnis liefert: Gut. Aber woher weiss
>> "ToNumber" denn wie es das konvertieren soll?
>
> [...]
>
> => Hatte ich ja oben von Karl Heinz "geklaut".

Ahja, verdammt... Hatte nur noch den Namen der eigentlichen Funktion 
"ToNum" im Sinn und dachte, Du machst ploetzlich was anderes... ;)


Volker

von technikus (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Protokoll:
> Einleitender Buchstabe, der bestimmt welche Aktion ausgeführt werden
> soll
> Dann die Zahl (oder Zahlen, zb mit Komma getrennt - meinetwegen auch als
> Hex-Zahl) und hinten nach noch ein \n. So kann nichts passieren und zum
> Entwickeln muss das Frontend-GUI auch noch nicht fertig sein.
> Der µC empfängt eine Befehlszeile als String, holt sich die Einzelteile
> raus, wandelt die Stringrepräsentierung der Zahlen in echte Zahlen um
> (das sind 4-Zeiler) und führt die Aktion aus, bzw. umgekehrt: er liefert
> seine Werte wieder als ASCII Zahl (itoa ist dein Freund).

Hallo,

ich denke das passt hier weiter ganz gut in den Thread.

Im PC Programm erwarte ich jetzt ebenso die Werte als Hex codierten 
String.
Karl Heinz hatte geschrieben dass itoa hier mein Freund ist.

Ich möchte jetzt die Daten, auf Aufforderung vom PC, zum PC senden.
Ich nutze nun unten stehenden Code:
1
  char puffer[5];
2
  char sendData[23];
3
4
//--Startzeichen
5
  strcpy(sendData,"#");          
6
7
//--Frequenz Stufe 1
8
  itoa(frequenz1.value8.b4,puffer,16);
9
  strcat(sendData,puffer);
10
11
  itoa(frequenz1.value8.b3,puffer,16);
12
  strcat(sendData,puffer);
13
14
  itoa(frequenz1.value8.b2,puffer,16);
15
  strcat(sendData,puffer);
16
17
  itoa(frequenz1.value8.b1,puffer,16);
18
  strcat(sendData,puffer);
19
20
21
//usw.
22
23
//--Daten senden
24
  uart_puts(sendData);
25
  uart_puts("\n");

Erstens erzeugt itoa hier kleine Buchstaben wie z.B. ff für 255.
Ich kann das relativ einfach im c# Programm auf Großbuchstaben umbauen, 
hätte nur gerne die gleiche Formatierung wie im Sendeframe vom PC zum 
Mikrocontroller, also Großbuchstaben.
Zweitens werden keine Nullen im String angehangen wenn die Variable
1
frequenz1.value8.bx = 0;

Da ich aber den kompletten Inhalt übertragen möchte,

z.B.
'#' '0' '0' '0' '0' '0' '0' 'F' 'F'

für 255

passt itoa so nicht.

Trotz Forensuche habe ich nicht wirklich eine Lösung gefunden die mir 
das gewünschte Ergebnis liefert.

Ich könnte mir da mit If abfragen ob da ne null drin ist und dann 
"händisch" die nullen im String anhängen. Jedoch gefällt mir diese 
Lösung nicht.

Gibt es da etwas fertiges?


Gruß
ernst

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Gibt es da etwas fertiges?
sprintf(string,"#%08X",wert);
heißt die Funktion die du suchst...

von technikus (Gast)


Lesenswert?

Hallo Lothar,

ich hätte es erwähnen sollen, sprintf kannte ich schon und hatte ich 
auch damals in der Schule benutzen müssen. Da sich der Code aber so 
ungemein aufbläht, suche ich nach etwas anderem.

Gruß
Ernst

von technikus (Gast)


Lesenswert?

Habe mal etwas zusammen getippt:
1
void itohex(uint8_t n, char *s)
2
{
3
  //obere 4 Bit 
4
  if ((n>>4)>9)
5
    s[0]=(n>>4)+55;
6
  else
7
    s[0]=(n>>4)+48;
8
    
9
  //untere 4 Bit
10
  if ((n&0x0F)>9)
11
    s[1]=(n&0x0F)+55;
12
  else
13
    s[1]=(n&0x0F)+48;
14
    
15
  s[2]=0;    //String mit 0 abschließen
16
}


Allerdings komme ich im moment nicht an die Harware ran.
Ich habe noch nie mit Strings als "Rückgabewert" in Funktionen 
gearbeitet, von daher kann das hier auch großer Mist sein.

Feedback?


Gruß
ernst

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Du darfst auch ohne Einschränkungen leserlich so schreiben:
1
  if ((n>>4)>9)
2
    s[0]=(n>>4)-10+'A';
3
  else
4
    s[0]=(n>>4)+'0';
Dann hast du keine solchen Magic Numbers und siehst später besser, was 
damit eigentlich gemeint ist...
Sonst kommst du irgendwann mal auf die Frage, was das soll:
1
  if ((n>>4)>9)
2
    s[0]=(n>>4)+'7';
3
  else
4
    s[0]=(n>>4)+'0';

> Ich habe noch nie mit Strings als "Rückgabewert" in Funktionen
> gearbeitet
Hier wird gar nichts zurückgegeben, da steht ein void als 
Rückgabeparameter. Du manipulierst nur wie üblich über einen 
char-Pointer ein (hoffentlich ausreichend großes) char-Array (aka. 
String).

von technikus (Gast)


Lesenswert?

Danke!


Lothar Miller schrieb:
>> Ich habe noch nie mit Strings als "Rückgabewert" in Funktionen
>> gearbeitet
> Hier wird gar nichts zurückgegeben, da steht ein void als
> Rückgabeparameter. Du manipulierst nur wie üblich über einen
> char-Pointer ein (hoffentlich ausreichend großes) char-Array (aka.
> String).

Deswegen Rückgabewert in ""

ernst

von technikus (Gast)


Lesenswert?

Und läuft auch mit der Int nach Hex Funktion!
Ich danke allen Beteiligten.


ernst

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.