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
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
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
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
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
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.
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
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
>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
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.
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
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?
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.
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
charc=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.
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
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).
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?
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
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!
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.
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.
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?
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
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
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
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!
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