Hallo Leute!
Hab mir vor Kurzem mal so einen schönen UART - USB - Adapter geholt.
Durch das AVR-GCC Tutorial läuft alles auch soweit.
Zurzeit schalte ich damit nur eine LED über ein C# GUI an und aus.
Wie man im Code sieht kann so aber nur die Eine LED angesprochen werden,
da diese einfach auf jedes eintreffende Byte reagiert. (Bzw auf '1' und
'0')
Ich würd aber gern zum Beispiel die vom µC über ein DS18B20 gemessene
Temperatur auf dem PC anzeigen lassen. Oder auch eine Solltemperatur vom
PC auf den µC übertragen.
Jetzt zu meiner Frage:
Wie macht man das am Besten.
Meine Idee wäre:
So wie bei jeder Variablenzuweisung.
1. Byte "Adresse" zum Bsp: 0x01
2. Byte Wert zum Bsp: 0x00
Dann im µC die "Adresse" vergleichen Bsp. 0x01 -> LED1
Dann wert abseichern Bsp. 0x00 -> LED1 aus
Danach beide Bytes auf 0 setzen und neue Übertragung abwarten.
Wäre dieser Ansatz eurer Meinung nach in Ordnung oder hat jemand Die
Standardlösung für dieses Problem parat?
Den Code der GUI kann ich auch noch posten, aber ich denke der ist hier
eher zweitrangig.
Schonmal vielen Dank für die Hilfe.
1
#define F_CPU 8000000UL
2
#define BAUD 9600UL
3
4
#include<avr/io.h>
5
#include<avr/interrupt.h>
6
#include"MyLib/UART.h"
7
8
voidinit_timer0()
9
{
10
// Timer 0 konfigurieren
11
TCCR0=(5<<CS00);// Prescaler 1024
12
13
// Overflow Interrupt erlauben
14
TIMSK|=(1<<TOIE0);
15
}
16
17
volatileunsignedcharreceivedbyte;
18
volatileunsignedcharstatus='0';
19
volatileunsignedinttimer0flag=0;
20
21
22
intmain(void)
23
{
24
DDRB|=(1<<PINB0);
25
26
init_uart();
27
init_timer0();
28
29
sei();
30
31
while(1)
32
{
33
if(receivedbyte=='1')
34
{
35
PORTB|=1<<PINB0;
36
}
37
elseif(receivedbyte=='0')
38
PORTB&=!(1<<PINB0);
39
40
if(PINB&(1<<PB0)==1)
41
{
42
status='1';
43
}
44
else
45
{
46
status='0';
47
}
48
49
if(timer0flag==3)// (8000000/1024)/256 = 30,5175 Vergleich auf 3 -> 100ms
Sebastian Schubert schrieb:> Ich würd aber gern zum Beispiel die vom µC über ein DS18B20 gemessene> Temperatur auf dem PC anzeigen lassen. Oder auch eine Solltemperatur vom> PC auf den µC übertragen.>> Jetzt zu meiner Frage:> Wie macht man das am Besten.
Indem du einfach eine feste Anzahl von Bits (z.B. 32) überträgst und die
dann auf deinem PC zusammenbastelst und dann entsprechend
interpretierst. Entweder als int, wenn du eine ganzzahl hast oder als
float bei fließkommazahlen. Natürlich kannst du auch 64bit übertragen,
damit deine Genauigkeit steigt. Strings z.B. überträgt man meistens nach
dem Ascii standard mit abschließenden 0 Terminator (also ein C-String,
im Gegensatz zum pascal-string (wikipedia sollte hier helfen)).
Im Prinzip legst du fest, was wie übertragen wird. Das nennt man dann
ein Protokoll.
>> Meine Idee wäre:>> So wie bei jeder Variablenzuweisung.>> 1. Byte "Adresse" zum Bsp: 0x01> 2. Byte Wert zum Bsp: 0x00>> Dann im µC die "Adresse" vergleichen Bsp. 0x01 -> LED1> Dann wert abseichern Bsp. 0x00 -> LED1 aus> Danach beide Bytes auf 0 setzen und neue Übertragung abwarten.
Sowas in etwa wird auch normalerweise gemacht. Dabei gibt's dann s.g.
Register oder Steuerbefehle und der µC antwortet dann entsprechend
darauf. Ein Beispiel ist dafür hier:
http://invensense.com/mems/gyro/documents/RM-MPU-6000A.pdf
Hoffe ich konnte dir helfen.
Gruß
Marcel
Danke für deine Antwort Marcel.
Das heißt ich liege garnich mal so falsch.
Aber noch eine Frage zum UART.
Ich dachte der Puffer (atmega8) ist nur 8bit groß und deswegen lassen
sich Sachen wie int die 32 Bit haben garnicht ohne weiteres übertragen.
Da hab ich wohl was falsch verstanden(?)
Also wenn ich dann die 32 Bit auf dem uC habe, muss ich die dann wieder
auseinander shiften? Erste 16bit sind Adresse und letzte 16 dann wert?
Werde aus dem PDF leider nicht ganz schlau.
Sebastian Schubert schrieb:> Das heißt ich liege gar nicht mal so falsch.
:)
>> Aber noch eine Frage zum UART.> Ich dachte der Puffer (atmega8) ist nur 8bit groß und deswegen lassen> sich Sachen wie int die 32 Bit haben gar nicht ohne weiteres übertragen.> Da hab ich wohl was falsch verstanden(?)
Jein. Wenn ich das noch richtig in Erinnerung habe (schon lange nicht
mehr mit dem mega8 operiert), dann musst du deine bits auseinander
klabüstern, also ja: immer 8 bit zur Zeit, wie du das machst ist deine
Sache und Teil des "Protokolls", das du dir überlegst.
>> Also wenn ich dann die 32 Bit auf dem uC habe, muss ich die dann wieder> auseinander shiften? Erste 16bit sind Adresse und letzte 16 dann wert?
Das versteh nicht. :/ Das Problem am Mega8 ist, dass es ein 8-bit
Mikrocontroller ist und mit 16- oder 32-bit Werten nicht optimal
arbeiten kann. Wahrscheinlich kriegst du eh einen 16bit Wert von deinem
Temperatursensor (welcher ist denn das? Datenblatt?!), oder wenn das
über ADC geht, dann maximal 10bit. Das funktioniert dann so, dass du
entweder periodisch (alle n Sekunden) die Werte an den PC schickst oder
der PC aktiv nachfragt und der µC antwortet (siehe oben mit der
Registertable).
> Werde aus dem PDF leider nicht ganz schlau.
Das war ein Beispiel, wie so eine Registertable aussieht. Z.B. schickst
du 3B zu dem Chip (Seite 7 oben) und kriegst den Wert ACCEL_XOUT[15:8]
(also die oberen 8bit von einem 16bit Wert) zurück. Wenn du die unteren
8 Bit auch noch willst, dann musst du noch ein 3C schicken und kriegst
das dann zurück.
Wie das nachher aussieht ist dir komplett überlassen aber sowas solltest
du dokumentieren, damit du später nicht auf deinen Code guckst und dir
denkst "hä?". Leider schon zu häufig passiert... :)
Jap der Tempsensor gibt 16bit raus.
Datenblatt:
http://datasheets.maximintegrated.com/en/ds/DS18B20.pdf> Das versteh nicht. :/
Na ich wollte mein Protokoll ;-) ja so anlegen, dass ich einen int, sei
es nun 16 oder 32 bit, verschicke und davon 8 bit z.B. 0x01(LED1) die
Adresse ergeben und 8 bit z.B. 0x00 den Wert. Und diese dann vom µC
interpretiert werden.
Also 0000 0001 0000 0000
-Adresse- - Wert -
Und der resultierende Wert des gesamten int garnicht interessiert.
So hätte man erstmal 255 Adressen für Variablen und einen Wertebreich
von 0-255. Würde mir auch erstmal ausreichen.
> Das Problem am Mega8 ist, dass es ein 8-bit> Mikrocontroller ist und mit 16- oder 32-bit Werten nicht optimal> arbeiten kann.
Ich hab bis jetzt auschließlich mit dem Mega8 gearbeitet... Aber ich
würde gern einen 16 oder 32 bit basierten µC benutzen.
Nur habe ich gerade mal geschaut auch 48, 168 und 328 haben 8bit
register. Auch der Mega16-16. Irgendwie blick ich da nicht durch. Die
erste Zahl steht ja für den Flash-Speicher wenn ich das richtig
verstanden habe. Gibt es denn überhaupt µC mit Registern größer 8 Bit?
> Z.B. schickst> du 3B zu dem Chip (Seite 7 oben) und kriegst den Wert ACCEL_XOUT[15:8]
Ok jetz hab ich's kapiert. Man schickt dem µC ne Adresse und er
antwortet dann mit dem Wert. So wollte ich das auch machen. Ich druck's
mir mal aus und nehms mit ins Bett ;-D
Sebastian Schubert schrieb:> Ich dachte der Puffer (atmega8) ist nur 8bit groß und deswegen lassen> sich Sachen wie int die 32 Bit haben garnicht ohne weiteres übertragen.
Das stimmt. Du brauchst auf dem µC noch ein Programm, was die Bytes
nacheinander überträgt.
In einem Buch stehen doch auch mehrere Buchstaben hintereinander, um
Worte zu formen.
Ich empfehle dir, eine fertige UART-Library zu nutzen. Z.b. die von
Peter Fleury: http://homepage.hispeed.ch/peterfleury/avr-software.html
Einfach zu verstehen, zu integrieren und zu verwenden.
Diese Lib hat einen Ringbuffer, den du in einer .h Datei definierst (ist
alles beschrieben). Dieser ist z.B. 32Byte groß.
In deiner Main-Schleife fragst du einfach dauernd ab, ob neue Daten über
UART kamen. Wenn nicht, machst du mit deinem Programm weiter. Sollten
neue Daten gekommen sein, kopierst du die Daten aus dem Ringbuffer in
ein Array. So lange, bis du ein '\0' bzw ein '\n' empfangen hast.
Zum Beispiel:
#D.R\n (Data.Request)
Das wären 5 Byte Daten. Natürlich müsstest du hier einen Timeout
einbauen und dich vor Buffer-Overflow schützen.
Mit strtok(); kannst du die Daten aufteilen und in meinem Beispiel am
"." trennen. Dann hättest du ein 2d-Array mit #D und R\n
Jetzt kannst du mithilfe von str Funktionen (strcmp();) abfragen, wie
der String aussieht. Entspricht er einem gültigen befehl, schickst du
Daten zurück.
Das kann ein String sein (uart_puts();) oder einzelne Zeichen
(uart_putc();) oder Zahlen, die vorher in einen String gewandelt werden
müssen (itoa();).
Das abschließende \n nicht vergessen!
Einstellungen kannst du mit der Selben Methode machen.
Zum beispiel: #TS.23\n (Temperatur Soll 23°C)
Teilst du wieder mit strtok(); auf und das Element [1] machst du mit
atoi(); zu einem int.
Sebastian Schubert schrieb:>> Das Problem am Mega8 ist, dass es ein 8-bit>> Mikrocontroller ist und mit 16- oder 32-bit Werten nicht optimal>> arbeiten kann.>> Ich hab bis jetzt auschließlich mit dem Mega8 gearbeitet... Aber ich> würde gern einen 16 oder 32 bit basierten µC benutzen.> Nur habe ich gerade mal geschaut auch 48, 168 und 328 haben 8bit> register. Auch der Mega16-16. Irgendwie blick ich da nicht durch. Die> erste Zahl steht ja für den Flash-Speicher wenn ich das richtig> verstanden habe. Gibt es denn überhaupt µC mit Registern größer 8 Bit?
Das macht doch überhaupt keinen Sinn, die UART überträgt immer jeweils
ein Byte und das ist nunmal 8 Bit groß (obwohl es UARTs gibt die auch 9
Bits zulassen). D.h. auch bei einem 32 Bit Controller bleibt das
Register 8 Bit groß. Das ist auch überhaupt kein Problem und auch besser
so, warum sollte ich immer automatisch 4 Bytes senden, wenn ich nur ein
Byte senden will? Man sendet einfach nacheinander seinen Bytestrom.
Im Namen steht nur wie viel Flash und mit welcher max. Frequenz der
Mikrocontroller betrieben werden kann. Alle AVRs sind 8 Bit Controller.
Die XX Bits stehen auch nur mit welcher nativer Wortbreite der Prozessor
rechnet (bitte keine Diskussion über die Bedeutung, ich weiß das es
wesentlich kompliziert ist).
Danke für eure Antworten.
Ok also ist wirklich alles auf 8 Bit.
Dann werde ich mir die Lib von Peter Fleury mal anschauen. Davon hatte
ich schonmal gelesen, aber ich wollte nicht einfach ne Lib einbinden und
das war's. Ich wollte erstmal den UART an sich etwas verstehen.
Aber jetzt nen Programm zu schreiben, dass mir paar Byte zusammen
bastelt ist im endeffekt unnötig, wenn es schon jemand gemacht hat. Da
weiß ich auch wie es funktionieren würde.
So dann hab ich erstmal bisschen was zu tun. Ich meld mich mal wieder
wie's so klappt.
Danke nochmal :)
Das Protokoll sollte vor allem aber auch eine Syncronisation erlauben.
Denn sonst bekommst Du die richtigen Bytes nie zusammen.
Wenn die SW auf dem PC das 1. Byte erwartet, der µC aber das 3. Byte
sendet, werden die Daten nie dort sein, wo sie sein sollen.
ASCII-Strings würde ich mit CR, LF oder beidem enden lassen. Dann kann
man die Daten auch in einem einfachen Terminalprogramm betrachten.
Gruß
Jobst
Einen schönen Samstag euch!
So ich hab mich jetzt erstmal mit der UART-Lib beschäftigt und ich
versuche jetzt seit gestern Abend einen String vom PC einzulesen.
Code hier:
1
#define F_CPU 8000000UL
2
#define UART_BAUD_RATE 9600
3
4
#include<stdlib.h>
5
#include<avr/io.h>
6
#include<string.h>
7
#include<avr/interrupt.h>
8
#include<avr/pgmspace.h>
9
#include<util/delay.h>
10
#include"MyLib/uart.h"
11
12
voiduart_gets(char*Buffer,uint8_tMaxLen)
13
{
14
uint8_tNextChar;
15
uint8_tStringLen=0;
16
17
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
Ich lasse mir den String Probehalber einfach zurückgeben.
Das Problem ist:
while( NextChar != 'A' && StringLen < MaxLen - 1 )
Verursacht mir nur Müll in der GUI. Mit '\0' als abbruchbedingung
funktioniert es aber wunderbar!
Wenn ich also "Hallo Universum!A" Schreibe, müsste doch "Hallo
Universum!" zurück kommen...
(nebenbei: ich finde den Standardsatz "Hallo Welt" einfach ungerecht den
anderen da draußen gegenüber...)
Es kommt aber "veHaoumlou rs rsUsulrs!HUsuaniv!" bei 10 mal abschicken.
Also es kommen zufällige Stückchen zurück.
Der CPU-Takt kommt von einem 8Mhz Quarzoszillator und glaube ich somit
nen Baudfehler von 0,3. Außerdem funzt es ja mit der terminierenden 0.
Werd da echt nicht schlau draus...
> Jobst M.> ASCII-Strings würde ich mit CR, LF oder beidem enden lassen.
Hallo. Was genau sind das für Zeichen? Das eine müsste Line Feed sein.
Aber das ist doch '\r\n' unter windoof.
Sebastian Schubert schrieb:>> Jobst M.>> ASCII-Strings würde ich mit CR, LF oder beidem enden lassen.>> Hallo. Was genau sind das für Zeichen? Das eine müsste Line Feed sein.> Aber das ist doch '\r\n' unter windoof.
CR ist carriage return (Wagenrücklauf)
LF ist line feed
Ist das selbe wie \r\n
Gruß
Jobst
Sebastian Schubert schrieb:> Der CPU-Takt kommt von einem 8Mhz Quarzoszillator
Fällt mir gerade noch auf: Ist es wirklich ein Quarzoszillator? Oder der
interne 8MHz Oszillator? Der interne ist für UART nicht zu gebrauchen.
Gruß
Jobst
Hier mal mein Brettboard. Ist wirklich ein externer Quarzoszillator :)
___________
Was mir gerade auch noch aufegfallen ist. Sobald ich nen strcmp oder
sonstwas mit dem String mache kommt auch nur Müll zurück...
Hm... Also offensichtlich wird das Array beim senden gelöscht. Sonst
würde er mir ja den Bildschirm voll machen.
Das is ja aber eigentlich ziemlich blöd so. Kann man das irgendwie
verhindern?
Ha, ich glaub ich habs ;)
Der Schlüssel ist dein Kommentar:
1
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
In der library lese ich, dass diese Funktion eben nicht wartet auf das
nächste Zeichen, sondern UART_NO_DATA (=0x0100) zurückgibt.
Das erklärt auch, warum deine Methode bei '\0' trotzdem funktioniert:
Wenn kein Byte verfügbar ist, ist im Speicher 0x00 = '\0'!
Ob das dein Problem mit dem strcmp löst, weiß ich nicht.
Das war tatsächlich der Fehler!
Hab jetzt mal geändert zu
while(UART_RxHead == UART_RxTail){}
Und jetzt klappt es. Auch der strcmp funktioniert jetzt. Danke! Da stand
ich echt bisschen auf dem Schlauch :D
Aber warum steht das dann in der Lib. Is doch irgendwie unvorteilhaft.
Wenn ich die Lib wieder zurückändere müsste ich zumindest die uart_getc
auf "No Data" abfragen und dann doch wieder warten bis was ankommt.
So ich hab's jetzt. Das "No Data" ist 16Bit groß und wenn man das
abfragt sollte auch die Variable dafür min 16Bit haben...
Hier nochmal das funktionsfähige Programm. Wenn ihr noch Verbesserungen
seht bin ich immer neugierig!
1
#define F_CPU 8000000UL
2
#define UART_BAUD_RATE 9600
3
4
#include<stdlib.h>
5
#include<avr/io.h>
6
#include<string.h>
7
#include<avr/interrupt.h>
8
#include<avr/pgmspace.h>
9
#include<util/delay.h>
10
#include"MyLib/uart.h"
11
12
voiduart_gets(char*Buffer,uint8_tMaxLen)
13
{
14
uint16_tNextChar;
15
uint8_tStringLen=0;
16
17
NextChar=uart_getc();// nächstes Zeichen im Ringbuffer
18
19
if(NextChar!=UART_NO_DATA)// Zeichen vorhanden
20
{
21
while(NextChar!='$'&&StringLen<MaxLen-1)//So lange behandeln bis $ kommt oder String voll ist
22
{
23
*Buffer=NextChar;
24
Buffer++;
25
StringLen++;
26
27
do
28
{
29
NextChar=uart_getc();
30
}while(NextChar==UART_NO_DATA);// Wenn NextChar leer
Das mit den 16bit hätte ich gleich dazuschreiben können, sry.
Im großen und ganzen sieht das recht funktionsfähig aus, ich würde mir
nur überlegen ob der Code das gewünschte Ziel auf bestem/ klarsten Wege
erreicht.
zB ist die Funktion getc absichtlich so ausgelegt, nicht auf ein Zeichen
zu warten und du blockierst durch das warten deinen uC, das ist bei
diesem simplen Ablauf natürlich kein Problem aber bei komplexeren
Programmen mindestens ineffizient. Um klarzustellen was hier passiert
würde ich daher eine Funktion einführen wie "waitforc" und dann diese
verwenden, dadurch vereinfacht sich deine gets und die Logik ist besser
aufgeteilt.
1
uint16_tuart_waitforc()//muss hier void in die klammer in C?
2
{
3
uint16_tret;
4
do
5
{
6
ret=uart_getc();
7
}
8
while(ret==UART_NO_DATA);//wiederhole dies so lange bis Daten vorhanden
9
returnret;//hier könnte man auch gleich ein 8bit zurückgeben, weiß nicht wie man den type cast macht.
10
}
11
12
voiduart_gets(char*Buffer,uint8_tMaxLen)
13
{
14
uint16_tNextChar;
15
uint8_tStringLen=0;
16
17
NextChar=uart_waitforc();//les 1 zeichen
18
while(NextChar!='$'&&StringLen<MaxLen-1)//So lange behandeln bis $ kommt oder String voll ist
Hi Lenny,
Lenny D. schrieb:> Im großen und ganzen sieht das recht funktionsfähig aus, ich würde mir> nur überlegen ob der Code das gewünschte Ziel auf bestem/ klarsten Wege> erreicht.>> zB ist die Funktion getc absichtlich so ausgelegt, nicht auf ein Zeichen> zu warten und du blockierst durch das warten deinen uC
Die Funktion wird ja sofort komplett übersprungen wenn "No Data" gelesen
wird. Und wenn ein Zeichen kommt muss ja erst der ganze String
eingelesen werden bevor damit gearbeitet werden kann.
Wenn man die Funktion zwischendrin verlässt müsste man die Position des
Zeigers auch extern zwischenspeichern bis der String beendet ist und
alle Funktionen die mit dem String arbeiten, dürften ihn zwischen drin
nicht verwenden, da er nicht komplett ist - müssten dann also
übersprungen werden usw. ... Finde das so für mich persönlich schon
recht gut.
Zumal bei kompletten 39 Zeichen 39/9600 = 4ms Zeit beansprucht werden (+
die Zeit zum Vergleichen und abspeichern natürlich). Was für mich
erstmal vollkommen ausreichend ist.
> Um klarzustellen was hier passiert> würde ich daher eine Funktion einführen wie "waitforc" und dann diese> verwenden, dadurch vereinfacht sich deine gets und die Logik ist besser> aufgeteilt.
Statt einer do while eine neue Funktion die eben diese do while
beinhaltet? Ist das nicht overkill?
Ja ich sehe was du meinst, unsere Programme machen logisch was anderes:
Meines blockiert sofort, deines erst ab dem ersten Zeichen und beide
blockieren ab da bis zum '$'.
Das Auslagern in eine eigene Funktion erhöht finde ich einfach die
Leserlichkeit, ich habe zB erst mal nicht verstanden dass deins
absichtlich 2mal nach UART_NO_DATA fragt, zu 2 verschiedenen Zwecken
eben (und hab dabei das Überspringen "wegoptimiert" ;) ).
Daher versuche ich einfach immer, möglichst Dinge logisch zu trennen die
nicht unbedingt zusammengehören müssen, das reduziert finde ich auch
Fehlerquellen.
Meine gets() Funktion ist zB unabhängig von der Implementierung der
Schnittstelle, sondern wartet wie der Name waitforc() sagt auf ein
Zeichen.
Spätestens wenn du das an einer anderen Stelle benutzt, hast du dir
somit Mühe und Fehlerquellen gespart.
Aus persönlichem Stil würde ich zu deinem Zweck auch eine Funktion
definieren "uart_ischaravailable()" oder so, eventuell gibts die sogar
schon in der Lib?
Diese dürfte dann den Ringbuffer nicht verschieben, wenn ich einfach nur
UART_NO_DATA==getc() schreibe kann es ja sein dass ich ein Zeichen
verschlampe. Damit wäre ich schlussendlich jedes Vorkommen von
UART_NO_DATA in meiner gets() methode los, ich finde das hübscher.
NB: Egal wie kurz, manchmal ist auslagern sinnvoll. Lerne grad den XMC
kennen, da gibts sogar vordefinierte Einzeiler, nämlich Funktionen um
jeden Pin zu setzen:
1
__STATIC_INLINEvoidP0_1_set(void){
2
PORT0->OMR=0x00000002UL;
3
}
Plus in Leserlichkeit, plus in Abstahiertheit, plus in
Fehleranfälligkeit. Da diese inline definiert sind, werden sie beim
compilieren eingesetzt und somit sind sie genauso schnell als stünde der
Befehl in deiner Funktion.
Ich bevorzuge Text-basierte Protokolle, denn die kann man sehr bequem
mit einem Terminal-Programm debuggen.
Der Rechenaufwand ist dann für den µC natürlich etwas größer.
Sebastian Schubert schrieb:> Die Funktion wird ja sofort komplett übersprungen wenn "No Data" gelesen> wird. Und wenn ein Zeichen kommt muss ja erst der ganze String> eingelesen werden bevor damit gearbeitet werden kann.
Dann wäre es aber sinnvoll, seine Denkweise etwas zu verändern.
Geh mal gedanklich weg von der Vorstellung, dass du darauf warten musst,
das eine komplette 'Zeile' übertragen wurde.
Geh hin zum Ablauf
* die erste Frage lautet: gibt es ein Zeichen auf der UART - ja oder
nein?
* wenn ja, was soll mit diesem Zeichen geschehen, bzw. was verrät es
mir?
Wenn es nicht das finale Ende-Zeichen ist (welches auch immer das sein
mag, in deinem Fall ein '$', dann ist es ein Teil der Zeile, die ich
gerde im Begriff bin zu empfangen. In diesem Fall interessiert den
AUfrufer der Funktion noch nicht, das etwas empfangen wurde und genau
das melde ich ihm auch: die empfangene Zeile (String) ist noch nicht
vollständig
Ist es hingegen das finale Ende Zeichen, dann macht die Funktion den
String damit fertig und meldet auch seinem Aufrufer, dass der String
jetzt vollständig ist und bearbeitet werden kann.
Auf die Art hast du jegliche Form von Warterei komplett aus dem Programm
draussen. Und genau das will man ja. Man will ja weg von Programmen die
aktiv auf irgendetwas warten und man will statt dessen hin zu
Programmen, die auf Ereignisse reagieren. Ein Ereignis tritt auf und für
das Programm stellt sich die Frage: wie reagiere ich auf das Auftreten
dieses Ereignisses. In diesem Fall ist dann eben das Ereignis: Ein
Zeichen wurde empfangen.
> Wenn man die Funktion zwischendrin verlässt müsste man die Position des> Zeigers auch extern zwischenspeichern bis der String beendet ist
ja. das macht ja nichts.
> und> alle Funktionen die mit dem String arbeiten, dürften ihn zwischen drin> nicht verwenden, da er nicht komplett ist - müssten dann also> übersprungen werden usw.
Ja. Und?
Das ist kein Beinbruch. In der Hauptschleife lautet es dann eben an
einer einzigen Stelle
alles in allem ... recht überschaubar
> Zumal bei kompletten 39 Zeichen 39/9600 = 4ms Zeit beansprucht werden (+> die Zeit zum Vergleichen und abspeichern natürlich). Was für mich> erstmal vollkommen ausreichend ist.
4ms sind eine halbe Ewigkeit. Und wenn ich mal mein Lieblingsbeispiel
heranziehe: Wenn von der Putzfrau beim Fegen während der Übertragung das
Kabel irrtümlich abgezogen wird, dann steht erst mal alles, weil der µC
auf die Beendigung einer String Übertragung wartet, die die nächsten
paar Stunden nicht passieren wird.
Aktiv auf etwas zu warten ist meist keine gute Idee. Vor allen Dingen
deshalb, weil die Alternative auch nicht komplizierter ist. Es ist nur
eine etwas andere Herangehensweise.