Forum: Mikrocontroller und Digitale Elektronik uint16_t array über UART übertragen


von Matthias P. (matt-eagle)


Lesenswert?

Hallo zusammen,

ich habe zwar einen ähnlichen Thread 
Beitrag "UART Daten binär übertragen" zu meiner Frage 
gefunden, möchte es aber trotzdem fragen.

Ich möchte ein uint16_t Array mit vorerst einem Messwert der eine 
Auflösung von 10Bit hat an ein C#-Programm übertragen, womit ich über 
die ReadByte-Funktion den Wert wieder in ein Array einfüge. Ich weiß, 
dass der Wert aus dem Array byteweise durch die UART gesendet wird.
Muss ich das nun als String (wenn ja per sprintf?) oder reicht es, wenn 
ich folgendes mache:
1
uint16_t wert[]={gemessener Wert};
2
void SendUART(char var);
3
{
4
   while(!(Senderegister(1<<Statusbit)));
5
   udr=var;
6
}
7
int main(void)
8
{
9
   .
10
   .
11
   .
12
   SendUART(wert);
13
   .
14
   . 
15
   .
16
}

Das ist für mich leider alles Neuland. Einfache 1 Bytevariablen habe ich 
schon senden und empfangen können. Hierbei steh ich aber auf dem 
Schlauch.

Gruß Matt-Eagle

von Peter II (Gast)


Lesenswert?

Matthias P. schrieb:
> Ich weiß,
> dass der Wert aus dem Array byteweise durch die UART gesendet wird.
schon mal gut

> Muss ich das nun als String (wenn ja per sprintf?) oder reicht es, wenn
> ich folgendes mache:
nein.

Du musst die 16bit (2byte) erst auf 2 einzelne Bytes aufteilen und diese 
dann versenden.
1
uint8_t byte1 = wert >> 8;
2
uint8_t byte2 = wert & 0xFF;

beim empfangen muss die die 2 Bytes wieder zusammensetzen. Da du damit 
aber ein Binäres Übertragung hast muss du dir auch noch Gedanken über 
ein Protokoll machen. Woher weisst du wo das Array beginnt und endet?

von Karl H. (kbuchegg)


Lesenswert?

Matthias P. schrieb:

> Muss ich das nun als String

'Müssen' tust du gar nichts.
Wenn du den Zahlenwert in Form eines Textes übertragen möchtest, dann 
kannst du das tun.
Willst du das nicht tun (weil du zuerst die Zahl in eine Textform 
bringen musst um den Text zu senden, bzw. der Empfänger erst wieder aus 
dem Text eine Zahl machen muss), dann kannst du das natürlich auch 
lassen und den Binärwert so wie er ist übertragen.


> oder reicht es, wenn
> ich folgendes mache:

> void SendUART(char var);

Das hier sendet ganz offensichtlich nur 1 Byte. Ein 16-Bit Wert besteht 
aber aus 2 Bytes.

Das ist wie wenn du eine Vertrag hast, der aus 2 Blatt beschriebenem 
Papier besteht. Wenn du den Vertrag faxen willst, dann musst du eben 2 
Blätter übertragen und nicht nur eines. 1 Faxsendung == 1 Blatt Papier. 
Hast du mehrere Blätter, dann musst du halt auch mehrere Blätter durch 
das Fax lassen. In diesem Sinne ist diese Send Funktion eine Funktion, 
die genau 1 Blatt Papier überträgt. Hast du mehrere Blätter, dann musst 
du die Funktion eben entsprechend öfter benutzen.
Hast du gar eine Mappe mit vielen Verträgen (ein Array), dann  musst du 
eben entsprechend oft die Funktion benutzen, die 1 Vertrag (in Form von 
2 Blättern) überträgt.

: Bearbeitet durch User
von Matthias P. (matt-eagle)


Lesenswert?

Peter II schrieb:

> beim empfangen muss die die 2 Bytes wieder zusammensetzen. Da du damit
> aber ein Binäres Übertragung hast muss du dir auch noch Gedanken über
> ein Protokoll machen. Woher weisst du wo das Array beginnt und endet?

Erstmal danke, ich kannte noch gar nicht diese Schreibweise um einen 
16Bit-Wert aufzusplitten. Das Hilft schon mal ungemein.
Ich habe eine feste Arraygröße, von daher kann ich mit Schleifen 
arbeiten. Außer diesem Array wird nichts übertragen, mein Gedanke wäre 
noch ein zusätzliches Zeichen das vor der Übertragung gesendet wird und 
dann eine FOR-Schleife in meinem C#-Programm auslöst, in der dann die 
folgenden Daten in das Zielarray eingespeist werden.
Das muss ich mir aber noch durch den Kopf gehen lassen.

von Walter S. (avatar)


Lesenswert?

Matthias P. schrieb:
> mein Gedanke wäre
> noch ein zusätzliches Zeichen das vor der Übertragung gesendet wird

wenn du binär überträgst, wirst du keine zusätzliches Zeichen übrig 
haben

von Matthias P. (matt-eagle)


Lesenswert?

Walter S. schrieb:
> Matthias P. schrieb:
>> mein Gedanke wäre
>> noch ein zusätzliches Zeichen das vor der Übertragung gesendet wird
>
> wenn du binär überträgst, wirst du keine zusätzliches Zeichen übrig
> haben

Meinte ein extra Byte z.B. den Hex-Wert von ASCII "!".

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Tu dir selbst einen gefallen und übertrag in ASCII (kann ja auch Hex 
sein). Spätestens wenn du mit einem Terminal-programm auf Fehlersuche 
gehst, wirst du unendlich dankbar sein.

von Sebastian V. (sebi_s)


Lesenswert?

Matthias P. schrieb:
>> wenn du binär überträgst, wirst du keine zusätzliches Zeichen übrig
>> haben
>
> Meinte ein extra Byte z.B. den Hex-Wert von ASCII "!".

Ich vermute der Kommentar war so gemeint, dass du durch dein 
zusätzliches Zeichen wie "!" nicht identifizieren kannst wo ein neuer 
Datenblock beginnt, da ja durch die binären Daten auch dieses (und jedes 
andere) Zeichen gesendet werden könnte. Also wird das Ganze eventuell 
blöd zu syncronisieren wenn man dein C# Programm erst startet nachdem 
dein µC schon Daten sendet.

von cfgardiner (Gast)


Lesenswert?

Oder so?

for (int ix = 0; ix < sizeof(wert); ix++) {
      // cast Startadresse des arrays zu dem gewünschten Typ*
      // Verwende Zeigerarithmetik für die gewünschte Schrittweite
      // und dereferenziere den resultierenden Zeiger
   SendUART( *(((uchar*)&wert[0]) + ix) );
   }


Schaut vielleicht hässlich bzw. kryptisch aus. Dafür ist aber kompakt 
und recht gut portable.

Falls Du z.B. in einer anderen Applikation Byte nach DWord casten 
willst, brauchst Du nur die 1 Zeile so ändern:

uint8_t wert[] ....

for (int ix = 0; ix < sizeof(wert) / 4; ix++) {
   SendSPI( *(((u32*)&wert[0]) + ix) );

von Walter S. (avatar)


Lesenswert?

cfgardiner schrieb:
> Dafür ist aber kompakt
> und recht gut portable.

Portabel ist da leider nichts denn die Reihenfolge in der die Bytes dann 
kommen ist je nach Prozessor anders

von Sebastian V. (sebi_s)


Lesenswert?

Die Zeile kann man auch etwas kürzer schreiben:
1
SendUART( ((uchar*)wert)[ix] );

Die &wert[0] Geschichte kann man sich sparen weil Arrays sowieso zu 
Pointern zerfallen. Und das *(ptr + ix) das Gleiche ist wie ptr[ix] 
sollte jedem klar sein. Hängt dann aber trotzdem noch von der Byteorder 
ab, weshalb ich die Bitshift Variante erstmal vorziehen würde.

von Wolfgang (Gast)


Lesenswert?

Matthias P. schrieb:
> Meinte ein extra Byte z.B. den Hex-Wert von ASCII "!".

Woher weiss der Empfänger, dass das nicht das 17 Byte von einem 
Datenblock ist? Übliches Verfahren in solchen Fällen ist, ein 
Sonderzeichen zu vereinbaren, dass im Datenblock dann nicht (alleine) 
übertragen werden darf. Falls das Zeichen nun aber im Datenblock 
vorhanden ist, wird das Sonderzeichen doppelt gesendet. Der Empfänger 
kann dann zwischen Einzelsonderzeichen (Steuerfunktion) und 
Doppelsonderzeichen (Dateninhalt) unterscheiden und schmeißt das 
zusätzlich gesendete vorm Ablegen im Datenarray wieder raus.

von Matthias P. (matt-eagle)


Lesenswert?

Wolfgang schrieb:
> Matthias P. schrieb:
>> Meinte ein extra Byte z.B. den Hex-Wert von ASCII "!".
>
> Woher weiss der Empfänger, dass das nicht das 17 Byte von einem
> Datenblock ist? Übliches Verfahren in solchen Fällen ist, ein
> Sonderzeichen zu vereinbaren, dass im Datenblock dann nicht (alleine)
> übertragen werden darf. Falls das Zeichen nun aber im Datenblock
> vorhanden ist, wird das Sonderzeichen doppelt gesendet. Der Empfänger
> kann dann zwischen Einzelsonderzeichen (Steuerfunktion) und
> Doppelsonderzeichen (Dateninhalt) unterscheiden und schmeißt das
> zusätzlich gesendete vorm Ablegen im Datenarray wieder raus.

Also es wird einen festgelegten Ablauf geben. Das Array das ich 
versenden möchte wird auch das einzige sein, das überhaupt zu meiner 
Applikation gesendet wird. Es wird eine feste Größe haben und meine 
Applikation wird genau diese Menge einlesen und nicht mehr. Bisher hat 
mir aber euer Lösungsansatz mit dem splitten des uint16 Werts geholfen.

Falls ich dennoch mit meiner eher einfachen Denkweise bei viel mehr 
Werten auf Probleme stoße werde ich wohl doch nicht darum herumkommen, 
doch ein Protokoll wie ihr es vorgeschlagen habt anzuwenden.
Ich danke aber auf jeden Fall für die Tipps und für die Hinweise 
bezüglich des Protokolls(Falls es zutrifft einmal Kopfzerbrechen gespart 
;)).

Ich gebe Rückmeldung ;)

von Nosnibor (Gast)


Lesenswert?

Da die Daten im Array nur 10 bit haben, reichen 5 bit Daten pro Byte. 
Dann bleibt wieder genug Luft für Framing, Steuerzeichen und was einem 
sonst so einfällt.

von W.S. (Gast)


Lesenswert?

Matthias P. schrieb:
> Also es wird einen festgelegten Ablauf geben. Das Array das ich
> versenden möchte wird auch das einzige sein, das überhaupt zu meiner
> Applikation gesendet wird. Es wird eine feste Größe haben und meine
> Applikation wird genau diese Menge einlesen und nicht mehr. Bisher hat
> mir aber euer Lösungsansatz mit dem splitten des uint16 Werts geholfen.

Du hast wirklich NICHT nachgedacht.

Was ist, wenn irgendwo ein Zeichen verlorengeht oder irgend ein Krempel 
davor hinzukommt? Datensalat natürlich.

Also denke dir ein Protokoll aus, wie es dir hier schon mehrfach 
angeraten wurde. Nicht umsonst wird weltweit bei allen 
Datenübertragungen ein ganz erheblicher Aufwand getrieben, um Daten 
mittels geeigneter Protokolle verläßlich zu übertragen - so daß der 
Empfänger sich aus den empfangenen Daten selbst synchronisieren und 
obendrein auch noch die Daten auf Richtigkeit überprüfen kann.

Das ist alles reine Denkarbeit und hat mit dem Schreiben in irgend einer 
Programmiersprache nix zu tun. Und ebensowenig hat es mit irgend einer 
internen Darstellung a la uint16_t zu tun. In deinem Falle willst du 
Zahlen übertragen und zwar ganze Zahlen im Bereich von 0 bis 1023. Also 
benutze deinen Kopf zum Denken. Es ist ja gar nicht schwer.

W.S.

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.