hallo!
ich habe vor, strings via uart zu versenden. Dazu habe ich eine fkt.
void uputs(char *s)
diese befüllt ein Array protocol, welches in der TX-ISR verwurstet wird.
der Aufruf: uputs("Test\r\n"); funktioniert super!
der Aufruf: uputs(buffer); funktioniert net es werden nur best. teile
gesendet
buffer ist: sprintf(buffer,"asldkfj %4d \r\n",9999); wobei buffer[40]
Timo P. schrieb:
> hallo!> ich habe vor, strings via uart zu versenden. Dazu habe ich eine fkt.> void uputs(char *s)> diese befüllt ein Array protocol, welches in der TX-ISR verwurstet wird.>> der Aufruf: uputs("Test\r\n"); funktioniert super!
Das glaub ich nicht.
Nicht mit der von dir geposteten uputs. Die landet unweigerlich in einer
Endlosschleife.
Wozu soll es gut sein, die einzelnen Character per Interrupt zu
versenden, wenn deine uputs Funktion dann sowieso auf das Ende des
Versendens wartet? (und nur mal angenommen, du hättest die
Endlosschleife while (*s) bereinigt)
das versenden via interrupt geht. So ist das Timing ok.
Jetzt wollte ich nur für die handlebarkeit eine fkt haben, an die ich
einen string übergebe, die sich dann kümmert. von mir aus auch unter
zuhilfenahme einer interruptfunktion!
Timo P. schrieb:
> das versenden via interrupt geht. So ist das Timing ok.
Ja. Aber so wie du das geschrieben hast ist es sinnlos.
Ich kann auch von Wien nach Frankfurt über Helsinki fahren wenn ich
will. Ich kann aber auch den einfachsten Weg nehmen.
> Jetzt wollte ich nur für die handlebarkeit eine fkt haben, an die ich> einen string übergebe, die sich dann kümmert. von mir aus auch unter> zuhilfenahme einer interruptfunktion!
Und warum muss die Funktion dann warten, bis der String rausgegeben
wurde? Der Witz hinter dem Versenden eines Strings per Interrupt besteht
ja gerade darin, dass der Aufrufer eben nicht darauf wartet, sondern
weitermachen kann, während der String im Hintergrund rausgesendet wird.
ok also ich könnte in meinem hauptprogramm:
- protocol[] füllen
- den interrupt aktivieren
- was anderes tun
und im interrupt:
- zeichen senden
- bei stringende den interrupt disablen.
if(temp != '\0');
UCA0TXBUF = temp; // TX next character
Siehst du den kleinen ; am Zeilenende vom if?
Die gewünschte Funktionalität, nämlich dass ein Zeichen nur dann
rausgeht, wenn es nicht '\0' ist, dürfte damit verloren gehen.
Auf der anderen Seite lässt die nicht vorhandene Einrückung vermuten,
dass das sowieso nicht beabsichtigt war, wodurch allerdings die Abfrage
sinnlos geworden ist. Wahrscheinlich wirft der Compiler sie raus.
Timo P. schrieb:
> ok also ich könnte in meinem hauptprogramm:>> - protocol[] füllen> - den interrupt aktivieren> - was anderes tun
Fast.
Die korrekte Version ist
- feststellen ob zufällig noch eine vorhergehende String-Versende
Aktion im Gange ist und auf deren Abschluss warten
- protocoll[] füllen, wobei es sinnvoll ist zu überprüfen, ob der
zu sendende String da überhaupt hineinpassen wird.
Ein strcpy mit einem unbekannten String in ein Zielarray ist
eine Harakiri-Aktion
- den Interrupt aktivieren
entweder in dem man das Interrupt Flag setzt, oder einfach das erste
Zeichen an die USART übergibt. Letzteres ist gebräuchlicher, da man
dann in der Sendefunktion kein Wissen über irgendwelche Sende-
Interrupt Flags benötigt
- aus der Funktion returnen
>> und im interrupt:>> - zeichen senden> - bei stringende den interrupt disablen.
und auf jeden Fall, den index des nächsten zu sendenden Zeichens nicht i
nennen. i kann alles Mögliche sein. Peinliche Verwechslungen sind
vorprogrammiert, wenn man wichtige globale Variablen i, j, k nennt.
warum sich das semikolon dahingeschlichen hat ist mir auch ein rätzel..
klärt aber immenoch nicht, warum die überhabe "sdflk" gegenüber der
übergabe:
(arrayname) funktioniert
Timo P. schrieb:
> warum sich das semikolon dahingeschlichen hat ist mir auch ein rätzel..>> klärt aber immenoch nicht, warum die überhabe "sdflk" gegenüber der> übergabe:> (arrayname) funktioniert
Das lässt sich auch mit dem Mikro-Code Schnipsel nicht erklären
ausschluss einer "Harakiri funktion" werde ich per sizeof sicherstellen
oder halt genug an zeichen reservieren, bisher habe ich keine
speicherprob.
i durch zb. next_char zu ersetzen ist ja auch kein prob.
würde trotzdem gerne wissen, warum die verschiedenen aufrufe zu
verschiedenen resultaten führen......
Timo P. schrieb:
> würde trotzdem gerne wissen, warum die verschiedenen aufrufe zu> verschiedenen resultaten führen......
Weil wahrscheinlich wieder mal irgendetwas Schlimmes passiert, was
ausserhalb des geposteten Source-Codes passiert.
1
volatilecharprotocol[80];
2
volatilesignedcharnext_char=-1;
3
4
unsignedcharuputs(constchar*s)
5
{
6
if(strlen(s)>sizeof(protocol)-1)
7
returnFALSE;
8
9
while(next_char!=-1)
10
;
11
12
strcpy(protocol,s);
13
next_char=0;
14
IE2|=UCA0TXIE;
15
16
returnTRUE;
17
}
18
19
#pragma vector=USCIAB0TX_VECTOR
20
__interruptvoidUSCI0TX_ISR(void)
21
{
22
chartemp=protocol[next_char];
23
24
if(temp=='\0')
25
{
26
next_char=-1;
27
return;
28
}
29
30
UCA0TXBUF=temp;
31
next_char++;
32
}
Ob die Sache mit den Interrupts bzw. den Interrupt Flags so stimmt kann
ich mangels Datenblatt bzw. Kentniss des Prozessors nicht sagen. Ich
habe das einfach vom TO so übernommen.
ok die idee von der leichteren handlebarkeit ist wieder über den haufen
geworfen und es läuft wieder über den interrupt, muss jetzt halt die
interruptflags setzen/löschen.
wie würde ich eine empfangs ISR aufbauen, die mir ein array füllt? wenn
ich einen string empfangnen will, der eine gewisse länge hat, dann endet
er irgenwann. wie stelle ich das in der empfangsroutine fest? kann ich
dann den string(den ich in ein arry schiebe) per \0 beenden? nur wie
stell ich fest, dass der empfangene string zu ende ist?
wird ja wohl ne andere lösung geben, als ein timeout oder?
wen es interessiert, hier die geänderte c-datei (ist auch nicht lang)
da habe ich per timer ein flag gesetzt, was zwischen protocolaufbau und
protocolversenden unterscheidet.
Timo P. schrieb:
> dann den string(den ich in ein arry schiebe) per \0 beenden? nur wie> stell ich fest, dass der empfangene string zu ende ist?
Indem du mit dem Sender vereinbarst, was als 'String-Ende' Zeichen zu
werten ist.
Üblich ist zb das das Zeichen '\n' einen Eingabestring beendet. Darum
muss man auch in den meisten Commandline Interpreteren auf Return
drücken, damit die eingegebene Zeichensequenz der Bearbeitung zugeführt
wird. ZUvor ist es einfach nur eine nicht abgeschlossene Abfolge von
Zeichen, die noch editiert werden kann. Danach ist es ein String, der
vom Commandline Interpreter als String bearbeitet wird (meistens ohne
das '\n')
Timo P. schrieb:
> Karl heinz Buchegger schrieb:>> du gibst zu leicht auf :-)>> widersprechen will ich da net. Aber ich habe auch immer das verlangen,> Zeit zu sparen.
:-)
Ist ganz einfach:
Mach es richtig, dann sparst du Zeit in der Entwicklung. Und eine
saubere String-Sende Funktion sollte es einem eigentlich Wert sein, dass
man da ein paar Stunden dafür opfert und auch ein paar Varianten
durchprobiert, miteinander vergleicht und die Vor/Nachteile
gegeneinander abwägt. Man kann damit nur lernen, welche Methoden
funktionieren, welche nur fake sind, welche zwar auf den ersten Blick
gut aussehen aber trotzdem Unsinn sind etc.
Beim nächsten mal ist nicht die String-Funktion sondern du musst ganze
Datenbanken per UART übertragen. Da es dasselbe Grundprinzip ist, kannst
du dann auf dein Wissen von der String-Funktion zurückgreifen :-)
PS: Die beste Lösung wäre ein Ringbuffer. Aber bring erst mal deinen
normalen linearen Buffer zum laufen. Da kann man auch noch eine Menge
dabei lernen.
Woher K.H.B. nur diese Geduld nimmt?
@ Zulu
>Aber ich habe auch immer das verlangen, Zeit zu sparen.
Das ist eine Illusion.
Die Zeit die Du Dir beim lernen sparst,
brauchst Du dann um die Fehler zu finden, die Du mangels Wissen und
Erfahrung einbaust.
Wenn sich K.H. die Zeit für eine Lektion in programmieren nimmt, dann
solltest Du das nutzen.
also ich habe meinen geänderten Code in einem der vorherigen beiträge
angehängt. Wie man dort sieht, nutze ich nur die ISR zum versenden.
Somit habe ich wieder Zeit gespart, weil ich zwischen den ISR`s was
anderes machen könnte.
wenn ich zb. jetzt aus:
ISR enable
protocol(also zu versendendes array) füllen
nach stringende in isr ISR selbst disablen
einen Funktionsaufruf machen möchte, dann kann ich dies doch einfach
tun.
Ich übergebe der fkt. als einzigen parameter einen string. diese kopiert
den string dann in das versende array. und enabled die TX-ISR.
Dann hab ich doch meine funktion zb.
void uputs(char *s);
{
IE2 |= UCA0TXIE;
strcpy(protocol, s);
}
aufruf uputs(arrayname);
Timo P. schrieb:
> Dann hab ich doch meine funktion zb.>> void uputs(char *s);> {> IE2 |= UCA0TXIE;> strcpy(protocol, s);> }
anders rum:
zuerst den Zwischenspeicher fertig herrichten, dann den Interrupt
freigeben und somit die Chose starten.
Ich hab dir doch weiter oben schon eine Version hergerichtet (die ich
allerdings naheliegender Weise nicht testen konnte). Nicht gesehen?
Selbst gedanken gemacht habe ich mir schon:
1) wenn ich in C "temp" schreibe ist das ein eindim. array mit inhalt:
temp\0
korrekt?
2) die uart_gets() fkt. liefert mir einen string mit \0
korrekt?
3) command-array ist mit [11] groß genug f. Aufruf: uart_gets(command,
10);
korrekt?
4) andere Fehler?
Timo P schrieb:
> Selbst gedanken gemacht habe ich mir schon:>> 1) wenn ich in C "temp" schreibe ist das ein eindim. array mit inhalt:> temp\0> korrekt?
Sollte zumindest so sein.
> 2) die uart_gets() fkt. liefert mir einen string mit \0> korrekt?
ja
> 3) command-array ist mit [11] groß genug f. Aufruf: uart_gets(command,> 10);> korrekt?
ja.
wobei an dieser Stelle gilt:
nicht kleckern, klotzen!
> 4) andere Fehler?
nichts erkennbares
aber lass dir doch einfach mal den String, den du empfangen hast
ausgeben
1
uart_gets(command,10);
2
uputs("\r\nEmpfangen: >");
3
uputs(command);
4
uputs("<\r\n");
dann weißt du ganz genau, was deine Leseroutine gelesen hat. Wichtig:
Vor und hinter dem command String ein Sonderzeichen ausgeben, damit du
auch versteckt Zeichen siehst. Am Terminal muss stehen
1
Empfangen: >temp<
Jede Abweichung davon weißt auf ein Problem hin
zb wäre
1
Empfangen: >temp
2
<
eine Abweichung, die darauf hindeutet, dass der Return nicht richtig
ausgefiltert wird und im empfangenen String durchkommt.
ich habe schon die ausgabe gemacht
und zwar folgendermaßen:
uputs("command eingeben: ");
uart_gets(command, 10);
uputs("\r\n einzelne Zeichen seriell: ");
uputchar(command[0]);
uputchar(command[1]);
uputchar(command[2]);
uputchar(command[3]);
uputchar(command[4]);
uputchar(command[5]);
uputchar(command[6]);
uputchar(command[7]);
uputchar(command[8]);
uputs("\r\n");
so sehe ich temp
die idee mit < und > ist gut, so kann ich zeilenvorschübe detektieren.
(im übrigen ist mir auch bewusst, dass ich in hyperterm gesendete
strings mit zeilenvorschub senden kann indem ich nen haken setze)
uputs("command eingeben: ");
uart_gets(command, 10);
uputs("\r\n\r\n");
uputs( "\r\n\r\nEmpfangen: >" );
uputs( command );
uputs( "<\r\n" );
Die Ausgabe ist: (habe nur ein t eingegeben)
t<pfangen: >t
damit kann ich garnix anfangen....
Ich kann da nur das kostenlose Programm "hterm" empfehlen, bei google
sofort zu finden. Da werden auch Steuerzeichen wie "\n" angezeigt etc..
HyperTerminal kann nix.
STIMMT!!!
Fehler behoben!
also \r\n wird anscheinend gesendet vom hyperterm
anstatt \n und meine(deine) fkt. die den string empfängt, kappt die
zeichen via \n
also ist es besser für mich, wenn ich zwei eval-boards miteinander
kommunizieren lasse.....
dann kann ich via sendecontroller *"temp?\n"* schicken und mit der
empfangsfkt.
in command schreiben, diesen dann via strcmp mit genau diesem
*"temp?\n"* vergleichen...
hab ich schon gemacht ;)
läuft wunderbar. Jetzt kommen trotzdem controller dran. Habe ja die
Möglichkeit zwei controller kommunizieren zu lassen, dann tu ich das
auch und zeige mir nur die ergebnisse der kommunikation eines
controllers via hyperterm
Besten Dank!
vllt kannst du mir ja mal allgemeine Tips geben:
ich habe vor, von einem Controller(Mainboard) commands zu senden an
verschiedene Device Controller. z.B. "temp?"
der entspr. device Controller reagiert natürlich nur auf "temp?" und
schickt die vorher gemessene Temperatur los. Werte können sein:
22,5 °C als 45 übertragen
23 °C als 46 übertragen
ist sowas sinnvoll? so brauche ich nicht per sprintf("%5.1f",...)
umrechnen. Habe gehört das frisst viel Zeit... sagen wir mal ich hätte 6
versch. Sensoren(sind dann auch 6 versch. Arten, 6 versch
device-Controller)diese 6 werte will ich höchstens jede sekunde
(wahrscheinlich alle 10 sek.) abfragen via mainboard.
also habe ich im worst case pro sekunde 6 kommands zu senden und 6 Werte
zu empfangen.
wie übertrage ich werte, wie übertrage ich commands?
IDEE:
command: "temp?"
wert: "45" //für 22,5°C
einfach keine Strings übertragen.
als ersten eventuell eine ID (z.b. 1 für Temp ) und danach den wert.
send(1)
//8bit
uint8_t tmp = 45;
send( tmp );
//16bit
uint16_t tmp = 45;
send( (uint8_t)tmp >> 8 );
send( (uint8_t)tmp & 0xFF );
Timo P schrieb:
> ich habe vor, von einem Controller(Mainboard) commands zu senden an> verschiedene Device Controller. z.B. "temp?"> der entspr. device Controller reagiert natürlich nur auf "temp?" und> schickt die vorher gemessene Temperatur los. Werte können sein:>> 22,5 °C als 45 übertragen> 23 °C als 46 übertragen>> ist sowas sinnvoll? so brauche ich nicht per sprintf("%5.1f",...)> umrechnen. Habe gehört das frisst viel Zeit... sagen wir mal ich hätte 6> versch. Sensoren(sind dann auch 6 versch. Arten, 6 versch> device-Controller)diese 6 werte will ich höchstens jede sekunde> (wahrscheinlich alle 10 sek.) abfragen via mainboard.> also habe ich im worst case pro sekunde 6 kommands zu senden und 6 Werte> zu empfangen.
Und in der Zwischenzeit löst dein µC noch mindestens 1000 teuflisch
schwierige quadratische Gleichungen.
Die Sache ist die
ASCII Transfer
**************
ist natürlich langsamer als ein paar Binärcodes hin und her zu schicken.
Hat allerdings den Vorteil, dass man sich mit jedem beliebigen
Terminalprogramm an die Leitung klemmen kann und im Klartext mitlesen
kann, was gesendet bzw. empfangen wird
Weiterer Vorteil: In der Entwicklungsphase können Sender und Empfänger
getrennt voneinander entwickelt werden. Die Rolle der jeweiligen
Gegenstelle übernimmt der Mensch, der vor dem Terminal sitzt.
Der Aufbau eines fehlergesicherten, selbst synchronisierenden Protokolls
ist trivial.
Binärer Transfer
****************
läuft voll Speed über die Leitung. Ohne spezielle Entwicklungswerkzeuge
ist eine getrennte Entwicklung von Sender und Empfänger nur schwer bzw.
umständlich zu realisieren. Ein Terminalprogramm, welches die Bytewerte
direkt anzeigt ist dabei unterste Grundausstattung. Aber selbst dann ist
es mühsam.
Der Aufbau eines fehlergesicherten, selbst synchronisierenden Protokolls
ist zwar möglich, je nach tatsächlichem Datenaufbau aber umständlich.
Dein Datenaufkommen schafft eine ASCII Verbindung mit links. Und das
Kommando an den Sensor muss ja nicht unbedingt "GetActualTemperatur"
lauten.
sagen wir ich habe 6 devices, jedes erwartet ein command a 5 Zeichen
und sendet ein zeichen id und 4 Zeichen Zahlenwert
also 6 * (5z+1) // für \n
und 6 * (5z+1) // id, 4 databytes \n
sind 72 zeichen(bidirektional gerechnet)
und via 8N1@9600 kann ich doch 960 Zeichen übertragen...
da hab ich ja mehr als genug luft.....
werde also senden: "10045\n" für ID: 1 und value: 25°
oder meintest du das so, dass ich das in GETRENNTEN Strings sende?
du musst dich zwischen Text und Binary entscheiden.
"10045\n" ist Text (6 Zeichen)
0x01, 0x2D ist Binary. (2 Zeichen)
Binay ist für dein µC einfacher weil er es nicht erst in text und zurück
umwandln muss. Aber für dich schwerer weil du schlecht mitlesen kannst.
Nen Kommando-Interpreter-Modul wäre doch was feines. Das sitzt zwischen
Applikation und dem UART-Treiber und übersetzt Ein-/Ausgaben von ASCII
nach BINARY oder anders herum. Intern wird ausschließlich binär
kommuniziert (beliebig komplex) und in Richtung HyperTerm hat man die
Wahl: Klartext oder Nullen/Einsen.. Per Kommando umschaltbar.
Erinnerte mich gerade an nen Teil meiner Diplomarbeit.. :P
Für mich denke ich, kommt binary doch mit ins spiel!
Also 0x01, 0x2D sind ja nur zwei Zeichen, darum werd ich`s so
übertragen...(warum auch immer dies binary genannt wird)
Muss mir halt mal gedanken machen, weil ein Byte für den Temperaturwert
nicht ausreichen wird, also zwei byte übertragen und irgendwie
zusammenstricken, am einfachsten nen 16bit int als low und highbyte
übertragen.
Mal ne Frage, wenn ich nen signed int habe, denn ich in zwei einzelne
bytes zerrupfe, auf der empfängerseite dann aus den beiden bytes wieder
ein signed zusammenstricke, dann habe ich doch keine Informationen
bezüglich der "signedness" verloren, richtig?
so lange du auf beiden seiten die gleichen Datentyp hast, es es ziemlich
egal wie du es überträgst.
Die signed information ist nur für den Compiler entscheident, damit er
weiss welche Instruktionen er an die CPU übergeben muss. Im Speicher
lässt sich ein signed nicht von einem unsigned unterscheiden.
Timo P schrieb:
> Mal ne Frage, wenn ich nen signed int habe, denn ich in zwei einzelne> bytes zerrupfe, auf der empfängerseite dann aus den beiden bytes wieder> ein signed zusammenstricke, dann habe ich doch keine Informationen> bezüglich der "signedness" verloren, richtig?
richtig.
Denk aber auch daran, deine Übertragung sollte im Idealfall so sein,
dass sie sich synchronisiert. Damit ist gemeint:
Die beiden Geräte laufen schon seit geraumer Zeit, das verbindende Kabel
ist abgefallen. Jetzt steckst du das Kabel wieder an und der Empfänger
sieht
0x87 0x02 0x02 0x56
Und er muss rausfinden können, dass hier
0x87 0x02 0x02 0x56
^
|
die nächste Temperaturübertragung beginnt.
kabel sind leiterplattenverbinder
es gibt ein mainboard, welches die devices (einstellbaren timings)
bestromnt, diese machen alle ihre messungen, und dann fragt das
Mainboard via command z.B "RH?\n" nach den Werten. Antwort könnte sein:
"RH60\n"
oder command:
"temp?\n"
antwort:
"T45\n" oder 0x54 0x2D 0x0D // so habe ich doch aus 4 zeichen 3 gemacht
:)
Timo P schrieb:
> kabel sind leiterplattenverbinder
Ah, ok.
Da von Sensoren die Rede war, bin ich davon ausgegangen, dass diese
räumlich abgesetzt sind und mit einem steckbaren Kabel mit einer
Zentrale verbunden wird.
Wenn sowieso alles auf einer Platine ist, sollte das dann kein Problem
sein.
evtl. sind von den einzelnen platinen(devices) sensorkabel selbst
weggeführt, aber die UART sind Platinenverbinder
1) * hierzu suche ich noch Wannenstecker und Wannenbuchsen als SMD in
2,54mm 6Polig*
2) Bytereihenfolge ist mir überlassen, oder wird es oft nach einem
bestimmten Prinzip gemacht? würde Big Endian nehmen.
3) wenn ich mal eine dez.13 übertragen will, kann ich dies nur tun,
wenn ich ein anderes Stringendezeichen für den UART-Empfang wähle??
Welches Würde sich anbieten? Ein Sonderzeichen wie '}' dann kann ich
keine dez.172 übertragen
Danke für Antworten
mir würde nur eine einzige Lösung für das Problem einfallen:
entweder
ich sende doch als string, dann hab ich mehr Zeichen, aber k. Prob mit
stringendezeichen...
*oder:*
ich sende nicht als string, aber immer eine definierte Anzahl an Zeichen
und lese via UART empfang auch nur diese Anz. an Zeichen aus, dann
brauch ich k. Endezeichen
> ich sende nicht als string, aber immer eine definierte Anzahl an Zeichen> und lese via UART empfang auch nur diese Anz. an Zeichen aus, dann> brauch ich k. Endezeichen
Das hilft dir nicht weiter, wenn du einmal aus dem Tritt kommst dann
stimmt alles nicht mehr.
Das einfachste ist wenn du ein zeichen nicht brauchst z.b. 255 das du
das als Start interpretierst und danach dann deine anzahl einliest. Wenn
jetzt innerhalb der Daten ein 255 auftaucht dann weist du das es ein
erneuter Start ist. Du musst bloss dafür sorgen das in den eigentlichen
daten dann kein 255 auftaucht.
richtig, es wäre aber schön, wenn ich von 0 bis 255 alle werte innerhalb
eines bytes übertragen könnte.
sonst brauch ich ja garnicht anfangen, ein 16int zu zerschnibbeln und
als zwei zeichen zu übertragen.
werde einfach ausweichen und doch zum string greifen. Die Datenmenge,
die ich zu handlen habe ist ja quasi lächerlich....
also nen "RH5644\n" zu senden jede sekunde...... das wird wohl gehen
dann muss ich halt nur noch die schnittstelle von ascii zu int
programmieren
oder gibt es schon ein gegenstück zu ..printf was int zu ascii machen
kann?
wenn du eh genug Reserve auf der Übertragunsstrecke hast, könntest du
auch na jeden Datensatz eine Pause machen. Dann weiss der Empfänger das
nach jeder Pause ein neuer Datensatz einfängt. Dann musst du nur dafür
sorgen das die eigentlichen Daten ohne pause gesendet werden - was aber
recht einfach ist.
Timo P schrieb:
> oder gibt es schon ein gegenstück zu ..printf was int zu ascii machen> kann?
Wenn du sowieso printf im Einsatz hast, ist scanf nicht weit.
Timo P schrieb:
> richtig, es wäre aber schön, wenn ich von 0 bis 255 alle werte innerhalb> eines bytes übertragen könnte.Beitrag "Synchronisation UART, Mega8 mit PC"
Hier findest du ein paar Ideen, wie man dieses Problem lösen kann.
ok ich könnte ja ein paket senden, was so aufgeb. ist:
0x00 0x01 0x02 DATABYTE 1 DATABYTE 2 0x02 0x01 0x00
quasi 0 1 2 als start
und 2 1 0 als ende
dann habe ich zwar die Möglichkeit alle erdenklichen Datenbytes zu
übertragen, aber den Nachteil dass ich mehr Zeichen senden muss.
wenn ich die wahrscheinlichkeit zu hoch ansehe dass die datenbytes
auch 0 1 2 oder 2 1 0 aufeinanderfolgend enthalten, muss ich noch
mehr bytes für start und endsequenz nehmen.
was soll ich nun tun?
Gerne würde ich doch strings nutzen! Oder ist mir da grundsätzlich bzw.
für meine lächerlichen Datenmengen von abzuraten?
Ich würde sagen du fängst erstmal mit Strings. Wenn du dann mal ein
größere Projekt hast wo du eventeull auch auf die Resourcen achten
musst. Kannst du dich auch mal an ein Binary Protokoll ranmachen.
Timo P schrieb:
> quasi 0 1 2 als start> und 2 1 0 als ende
Das sieht zwar alles nett aus.
Aber je komplizierter deine Start und Endesequenzen sind, umso mehr
Aufwand muss man in die Erkennung stecken.
> dann habe ich zwar die Möglichkeit alle erdenklichen Datenbytes zu> übertragen, aber den Nachteil dass ich mehr Zeichen senden muss.
Womit gerade bei kurzen Datenpaketen der Vorteil der geringeren
Datenmenge schnell wieder aufgebraucht wird.
Dass in einem Datenbyte ein von dir benutzes Steuerbyte vorkommt, ist
eine Ausnahmesituation. Ich würde das auch so behandeln: Grundsätzlich
ein so einfaches Protokoll wie notwendig und nur dann, wenn diese
Ausnahme auftritt, auf etwas komplizierters zurückgreifen.
> Gerne würde ich doch strings nutzen! Oder ist mir da grundsätzlich bzw.> für meine lächerlichen Datenmengen von abzuraten?
Du hast Zeit genug, die Aufbereitung ist simpel, auch das
auseinanderklamüsern der Daten ist kein großes Problem.
T?;
ist die Aufforderung an den Sonsor seine Temperatur zu senden. Oder
meinetwegen auch einfach nur
T;
oder vielleicht auch
?T;
(das ? steht für: Ich hätte da mal eine Frage ...
das T steht für: ... bezüglich der Temperatur
das ; steht für: hiermit beende ich das Kommando)
-----
T23.5;
ist die Antwort des Sensors. Das T steht für Temperatur. Alles danach
bis zum ; ist der Zahlenwert. Das kann man einfach programmtechnisch
leicht erzeugen und auch leicht wieder auseinandernehmen um an den Wert
als Zahl zu kommen (und vermeidet den ganzen Ärger mit \r \n oder nur \r
oder nur \n)
Der springende Punkt ist:
Es gibt kein 'richtig' und kein 'falsch'. Es gibt auch kein 'besser'
oder 'schlechter'.
'richtig' und 'gut' ist immer das, was du implementieren kannst und was
einwandfrei funktioniert. Denk dir was aus. Aber mach nicht den Fehler
einfach mal draufloszuprogrammieren ohne dir vorher ein Konzept überlegt
zu haben, wie die Kommunikation grundsätzlich funktionieren soll.
zb könntest du dir überlegen:
* Eine Übertragung beginnt mit einem Kommandozeichen und dauert immer
bis zu einem ;
Alle Zeichen dazwischen, inklusive dem Kommandobyte bilden ein Paket
* Das erste Byte eines Pakets ist immer ein Kommando
? Abfrage
! Wert wird übergeben
* Das nächste Byte des Pakets bezeichnet, welcher Wert betroffen ist
T Temperatur
D Druck
L Luftfeuchte
H Uhrzeit Stunden
M Uhrzeit Minuten
S Uhrzeit Sekunden
* Alle restlichen Bytes sind der Wert, wobei Kommazahlen mit
einem . geschrieben werden, sofern sie vorhanden sind.
* Abschliessendes Zeichen eines Pakets ist immer ein ;
Damit ist klar, wie
!T38.5;
oder
!L45;
oder
?H;
zu interpretieren ist und was zu machen ist, egal wer diese Sequenz an
wen schickt.
PS:
Ach ja. Vergiss am besten gleich wieder die Idee, die Kommunikation so
natürlichsprachlich wie möglich anzulegen. "Computer, strukturelle
Integrität um 20% erhöhen" funktioniert nur bei Star Trek.
nochmals danke für die zahlreiche Beteiligung.
ps: keine Angst, ich mag star trek eh nicht...
Raumschiff Orion sagt mir da eher zu mit Bügeleisen, Brausetablette
im Wasserglas, Badewannenstrudel usw... ;)
Ich würde vorschlagen, du baust die nen definierten Header, falls du
doch binär bleiben möchtst, z.B. so:
1. Byte | 2. Byte | 3. Byte | ..... | n-tes Byte
Start Länge Status Data Checksum
Dein UART empfängt stets per Interrupt Zeichen für Zeichen und puffert
diese. Sobald das vereinbarte Start-Zeichen erkannt wird, setzt der µC
eine Nachricht zusammen und baut diesen Puffer wieder ab. Im 2. Byte
findet er die Nachrichten-Länge, dadruch weiß er, wann er aufhören muss
die Nachricht zusammen zu setzten. Ob das funktioniert hat, merkste dann
an der Prüfsumme im letzten Byte. Im Fehlerfall kannst du einen Fehler
zurück geben und im Status Byte codieren. Die Gegenstelle kann dann
entscheiden was zu tun ist (z.B. die Nachricht wiederholen).
Vielleicht etwas dick für deinen Anwendungsfall, aber ne saubere Sache.
@Steffen A.
So einfach ist es leider nicht, das Problem ist wenn das Start-Byte in
den Daten vorkommt. Dann Synchroniert der Empfänger nicht mehr auf den
Sender.
Peter schrieb:
> @Steffen A.> So einfach ist es leider nicht, das Problem ist wenn das Start-Byte in> den Daten vorkommt. Dann Synchroniert der Empfänger nicht mehr auf den> Sender.
Das muss man halt escapen, wurde das noch nicht erwaehnt? Dann kann man
auch waehrend man die Daten liest auf das Startbyte hoeren - dann weiss
man schon vor der Checksumme, das was schief gegangen ist.
Peter Stegemann schrieb:
> Peter schrieb:>>> @Steffen A.>> So einfach ist es leider nicht, das Problem ist wenn das Start-Byte in>> den Daten vorkommt. Dann Synchroniert der Empfänger nicht mehr auf den>> Sender.>> Das muss man halt escapen, wurde das noch nicht erwaehnt? Dann kann man> auch waehrend man die Daten liest auf das Startbyte hoeren - dann weiss> man schon vor der Checksumme, das was schief gegangen ist.
Wenn das Start-Byte beim Zusammenbau der Nachricht vorkommt, sollte das
die Software nicht schocken. Sollte aber das Richtige versäumt werden
und dann das 2. "Start-Byte" fälschlicherweise als Startbyte erkannt
werden, kommt die Checksumme nicht mehr hin... Fehlermeldung senden und
die letzte Nachricht wiederholen lassen, bzw. ne fortlaufende ID mit im
Header aufnehmen. Dann kann man gezielt sagen "Nachricht No. XY nochmal,
bitte."
Bin nicht sicher, was mit dem "Unwort" escapen gemeint ist? Erbitte
Erklärung deines Vorschlages. :)
Steffen A. schrieb:
> Bin nicht sicher, was mit dem "Unwort" escapen gemeint ist? Erbitte> Erklärung deines Vorschlages. :)
Finde ich etwas irritierend, dass du eine lange Antwort schreibst und
dann erst nach dem Wort fragst, was du nicht verstanden hast. Kein
Wunder passt deine Antwort irgendwie nicht zu dem, was ich geschrieben
habe.
http://de.wikipedia.org/wiki/Escape-Sequenzhttp://de.wikipedia.org/wiki/Maskierungszeichen
Die Antwort bezog sich auf das Zitat in deinem Zitat, ich habe erklärt
wie dessen Bedenken ausgeräumt werden können. War wohl nicht ganz
offensichtlich, zugegeben.
Was escape-Zeichen sind, ist mir übrigens bekannt. Beim Zusammenhang
hatte ich gehofft, du würdest das fix in 1-2 Sätzen zusammen schreiben.