Hallo liebe Hacker ;-)
Ich habe folgendes - wahrscheinlich suuper einfaches - "String" Problem.
Ich möchte gerne UART als "Kalibrationsmodul" für meine
Wintergartentemperaturregelung verwenden.
Dazu möchte ich gerne einen kurzen String - bestehend nur aus Zahlen via
UART in den uC einlesen, und diesen dann auswerten. Zeichen werden über
ISR eingelesen. UART Kommunikation funktioniert auch so weit, aber es
scheitert an der anschließenden Weiterverarbeitung.
Länge des Strings ist immer gleich - Position der Daten auch. Endzeichen
ist ";".
An der ersten Position im String wird die zu kalibrierende Variable
stehen.
An der 2. und 3. Position die neue Temperatur.
Beispiel:
123; Variable 1 23Grad
245; Variable 2 45Grad
Wie trenne ich jetzt am besten den String auf.
Ziel wäre es, das in der ISR die Auswertung gemacht wird, und die Daten
anschließend gleich in den EEPROM geschrieben werden. Ausserdem wird ein
"NewValueAvialable" Flag gesetzt, da die MainRoutine veranlasst, sich
die neuen Daten aus dem EEPROM zu holen.....
Folgenden Code hab schon programmiert (bzw. abgekuckt)
1
voiduart_gets(char*Buffer,uint8_tMaxLen){
2
uint8_tNextChar;
3
uint8_tStringLen=0;
4
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
5
6
// Sammle solange Zeichen, bis:
7
// * entweder das String Ende Zeichen kam
8
// * oder das aufnehmende Array voll ist
9
while(NextChar!=';'&&StringLen<MaxLen-1)
10
{
11
*Buffer++=NextChar;
12
StringLen++;
13
NextChar=uart_getc();// While schleife wird bei Strichpunkt beendet.
Ich sehe da zunächst noch ein anderes Problem.
Der UART-Rx-Interrupt kommt pro empfangenem Zeichen. Es ist sinnlos,
darin einen gesamten String (also mehr als 1 Zeichen) abholen zu wollen
und genauso, darin einen ganzen String abzusenden. Das solltest Du
besser zunächst umschreiben (Ansätze für UART-Rx-Interruptroutinen
gibt's hier viele zum Nachlesen), bevor Du Dich an die Verarbeitung des
empfangenen Strings machst.
Benni L. schrieb:> Sieht so aus, als wäre atoi(char *string) dein Freund.>> Wenn du danach ein wenig suchst, dürftest du schnell fündig werden.
Ich hab schon ein wenig mit atoi rumprobiert...
Solange ich den ganzen String mit atoi bearbeite funktionierts
wunderbar.
1
waiting=atoi(Line);
2
printf("\n wartezeit %i \n",waiting);
Verwende ich aber atoi(Line[1]) gehts nicht mehr.
Das die ISR bei jedem neuen Zeichen ausgeführt wird kann ich mir ehrlich
gesagt nicht vorstellen, den die obrigen Zeilen waren schon in der ISR
drinn, und das hat wunderbar fuktioniert.
Aber falls es wirklich so sein sollte, dann kann ich das ganze auch in
der Main machen...
Bin grad schon ein wenig zu müde um mich mehr reinzudenken.
Aber probier doch einfach sprintf("%s",Line) mal aus, dann siehst du wie
viele Zeichen in Line sind.
Und was willst du mit atoi(Line[0]), das funktioniert natürlich nicht.
Da atoi einen Pointer erwartet und dann den String durchgeht bis zum
Ende des String. Evtl. funktioniert atoi(&Line[0]) bzw. dann halt gleich
atoi(Line).
Du solltest der Funktion atoi(const char* s) einen String übergeben und
nicht ein char. Durch Line[1] wird ein char übergeben und dieser in
einen Zeiger auf einen String konvertiert.
Der Compiler wirft sicher eine Warning:
warning: passing argument 1 of 'atoi' makes pointer from integer without
a cast
Also übergib den Zeiger auf den String an atoi:
Wolfgang E. schrieb:> Das die ISR bei jedem neuen Zeichen ausgeführt wird kann ich mir ehrlich> gesagt nicht vorstellen,
Das Datenblatt hilft hier weiter.
> den die obrigen Zeilen waren schon in der ISR> drinn, und das hat wunderbar fuktioniert.
Mag sein, wenn ein paar Randbedingungen zutreffen. Da Du nur ein paar
Ausschnitte und nicht das komplette Programm gezeigt hast, lässt sich
das nicht beurteilen. So der Richtung nach würde ich sagen, dass
mindestens jeweils das erste Zeichen fehlen dürfte. Der Sinn einer
Interruptroutine ist ohnehin verfehlt, wenn darin gewartet wird, z.B.
auf das nächste Zeichen.
Aber aus nichts lernt man besser als aus den eigenen Fehlern (heißt es).
Ich lasse es also.
Hi
wenn ich dich richtig verstanden habe ist die erste stelle deines String
ein
Index und die nächsten 2 der wert welcher in den index geschrieben
werden soll.Du must also nur aus den einzelen Zeichen in den String eine
Zahl machen und einmal mit 10 Multiplizieren. Die Quick& Dirty lösung
die mir sofort einfallt ist von den jeweiligen Zeichen '0' abziehen.
Ist zwar super dreckig aber die Erfahrung zeigt das es geht. Wenn du es
eine Stufe Sauber machen willst macht du ein Switch Case für das
jeweilige Zeichen. Dann must du nur noch (tm) bei deiner Grad Celsius
Rechnung die Zahl die du in dem Zehner teil mit der 10 multiplizieren.
Wolfgang E. schrieb:> Länge des Strings ist immer gleich - Position der Daten auch. Endzeichen> ist ";".>> An der ersten Position im String wird die zu kalibrierende Variable> stehen.> An der 2. und 3. Position die neue Temperatur.>> Beispiel:>> 123; Variable 1 23Grad> 245; Variable 2 45Grad> Wie trenne ich jetzt am besten den String auf.
Wenn ich Dich recht verstehe, dann baust Du dir den String selbst auf.
Also könntest Du Dein Protokoll etwas besser bzgl. der Auswertung
gestalten.
Was hindert dich daran z.B. zu schreiben:
1:26;
oder 12=142;
Jetzt kannst Du einfach den String einlesen, bis Du auf ein Doppelpunkt,
bzw. ein '=' stösst und weisst genau, daß der erste Teil die Nummer der
Variablen ist und der folgende Teil der Wert. Du speicherst beim Lesen
aus der seriellen Schnittstelle schon beide Teile in verschiedenen
Strings ab und kannst die dann mit atoi oder atol einfach konvertieren.
Auch könntest Du dann sowohl Deine Variablen statt mit Ziffern mit Namen
versehen und als Werte auch String senden wenn das mal nötig sein
sollte.
Was deine Progammierkenntnisse betrifft. Jeder fängt mal an, aber man
lernt nicht indem man Code aus dem internet zusammensucht, sondern indem
man sich eine bewältigbare Aufgabe stellt und die dann selbstständig
löst. Stringverarbeitung/Zerlegung ist eines der Basics, das solltest Du
selbstständig können.
Also nimm dir so ein Beispiel und programmiere das auf dem PC bis es
funktioniert. Dort kannst Du viel schneller ausprobieren und besser
debuggen als auf dem µC. Wenn es dann grundlegend funktioniert portierst
Du den Code in dein µC Programm.
Viel Spass am selbst programmieren.
Ich bin der Meinung: "In die ISR immer nur das allernötigste". Ich würde
da eine zusätzliche Auswerteroutine nehmen, die vom Hauptprogramm
ausgerufen wird, wenn Zeit ist. Die sammelt die Zeichen ein (lokale,
statische(!) Variable) und startet eine Auswertung, wenn das Ende
erkannt wird.
Das könnte dann so aussehen:
1
var_index=buffer[0]-'0';
2
var_value=atoi(buffer+1);
Die Werte sollte man dann noch unbedingt auf Konsistenz prüfen.