Forum: Mikrocontroller und Digitale Elektronik Datenpakete senden


von Pt100 (Gast)


Lesenswert?

Schönen Feiertag allen ;-)

ich hab mir soeben für meinen Code einige Sachen Überlegt.
Ich möchte auf "Anfrage" von meinem PC via Bluetooth von meiner 
Schaltung ein Großes Datenpaket empfangen.

Ich möchte ganz genau 15 Spannungen á 10 Bit senden. Das heißt ich habe 
ein Datenpaket von 150 Bit. Das Bluetooth Modul ist im prinzip eine 
serielle Verbinung, nach dem sie eingerichtet wurde, also das Modul 
sendet alles transparent und Kabellos durch. Also wie wenn ich ein Kabel 
verwenden würde.

Jetzt stellt sich mir die Frage, wie realisiere ich dieses rießen 
Datanpaket.

Habt ihr eine Ahnung bzw mir eine Hilfestellung?

Hoff Ihr könnt mir helfen,

Grüße Pt100

von spess53 (Gast)


Lesenswert?

Hi

>Jetzt stellt sich mir die Frage, wie realisiere ich dieses rießen
>Datanpaket.

Das sind im Minimalfall 30 Byte. Was ist daran riesig?

MfG Spess

von Pt100 (Gast)


Lesenswert?

Naja klar aber ich habe ja Funktionen zum senden eines STRINGS. Jetzt 
frag ich mich, wie ich die Daten in einen String rein bekomm. Ich hab ja 
verschiedene 10 Bit Varaiblen in Integer drin, so kommen die von meiner 
Funktion des AD-Wandlers.

Also wie "schieb" ich jetzt die Daten da rein?

Hoffe auf Hilfe

Grüße

von spess53 (Gast)


Lesenswert?

Hi

Vielleicht hilft dir das weiter:

Beitrag "UART: Hex-Bytes versenden"

MfG Spess

von Pt100 (Gast)


Lesenswert?

okay, danke schonmal.
Ich hab mir jetzt das mal durch den Kopf gehen lassen.
Da ich die Daten auf dem PC nacher auch Seriell erhalte, muss ich diese 
dort auch wieder auslesen.
Wenn ich jetzt AD-Werte habe und diese per UART ausgebe, dann habe ich 
im Zweifelsfall verschieden lange Zahlen. Ich brauch dann voranstehende 
NULLEN. Mit welcher Funktion kann ich diese dann einfügen, bzw muss ich 
die Zahl in einen String schreiben und Nullen voransetzen?

Danach kann ich dann einfach alle Strings nacheinander per UART 
ausgeben. Die gesamten Daten teil ich mir dann auf dem PC auf.

Die Frage stellt sich jetzt nur um die Nullen.

Grüße Pt100

von Pt100 (Gast)


Lesenswert?

Wär echt super, wenn noch jemand eine Idee für die voranstehenden Nullen 
hat. Nacher soll das ein Strin sein so in der Art:

10230025035610000999....

Also JEWEILS IMMER vier Stellen für eine Spannung, damit ich nacher den 
String im PC auslesen kann und nach allen vier Stellen diesen wieder in 
einen Integer umwandle, damit ich mir die Spannungen ausrechnen kann.

Gute Nacht

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Printf kann Zahlen mit Festlänge und auch mit vorangestellten Nullen 
ausgeben.

http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

Z.B.
unsigned int a=5,b=10,c=115;
char string[13];

sprintf(string, "%04d%04d%04d", a, b, c);

Der Output in string sollte so aussehen:
000500100115

Alternativ könnte man die Zahlen auch mit Leerzeichen trennen.

Das Rücklesen am PC funktioniert über scanf mit der gleichen 
Formatanweisung wie das Senden.

char string[13];
unsigned int a,b,c;

Angenommen, die empfangenen Daten stehen in string
sscanf(string, "%04d%04d%04d", &a, &b, &c);
Dann stehen jetzt die Zahlen wieder in a, b und c.

Grüße,

Peter

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:
> Wär echt super, wenn noch jemand eine Idee für die voranstehenden Nullen
> hat. Nacher soll das ein Strin sein so in der Art:
>
> 10230025035610000999....

Diese Idee ist zwar naheliegend aber nicht so gut
Wenn dein PC das erste Zeichen verpasst (weil er zb nach deiner 
Schaltung gebootet wurde), dann empfängt er

 0230025035610000999....

und das sind dann ganz andere Zahlen, obwohl der Sender immer noch 
dasselbe meinte.

Denk mal darüber nach, welchen Vorteil wohl

 1023;25;356;1000;999;....

in dieser Hinsicht hat.

Mit ein bischen Flexibilität im Datenformat und definierten Fixpunkten 
an denen sich der Empfänger orientieren kann, kann man viele Probleme 
von vorne herein ausschliessen ohne dass das gleich in eine 
programmtechnische Schlammschlacht ausartet.

von Pt100 (Gast)


Lesenswert?

Guten Morgen,

erstml besten DANKE an das was Ihr in den zwei Posts alles geschrieben 
habt!
Hat mir auf jeden Fall weitergeholfen.
Also ich werde das jetzt auch so machen! Dann kann ich auf dem PC immer 
bis zum Semikolon trennen. Das das dann auch Vorteile hat war mir noch 
nicht so klar, aber wie Ihr das geschrieben habt ist jetzt logisch.

Muss ich sonst noch auf was achten?
Auf jeden Fall verwende ich jetzt sprintf für die Nullen und trenne 
danach mit den Sonderzeichen!


Besten Dank

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:
> Guten Morgen,
>
> erstml besten DANKE an das was Ihr in den zwei Posts alles geschrieben
> habt!
> Hat mir auf jeden Fall weitergeholfen.
> Also ich werde das jetzt auch so machen! Dann kann ich auf dem PC immer
> bis zum Semikolon trennen. Das das dann auch Vorteile hat war mir noch
> nicht so klar, aber wie Ihr das geschrieben habt ist jetzt logisch.
>
> Muss ich sonst noch auf was achten?
> Auf jeden Fall verwende ich jetzt sprintf für die Nullen und trenne
> danach mit den Sonderzeichen!

Ähm:
Du kannst alles in einem einzigen sprintf machen!
Und die führenden 0-en brauchst du gar nicht mehr
1
   for( i = 0; i < 15; ++i ) {
2
3
     wert = getADCValue( i );
4
5
     sprintf( Buffer, "%d;", wert );
6
     send_String( Buffer );
7
   }
8
   SendString( "\n" );     // hinten nach noch einen Zeilenvorschub
9
                           // dann hat es der Empfänger leichter, weil
10
                           // für ihn die 15 Werte erst mal einfach nur
11
                           // eine Eingabezeile darstellen

von Peter D. (pdiener) Benutzerseite


Lesenswert?

>Denk mal darüber nach, welchen Vorteil wohl

> 1023;25;356;1000;999;....

>in dieser Hinsicht hat.

Noch besser wäre wohl:
a1023b25c356 usw.

Sonst weiß man ja auch nicht, wann welche Zahl gemeint ist.

Grüße,

Peter

von Karl H. (kbuchegg)


Lesenswert?

Peter Diener schrieb:
>>Denk mal darüber nach, welchen Vorteil wohl
>
>> 1023;25;356;1000;999;....
>
>>in dieser Hinsicht hat.
>
> Noch besser wäre wohl:
> a1023b25c356 usw.
>
> Sonst weiß man ja auch nicht, wann welche Zahl gemeint ist.

Hatte ich zuerst auch gedacht.
Aber im Eröffnungsposting steht, dass der PC die Daten explizit 
anfordert.
Ich würde diese Unterscheidung, so wie du das vorschlägst, trotzdem 
reinmachen. Einfach deswegen, weil es mir ein Greul ist, wenn der 
Empfänger Annahmen treffen muss. Im Idealfall (IMHO) 'treibt' der Sender 
den Empfänger mittels der Datenübertragung so, dass es zu keinen 
Missverständnissen kommen kann und der Empfänger nur sehr wenig annehmen 
muss.

Erweiterbarer für die Zukunft ist es ausserdem und zudem würde sich das 
Tor öffnen, dass der Empfänger nur geänderte Werte übertragen muss.

Aber das muss der TO entscheiden.

von Pt100 (Gast)


Lesenswert?

Also die Daten werden vom PC angefortert. Das heißt ich schicke vie 
Bluetooth den Code für das aktuelle Datenpaket. Danach schickt die 
Platine mir auf den PC einen String welcher jetzt dann so aussieht: 
a1023b25c356

Aber ich würde das jetzt alles in eine Zeile knallen. Also erst nach dem 
letzten Wert den Zeilenvorschub senden. Das sind dann alle 15 Werte, 
also MAXIMAL 75 Zeichen, also 600 Byte. Mit dem Bluetooth kann ich 
maximal 115 kBaud.

Auf dem PC hab ich mir ein Programm geschrieben mittels MFC in C++. Ich 
denke die dortigen Funktionen find ich dann schon, damit ich immer 
direkt das was zwischen den Buchstaben steht ermittle.

Viele Grüße

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:

> Platine mir auf den PC einen String welcher jetzt dann so aussieht:
> a1023b25c356

wenn du dir auf dem PC das Leben leichter machen willst, dann machst du 
zusätzlich noch ein Trennzeichen rein, so dass du beim 
Auseinanderpfriemeln des Strings auf dem PC einen Fixpunkt hast: nämlich 
das Trennzeichen.

A1023;

Jeder Wert wird also in einem Paket übertragen, welches besteht aus
  * einem Buchstaben, der eine Aussage darüber erlaubt welcher Wert
    das überhaupt ist, wo er herstammt
  * Dem Zahlenwert selber
  * Einer Terminierung (hier IMMER ;) die aussagt wo die Zahl aufhört

Von diesen 'Wertpaketen' können (bei dir jetzt) maximal 15 in einer 
Zeile kommen. Ein komplettes Datenpaket ist also im Grunde einfach nur 
eine Textzeile (hört mit einem \n auf), in der mehrere Wertpakete 
enthalten sind.

> Aber ich würde das jetzt alles in eine Zeile knallen. Also erst nach dem
> letzten Wert den Zeilenvorschub senden. Das sind dann alle 15 Werte,
> also MAXIMAL 75 Zeichen, also 600 Byte.

Nö.
75 Zeichen sind 75 Byte.
Wobei dich das auf einem PC eher weniger interessiert.
Der Empfangsbuffer wird mit 512 Bytes Größe festgelegt und wenn dann 
anstelle der 75 Bytes in 2 Jahren mal 90 daherkommen (weil noch 5 
weitere ADC Quellen dazugekommen sind), dann juckt dich das herzlich 
wenig.

> Mit dem Bluetooth kann ich
> maximal 115 kBaud.

Und?
Welche Zeitbeschränkungen hast du am PC? Wie schnell müssen die Werte 
reinkommen?

von Pt100 (Gast)


Lesenswert?

Naja auf dem PC hab ich mir das jetzt einfach so gedacht, dass ich eine 
Sekunde Timeout hab, also sende ich das Flag für die Anforderung und 
dann springt mein uC in den Interrupt wo er sich ein Arbeitsflag setzt, 
welches im Hauptprogramm dann die ADC-Wandlungen durführt und die daten 
so raushaut.

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:
> Naja auf dem PC hab ich mir das jetzt einfach so gedacht, dass ich eine
> Sekunde Timeout hab, also sende ich das Flag für die Anforderung und
> dann springt mein uC in den Interrupt wo er sich ein Arbeitsflag setzt,
> welches im Hauptprogramm dann die ADC-Wandlungen durführt und die daten
> so raushaut.

Ja, ist ok.

1 Sekunde ist viel Zeit. Da hast du jede Menge Zeit dir die Daten 
senderseitig so aufzubereiten, dass der Empfänger sie möglichst einfach 
auseinanderpfriemeln kann und dabei auch noch Fehlererkennung betreiben 
kann.

Auf dem PC schreibt man sich dann noch eine Funktion, die einen 
beliebigen String anhand von fixen Trennzeichen in einzelne Strings 
aufteilt und schon hast du deine Wertpakete wieder. Im Wertpaket sagt 
dir der erste Buchstabe um welchen Wert es sich handelt und der Rest von 
diesem Teilstring kann dann zb in atoi reingestopft werden um wieder 
eine Zahl zu erhalten. Anhand des Kennbuchstabens dann noch die Zahl 
richtig verteilt (zb in ein Array) und fertig.

Senderseitig ist das alles sowieso kein Problem.
Wobei sich noch die Frage erhebt, was der µC sonst noch so alles machen 
soll. Wenn der sonst nichts zu tun hat, schadet es auch nicht, wenn der 
einfach ständig reihum alle ADC abfrägt und sich die gemessenen Werte 
zwischenspeichert. Auf Anfrage vom PC werden dann einfach die jeweils 
letzten Messwerte rausgesendet.
1
   ....
2
3
   while( 1 ) {
4
5
     Value[nextADC] = readADC( nextADC );
6
     nextADC++;
7
     if( nextADC == 15 )
8
       nextADC = 0;
9
10
     if( transmitRequested ) {
11
       transmitRequested  = FALSE;
12
       for( i = 0; i < 15; ++i ) {
13
         sprintf( buffer, "%c%d;", i + 'A', Value[nextADC];
14
         sendString( buffer );
15
       }
16
       sendString( "\r\n" );
17
     }
18
19
   }
20
21
....
22
23
24
ISR( .... )
25
{
26
  char c = UDR;
27
28
  if( c == 'V' )                    // V wie 'Values' ... Werte übertragen
29
    transmitRequested = TRUE;
30
}


das kann man dann wunderbar zb mit Hyperterminal oder einem anderen 
Terminalprogramm testen und so sicherstellen, dass senderseitig erst mal 
alles klappt ehe man dann anfängt auf dem PC ein Programm zu schreiben.

von Pt100 (Gast)


Lesenswert?

Hallo,

jop, ich hab die Funktionen für die Main-Loop schon geschrieben, der uC 
hat da dann die Variablen, in denen er den letzten Messwert ablegt. Wenn 
der Interrupt das Flag setzt, das heißt, wenn der PC Daten anfordert, 
dann springt er uC nicht wie gewohnt in die ADC-Funktionen sonder 
überprüft vor der Loop das Flag, falls das gesetzt ist geht ja alles 
ziemlich schnell, er stellt den String zusammen und schickt den raus. 
Danach setzt er das Flag zurück und es kann weiter gehn.

Wenn ich den String zusammenstelle reicht es im Prinzip eine sprintf 
Funktion oder? Ich kann ja hier beliebig viele Werte eingeben oder? Und 
die Sonderzeichen lassen sich ja auch so einfügen.

Grüße

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:

> Wenn ich den String zusammenstelle reicht es im Prinzip eine sprintf
> Funktion oder?

Kannst du natürlich auch machen.
Nur brauchst du dann mehr Speicher für den zwischendurch entstehenden 
String und abhängig von deiner UART-Funktionalität brauchst du unter 
Umständen ein bischen mehr Zeit (wird sich aber nicht um viel reißen).

von Pt100 (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Nur brauchst du dann mehr Speicher für den zwischendurch entstehenden
> String und abhängig von deiner UART-Funktionalität brauchst du unter
> Umständen ein bischen mehr Zeit (wird sich aber nicht um viel reißen).

Wie meinst du brauch ich "mehr" Speicher für den String? Ich habe doch 
in einer Variable den Speicher für den String schon reserviert. Spielt 
das dann eine Rolle oder kann ich es dann auch besser lösen?

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:
> Karl heinz Buchegger schrieb:
>> Nur brauchst du dann mehr Speicher für den zwischendurch entstehenden
>> String und abhängig von deiner UART-Funktionalität brauchst du unter
>> Umständen ein bischen mehr Zeit (wird sich aber nicht um viel reißen).
>
> Wie meinst du brauch ich "mehr" Speicher für den String?

Nun ja.
Auf einem µC bist du meistens nicht so mit freiem Speicher gesegnet wie 
auf einem PC.

In
1
   for( i = 0; i < 15; ++i ) {
2
3
     wert = getADCValue( i );
4
5
     sprintf( Buffer, "%d;", wert );
6
     send_String( Buffer );
7
   }
8
   SendString( "\n" );

muss Buffer, das char Array welches den String aufnimmt, minimal 7 
Zeichen gross sein. 4 für die Zahl ( 0 bis 1024), 1 für den Buchstaben, 
1 für den Terminator und 1 für das abschliessende \0 das jeder String 
hat. Ist der Teilstring für einen Wert fertig, wird er sofort an die 
UART übergeben und übertragen und damit steht dann dasselbe 7-Character 
Array für den nächsten Wert zur Verwendung zur Verfügung.


In
1
   sprintf( Buffer, "A%d;B%d;C%d;E%d;\n" wert[0], wert[1], wert[2], wert[3] );

muss Buffer aber schon 26 Zeichen gross sein (und da hab ich nur 4 Werte 
angenommen), denn so lang kann der komplette String maximal werden.

von Michael H. (michael_h45)


Lesenswert?


von Pt100 (Gast)


Lesenswert?

Okay also dann mach ich den Buffer genau sieben Zeichen lang und schick 
das alles sofort raus. Die Einzelnen AD-Werte liegen ja immer in einer 
Variable vor, sodass es egal ist wie weil ich mit dem durchwandeln bin, 
er nimmt einfach den zuletzt vorliegenden Wert.
Dann kann ich die Variable nehmen und in den String schreiben, das 
braucht dann auch fast keine Zeit oder?

Bis jetzt habt Ihr mir echt geholfen großes Lob und danke dafür!

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:

> Dann kann ich die Variable nehmen und in den String schreiben, das
> braucht dann auch fast keine Zeit oder?

Im Vergleich zur reinen Übertragungszeit auf der UART ist das dazwischen 
(fast) alles pipifax. Die Durchlaufzeit wird im wesentlichen davon 
bestimmt, wie lange die physikalische Übertragung dauert und nicht 
davon, welche Klimmzüge du machen musst um zum String zu gelangen.
Mit einer vernünftigen UART-Lib (zb der vom Peter Fleury), die das 
Versenden ebenfalls mittels Interrupts macht, kannst du zwischen dem 
Senden von 2 Zeichen einen guten Teil deiner restlichen Arbeit (wie zb 
Aufbereitung durch sprintf) erledigen lassen, so dass das dann überhaupt 
nicht mehr ins Gewicht fällt.

von Pt100 (Gast)


Lesenswert?

Okay, also Peter Fleury ist vollständig in das Programm integriert, das 
war schon von anfang an so geplant ;) Hab das jetzt ebenfalls auf vier 
Schnittstellen umgesetzt.
Derzeit hab ich die Varaiblen für die ganzen Spannungen Global angelegt, 
damit ich diese dann immer in der Loop aktualisiere.
Sobald das Flag da ist also im Interrupt gesetzt wurde reagiere ich in 
meiner Mainloop mit einer Funktion.

von Pt100 (Gast)


Lesenswert?

Habe gerade überlegt, wenn ich für einen AD-Wert (10 Bit) einen Integer 
nehm gehn mir ja sechs Bits dirrekt verloren oder? Also bei 15 ADC´s 
macht das dann etwas über 11 Byte "Müll"
Kann ich das irgendwie umgehen?

von Pt100 (Gast)


Lesenswert?

Ich hab mich mal belesen, wenn ich einen Struct einfüge und dann die 
Bits seperat zuweiße. Würde ich mir dann den Platz im Prozesor sparen?

Ich denke es wird nacher evtl. knapp und dann wäre es super

Grüße

von Sascha W. (sascha_w)


Lesenswert?

Pt100 schrieb:
> Habe gerade überlegt, wenn ich für einen AD-Wert (10 Bit) einen Integer
> nehm gehn mir ja sechs Bits dirrekt verloren oder?
verloren? du meinst deine Variable hat 6Bit die nicht genutzt werden

> Ich hab mich mal belesen, wenn ich einen Struct einfüge und dann die
> Bits seperat zuweiße. Würde ich mir dann den Platz im Prozesor sparen?
mit sowas kannst du sinnvoll sicher keinen Platz sparen. Im SRAM evl. 
schon aber im Programm (FLASH) würde ein aufteilen der Bits vom 
AD-Wandler in die Bytes im SRAM einen riesigen Aufwand darstellen.

PS: schau dir erst mal deine sonsigen Variablendefinitionen an ob die 
nicht größer als notwendig deklariert sind.

Sascha

von Karl H. (kbuchegg)


Lesenswert?

Pt100 schrieb:
> Ich hab mich mal belesen, wenn ich einen Struct einfüge und dann die
> Bits seperat zuweiße. Würde ich mir dann den Platz im Prozesor sparen?

Das lohnt nur dann, wenn du die paar Bytes so dringend brauchst, wie ein 
Verdurstender einen Schluck Wasser

von Pt100 (Gast)


Lesenswert?

Also dann doch lieber schon 16 Bit Integer nehmen, auch wenn meine 15 
AD-Eingänge jeweils nur 10 Bit abliefern?
Naja dann mach ich das mal so und wenn es dann doch knapp wird meld ich 
mich ;-)

Besten Dank schonmal!

von Michael H. (michael_h45)


Lesenswert?

Hast du dir mal ausgerechnet, was 10 bit Auflösung überhaupt bedeutet?
Meinst du nicht, dass andere Komponenten wesentlich weniger Genaugikeit 
zulassen?
Reichen dir nicht vielleicht einfach 8 bit völlig ?

Auflösung und Genauigkeit

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.