Hallo!
Bin gerade dabei mittels Tasterdruck eine SMS zu versenden.
Beim ersten Tasterdruck funktioniert alles besten, doch beim zweiten mal
kommt das Unterprogramm zum Versenden der SMS immer nur bis zum printf
Befehl. Dieser wird nicht mehr über die serielle Schnittstelle
rausgeschrieben.
Um das ganze zu initialisieren benutze ich:
fdevopen (uart_putchar, uart_getchar);
und:
Beim compilieren bekomme ich dises Warning:
../handy.c:50: warning: passing argument 1 of 'fdevopen' from
incompatible pointer type
Habt ihr vielleicht einen Verdacht warum das printf nicht rausgeht über
die schnittstelle?
Ich kann natürlich auch den ganzen Code senden.
Vielen Dank,
philip
Phil schrieb:
> Beim compilieren bekomme ich dises Warning:> ../handy.c:50: warning: passing argument 1 of 'fdevopen' from> incompatible pointer type
Kompletten Code zeigen.
Grrrr schrieb:
> Die Rekursion in uart_putchar geht natürlich schief.
Nö.
Warum sollte die schief gehen (ausser durch einen knapp bemessenen
Stack)
> Besser:>
1
>intuart_putchar(charc){
2
>if(c=='\n')
3
>c='\r';
4
>//Warten solange bis Zeichen gesendet wurde
5
>while(!(UCSRA&(1<<UDRE)));
6
>//Ausgabe des Zeichens
7
>UDR=c;
8
>return(0);
9
>};
10
>
Das macht was anderes.
Die Idee im Original ist es, einem \n ein \r voranzustellen. Dein Code
ersetzt ein \n durch ein \r
Phil schrieb:
> anbei der code
Ich habe mich falsch ausgedrückt.
Reduziere den Code bitte soweit, das der Fehler gerade noch auftritt,
das Ganze aber kompilierbar ist.
Dann brauchen wir nicht so viel lesen, was garnichts mit dem Problem zu
tun hat.
Du solltest auch einmal dein gesamtes Konzept überdenken. Da sind einige
Stolperfallen mit drin. Z.B. schreibt man in die ISR keine while
Schleifen. Dein strcmp beim auslesen des Inhaltes einer SMS ist auch
fragwürdig. Was ist wenn jemand EIN schreibt oder ein Leerzeichen
anfügt? Das auslesen der SMS zyklisch zu machen ist auch völlig
überflüssig ( es sei denn ich hab mich verguckt). Beim Eingang einer SMS
bekommst du über die serielle Schnittstelle ein +CMTI Kommando zurück
mit dem entsprechenden Index wo die neue SMS gespeichert ist. Da braucht
man nichts pollen. Lediglich den UART Puffer auf z.B.
if ( strstr((char*)uart_string,"+CMTI:") ){
überprüfen und wenn das schon mal geklappt hat, den Index der SMS
auslesen mit sscanf((char*)uart_string,"+CMTI: \"ME\",%i",&sms_index);
und die entsprechende SMS abrufen.
Das sind nur ein paar Kleinigkeiten, aber genau an so einer wirst du
hängen. Ist alles ein wenig unübersichtlich. Schalte dir doch einfach
mal ein paar LEDs an bestimmten Codeabschnitten ein. Ich tippe mal, dass
du irgendwo in einer Endlosschleife kommst und es nicht an dem printf
scheitert. Oder du hast irgend ein Flag nicht zurückgesetzt.
Evtl. hilft dir auch mein Code
(http://www.mikrocontroller.net/articles/Versenden_von_SMS_mittels_Mobiltelefon).
Da reagiere ich auch auf bestimmte Textinhalte einer SMS und führe dann
eine bestimmte Funktion aus (Wie z.B. die Heizung einschalten). Ist nur
ein wenig universeller (zumindest denke ich das^^)
du hast absolut recht - es ist ein wenig unübersichtlich!
Ich bekomme aber kein BEfehle auf die RS232 bei empfangener SMS.
Muss ich das beim Handy extra einschalten.
Ich hab auch noch das Echo vom Handy an - das könnte auch ein Problem
sein.
Schau dir mal in meinem Artikel die sms.c an. Da findest du eine
sms_init() in welcher die UART Schnittstelle initialisiert wird, das
Echo ausgeschaltet wird, der Speicherplatz eingehender SMS auf den
internen Speicher des Handys gesetzt wird und das new message indication
eingestellt wird. Probier das einfach mal aus und schau dann nach, ob
wirklich keine Indikation kommt. Der Befehl war glaube ich AT+CNMI...
für die new message indikation.
Die Unübersichtlichkeit bekommst du dchon weg, wenn du alles was
zusammengehört in einzelne *.c Dateien auslagerst. Also deine State
Machine z.B. mit in die handy.c Die ganzen UART Funktionen in eine extra
UART.c and so on...
Pass auch auf deine globalen Variablen auf. Da fehlt bestimmt auch
irgenwo ein volatile.
Auszug aus dem Artikel:
Die aktuelle Software passt nicht mehr in einen ATmega8. Ich arbeite
aktuell mit einem ATmega32. Mit ein paar Anpassungen sollte es aber
problemlos möglich sein, den Code in der Größe stark zu reduzieren. So
können z.B. die Bibliotheken zur Ansteuerung des Temperatursensors
entfallen (twi.c, twi.h, ds75lv.c und ds75lv.h).
Hast du die Optimierungen eingeschaltet?
Du kannst auch Funktionen, welche du nicht benötigst rausschmeissen.
Evtl. brauchst du z.B. nicht die Funktion zum Anzeigen von Nachrichten
auf dem Display (sms_diaplay_text) etc...
Remote One schrieb:
> Ich habe schon den Code für den Temp Sensor rausgenommen,> Data ist aber immer noch 106,6 % voll !!
Data sind Variablen etc. du kannst ja den SMS Puffer Speicher von 450
Zeichen reduzieren. Also einfach in der uart.h das define uart_maxstrlen
von auf z.b 50 reduzieren. Das bedeutet aber auch, dass du nicht mehr
SMS mit 160 Zeichen empfangen kannst. Die 450 kommt Zustande, da ja
neben den einzelnen Zeichen der Nachricht noch der PDU Header dazukommt
(also TelNr, Zeitstempel etc.). Zudem wird jedes Zeichen der Nachricht
ja im PDU Format als Hex String übermittelt. Also ist im schlimmsten
Fall jedes einzelne Nachrichtenzeichen 2 Byte groß. Jeder konstante
String nimmt natürlich auch Speicher im Data Bereich weg. Also jeden
printf("at-....");
Ich schau mal was in den nächsten Tagen noch reduzieren kann.
Hattest du nicht bei einem Text von "Ein" in der SMS die Heizung
eingeschaltet??
Dann ist es doch einfacher, diesen Bereich in der sms.c anzupassen:
1
constSMS_CMD_LIST_Tsms_cmd_list[]={
2
{"set",sms_cmdset},
3
{"test",sms_cmdtest}
4
};
Also statt "set" nimmst du "Ein" und gibst dann noch die Funktion an,
welche ausgeführt werden soll.
OK, du hast es aber erst einmal versucht, mit einem Anruf.
In der sms.c brauchst du dazu eigentlich gar nichts ändern. Schau dir
doch einfach mal die main loop an, dort wird zyklisch sms_state_machine
ausgeführt. Der Rückgabewert ist aus dem enum:
1
typedefenum{
2
SMS_OK,/**< OK von Mobiltelefon empfangen */
3
SMS_ERROR,/**< ERROR von Mobiltelefon empgangen */
4
SMS_MSG_DECODE,/**< Textnachricht eingegangen, decodiert und in \ref SMS_DECODE_DATA_T Struktur gespeichert */
5
SMS_INCOMING_RING,/**< eingehender Anruf */
6
SMS_CANCEL_RING,/**< eingehender Anruf wurde abgewiesen */
7
SMS_REQUEST_TELNR,/**< Telefonnummer des eingehenden Anruft wurde abgefragt */
8
SMS_RETRIEVE_TELNR,/**< Anrufer wurde abgewiesen, Telefonnummer ermittelt und korrekt mit \ref SMS_TELNR verglichen */
9
SMS_IDLE/**< empfangene Zeichenkette wurde nicht in sms_state_machine "gefunden" (kein Eintrag) */
10
}SMS_MSG;
Das heisst, du kannst in der main loop von der sms_state_machine den
Rückgabewert vergleichen mit SMS_RETRIEVE_TELNR.
1
uint8_tflag;
2
flag=sms_state_machine()
3
if(flag==SMS_RETRIEVE_TELNR){
4
//mach irgend was
5
}
Wenn das zutrifft, hast DU angerufen (insofern du in der sms.h deine
Telefonnummer eingetragen hast, also SMS_TELNR). Das ist denke ich das
einfachste. Das ganze Projekt ist ja extra so angelegt, dass du
möglichst wenig am code ändern musst. Also entweder mit den
Aufzählungstypen arbeiten (enum SMS_MSG) oder eben das mit den
Textnachrichten-Phrasing.
Schau dir in Verbindung mit dem Detektieren des Anrufes auch einmal an,
was dein Handy sendet bei einem Anruf. Ich vergleiche mit "Ring". Manche
Mobiltelefone senden aber auch etwas anderes. Also erst einmal mit hterm
überprüfen und evtl. anpassen.
(Für weitere Fragen bin ich morgen wieder erreichbar^^. Muss jetzt
langsam Schluss machen.)
Phil schrieb:
> Ich habe schon den Code für den Temp Sensor rausgenommen,> Data ist aber immer noch 106,6 % voll !!
Remote One schrieb:
> Data sind Variablen etc. du kannst ja den SMS Puffer Speicher von 450> Zeichen reduzieren. Also einfach in der uart.h das define uart_maxstrlen> von auf z.b 50 reduzieren.
Das mit den 50 war etwas zu voreilig. Ich habe mir mal eben den Header
vom PDU String angeschaut. Der ist im schlimmsten Fall 60Byte groß. Das
heisst, wenn du für uart_maxstrlen 290 eingibst sollte es auch
problemlos in die Data Sektion des ATmega8 passen (habe bei dem Test die
Lib zum Temp Sensor noch mit drin gehabt, also kann es auch höher als
290 sein). Bei einem eingestellten Wert von 290 solltest du noch
Textnachrichten mit ca. 130 Zeichen empfangen können.
Erst einmal möcht ich mich bei dir bedanken, dass du dich um mein
Problem so annimst!
Ich sag dir einmal was mein Programm können sollte:
- Bei Anruf soll die Heizung umgeschaltet werden und eine SMS mit dem
aktuellen Status der Heizung zurück gesendet werden.
- wenn eine SMS mit dem Text "Ein" ankommt soll eingeschaltet werden.
- wenn eine SMS mit dem Text "Aus" ankommt soll ausgeschaltet werden.
- wenn eine SMS mit dem Text "Status" ankommt soll der aktuelle Status
per SMS zurück gesendet werden.
So, bin jetzt beim ersten Problem:
Bei Anruf umschalten: Habe ich so gelöst wie du gestern gesagt hast.
Funktioniert auch nur kommt am Handy dann ein komisches Symbol, das
Handy lasst sich auch nicht mehr normal bedienen bzw. ausschalten.
Das Symbol findest du im Anhang.
Das Handy lässt sich weiter hin mit den AT Befehlen steuern, also
soweit kein Problem - wahrscheinlich aber trotz dem nicht erwünscht.
Vielleicht könnten wir auch per Email weiter kommunizieren...
Phil schrieb:
> Funktioniert auch nur kommt am Handy dann ein komisches Symbol, das> Handy lasst sich auch nicht mehr normal bedienen bzw. ausschalten.
Das Problem hat sich mit einem anderen Handy erledigt...
Weiß jetzt nicht was der Fehler war.
Werd jetzt das Thema mit den SMS versuchen zu lösen, bei Problemen melde
ich mich wieder...
Schön dass sich alles von alleine regelt ;)
Ich hab den Artikel zum Versenden von SMS auf deine Anfragen auch noch
einmal ergänzt. Da kannst ja auch noch mal rein schauen. Auch wenn sich
das mit dem "Symbol" erledigt hat, so sieht es für mich so aus, als
würde das Handy erkennen, dass das Datenkabel dran ist und in einen
"Kommunikationsmodus" umschalten. Das kann man bestimmt in den
Einstellungen abschalten. Die zwei Symbole sehen ja schon wie 2 Handys
aus und die Pfeile symbolisieren den Datenaustausch. Das würde auch
erklären, warum die AT Kommandos noch klappen.
Remote One schrieb:
> Das kann man bestimmt in den> Einstellungen abschalten
ok, das werde ich versuchen und sag dir dann bescheid!
Bin nun beim Versenden der SMS:
in der Main schleife läuft nun:
1
flag=sms_state_machine();
2
if(flag==SMS_RETRIEVE_TELNR){
3
if(Heizung==0)
4
{
5
Heizung=1;
6
sms_send(SMS_TELNR,"Heizung Ein");
7
}
8
else
9
{
10
Heizung=0;
11
sms_send(SMS_TELNR,"Heizung Aus");
12
}
13
}
der MC sendet aber nichts über die Schnittstelle raus, nicht einmal das
"AT+CMGS=xx" geht raus.
was hab ich falsch gemacht :-) ?
Ich habs auch gerade mal über hterm getestet (Handyakku ist gerade
leer^^) und da geht alles problemlos raus.
Kannst du das Problem weiter eingrenzen?
Also falls du ein Display hast ein paar Zwischenausgaben machen oder
LEDs toggeln. Ich weiss ja icht in wie fern du was am code geändert
hast. Aber in der Funktion sms_send wird ja lediglich über printf der
PDU string raus geschrieben.
Wird denn der eingehende Anruf korrekt detektiert?
In der sms_send sind zwei while Schleifen vor der Ausgabe von AT+CMGS.
Evtl hängst du da fest.
Ist die Telefonnummer auch ein String? Also sind im Makro die "..." mit
dabei.
ich hab jetzt vor der ersten while schleife ein "AT" eingefügt und das
delay, jetzt funktioniert das SMS senden.
Versteh aber eigentlich nicht was das bringen soll...
Remote One schrieb:
> Ist die Telefonnummer auch ein String? Also sind im Makro die "..." mit> dabei.
das stimmt, der Anruf wird ja auch richtig erkannt.
Das wird einfach nur das delay sein. Das hab ich auch schon
festgestellt, dass die Mobiltelefone mitunter etwas Zeit zum Überlegen
brauchen ;)
Phil Wurglits schrieb:
> das stimmt, der Anruf wird ja auch richtig erkannt.
Stimmt^^
Jetzt möchte ich noch im Hauptprogramm den Text der Empfangengen
Nachricht auswerten.
Kannst du mir das bitte kurz zeigen bzw. hast du auch gleich eine gute
Seite da besser in die C-Programmierung reinzuschnuppern???
Das Auswerten von Textnachrichten wird automatisch in der
sms_state_machine gemacht. Das heißt, wenn über die serielle
Schnittstelle erkannt wird, dass einen Textnachricht eingeht, wird der
Index ermittelt und diese ausgelesen. Das Ergebnis, also der PDU String,
wird decodiert und in der globalen Variable sms_dec_data der
Datenstruktur SMS_DECODE_DATA_T abgelegt. Automatisch wird ebenfalls der
decodierte Text nach den von dir festgelegten Schlüsselwörtern
durchsucht und die entsprechend hinterlegte Funktion über den
Funktionspointer aufgerufen. Du brauchst also nur, wie im Artikel
beschrieben, in der sms.c das Konstrukt
1
constSMS_CMD_LIST_Tsms_cmd_list[]={
2
{"set",sms_cmdset},
3
{"test",sms_cmdtest}
4
};
anpassen. Also der erste Parameter ist der String auf den reagiert
werden soll. Dabei ist zu beachten, dass es nur Kleinbuchstaben sind, da
ich den Text immer in Kleinbuchstaben wandle und dann erst vergleiche.
Die Funktion, also hier z.B. sms_cmdset muss nach folgendem Schema
aufgebaut sein:
1
uint8_tfunktionsname(uint8_tdat){
2
...
3
}
Ich habe das so gestaltet, da ich es noch realisieren möchte, dass auch
Parameter an die Funktion übergeben werden. Also, dass man z.B.
Heizung#1 schreibt und die Heizung eingeschaltet wird bzw. bei Heizung#0
wird eben ausgeschaltet. Da würde ich dann nur nach Heizung suchen und
die nachfolgende Zahl als Parameter der Funktion übergeben. Das ist
zumindest geplant^^
ok, das Problem ist nur dass ich den beiliegenden Code auskommentiert
habe, sonst würde der Code nicht in den ATMEGA passten.
Es hilft auch nichts wenn ich den Code auskommentiere um einen Text auf
das Display zu schreiben.
Die Empfangslänge für den ankommenden String beträgt 200 Zeichen.
Sonst kann ich meiner Meinung nach nichts mehr auskommentieren, da ich
die anderen Funktionen benötige.
hättest du vielleicht sonst noch eine Idee oder muss ich auf einen
größeren Controller ausweichen?
Ist halt mühsam weil die Platine und der Aufbau schon fix fertig ist!
1
// sortieren der Befehlsliste (Voraussetzung für bsearch)
Remote One schrieb:
> Na ja, sms_time könntest du noch auskommentieren
Sorry, hab ich vergessen zu sagen.
Habe sms_time auch schon draußen,
die Librarys fürs LCD und den Temp Sensor auch schon draußn.
Ich glaub dann bleibt leider nichts mehr übrig :-(
Hallo!
Hab mir nun den ATMEGA328 angeschafft und auch schon das erste Problem.
Immer wenn das Handy etwas über den UART zum AVR sendet startet dieser
neu.
Was kann den das für ein Problem sein.
Ich habe alle Register auf den ATMEGA328 angepasst, sonst sollte sich im
Code ja nichts verändern oder?
Das kann alles und auch nichts sein. Teste am Besten alles step by step
durch. D.h. erst einmal mit hterm prüfen ob du eine vernünftige
Kommunikation mit dem Mobiltelefon zu Stande bekommst. Dann bei dem
neuen µC lediglich die UART Schnittstelle überprüfen. D.h. auch wieder
mit hterm --> also hterm + µC.
Dann kannst du erst das Mobiltelefon anschließen und weiter testen.
Hast du die Fuses des neuen µC richtig gesetzt? OK das wird du
spätestens beim Test hterm + µC sehen. Also immer schön Schritt für
Schritt vorgehen und nicht zu viel auf einmal ändern um korrekt
Rückschlüsse zu ziehen.
Hast du was an der Beschaltung geändert, also hast du alle
Abblockkondensatoren dran?
Hallo,
hab das Problem behoben...
Die Interruptroutine muss man folgendermaßen aufrufen ISR(USART_RX_vect)
was anderes,
Ich habe im Hautpprogramm eine Variable die Heizung heißt!
Wenn ich nun "ein" als SMS bekomme soll diese Variable auf 1 gesetzt
werden.
Ich habe nun im main.c folgenden Code
1
uint8_tsms_cmdein(uint8_tdat)
2
{
3
Heizung=1;
4
return0;
5
}
und in sms.c
1
constSMS_CMD_LIST_Tsms_cmd_list[]={
2
{"ein",sms_cmdein},
3
{"aus",sms_cmdaus}
4
}
die SMS wird nachher auch gelöscht!
muss ich den Code den ich im main.c habe im sms.c schreiben?
Wenn ja, wie kann ich dann meine Variable ansprechen.
Ein bisschen dumm erklärt, ich hoffe du weißt was ich meine!
Phil Wurglits schrieb:> Ein bisschen dumm erklärt, ich hoffe du weißt was ich meine!
Richtig verstanden hab ich nicht^^
Phil Wurglits schrieb:> Ich habe nun im main.c folgenden Code
<uint8_t sms_cmdein(uint8_t dat)
> {> Heizung=1;> return 0;> }>> und in sms.cconst SMS_CMD_LIST_T sms_cmd_list[] = {> {"ein",sms_cmdein},> {"aus",sms_cmdaus}> }
Aber da fehlt noch der Eintrag in sms.h. Also du musst den Prototyp in
sms.h anlegen, damit sms.c auch was damit anfangen kann. Also einfach
den folgenden Eintrag durch deine Funktionsprototypen ersetzen (ist in
sms.h ganz unten zu finden)
1
externuint8_tsms_cmdset(uint8_tdat);
Da müsste eigentlich auch eine Fehler oder ein Warning kommen, wenn du
das nicht gemacht hast. Aber evtl. hab ich dich nur falsch verstanden.
okela, habe jetzt alles hinbekommen, dank deiner Hilfe - vielen dank!
Nun noch eine Frage!
Die Software funktioniert ja nur mit einer Nummer die fix programmiert
ist.
Wäre es nicht möglich beim Einschalten die ersten 5 Nummern im
Telefonbuch auszulesen und diese für Anrufe oder SMS freigeben?
lg, philip
Phil Wurglits schrieb:> Wäre es nicht möglich beim Einschalten die ersten 5 Nummern im> Telefonbuch auszulesen und diese für Anrufe oder SMS freigeben?
Ja, möglich ist alles...
Ich schau mir das mal an. Hab in letzter Zeit aber mehr mit meiner
Masterarbeit zu tun. Ich such auf jeden Fall mal den AT-Befehl zum
auslesen der Nummern raus. Sollen die Nummern vom Mobiltelefon oder von
der SIM kommen?
Na ja, da kann ich auch wieder einen Schalter aller #define... machen.
Ich habe das mit den Nummern in meinen alten Programm so gelöst, dass
ich die ersten 5 Nummern von der Sim Karte abfrage und diese dann für
Anruf und SMS freigebe.
Nur schaffe ich es nicht, dass ich meinen alten Code in dein Projekt
einbaue, so dass es funktioniet - da hab ich wohl zu wenig Wissen in C !
Ich kann dir gerne meine Lösung in meinem alten Projekt am Abend posten.
Ist für dich dann sicher einfach, das ganze zu implementieren.
Phil Wurglits schrieb:> Ich habe das mit den Nummern in meinen alten Programm so gelöst, dass> ich die ersten 5 Nummern von der Sim Karte abfrage und diese dann für> Anruf und SMS freigebe.
Das sollte mit at+cpbs und at+cpbr eigentlich nicht so schwer sein. Ich
muss ja nur ein Array für die 5 Telefonnummern anlegen und die ersten 5
Einträge da rein packen. Das bekomm ich schon hin^^
Der Vergleich müsste natürlich angepasst werden. Das klappt schon...
Sende mal an dein Mobiltelefon AT+CPBS="SM" <cr><lf>
und danach AT+CPBR=1 <cr><lf>
Poste dann mal die exakte Antwort am besten als hex und ASCII Werte.
Ich hab grad mal ein paar Stunden Zeit, aber kein Mobiltelefon zur Hand.
Ich weiß nicht, ob vor der Antwort von CPBR noch ein \n\r kommt und wo
evtl Leerzeichen sind.
Ansonsten kann ich mich da nicht vor Donnerstag ran setzten.
%s liest immer bis zu einem white space, also bis Leerzeichen,
Zeilenvorschub, Tab etc..
Eine feinere Steuerung geht mit %[...] bzw. %[^...].
Wenn du das Lesen also bei einem Gänsefüßchen abbrechen willst,
müsstest du %[^"] im Formatstring haben, was dann im Quelltext
als %[^\"] zu schreiben wäre.
Verdammt, hast Recht (Brett vorm Kopf^^)
Da ich die Länge der Telefonnummer nicht kenne bleibt mir wohl nichts
anderes übrig, als auf das " nach der Telefonnummer zu parsen und mit \0
zu ersetzen.
Klaus Wachtler schrieb:> Wenn du das Lesen also bei einem Gänsefüßchen abbrechen willst,> müsstest du %[^"] im Formatstring haben, was dann im Quelltext> als %[^\"] zu schreiben wäre.
Cool, das war neu für mich. Steht nicht einmal in meinem C Buch. Hab
schon nach so etwas gesucht ;)
Werde es gleich mal probieren
Klaus Wachtler schrieb:> wieso mit \0 ersetzen?scanf("+CPBR:
%i,\"%[^\"]\",%i,\"%s\"\r\n",&dummy,telnr,&dummy,tmp);
> sollte das schaffen.> Den Dummy-Wert kannst du dir übrigens sparen mit:scanf("+CPBR:
%*i,\"%[^\"]\",%*i,\"%s\"\r\n",telnr,tmp);
Ja thx, ich hatte deinen Beitrag zu spät gelesen. Ich habs jetzt so:
1
scanf("+CPBR: %i,\"%[^\"]",&dummy,telnr);
damit fällt dann auch das lästige tmp raus (frisst eh nur Speicher)
Klaus Wachtler schrieb:> http://www.wachtler.de/ck/19_4_Liste_Funktionen.ht...
Ja, da sollte man(n) dann doch mal öfters nachschauen. Hab die zwar in
den Favoriten, schau aber meist dann doch ins C Buch^^
Nochmal thx, wieder was gelernt
> sollte das schaffen.
Nichts gegen diese "neuen" Regular Expressions im Formatstring.
Aber:
Es ist IMHO unklug, von der Eingabe nicht alles zu lesen. Mit sowas
kommt man ganz schnell in Teufels Küche bei nachfolgenden
Leseversuchen, weil man nie weiß was und wieviel noch im Input-Buffer
wartet. Besonders dann, wenn es beim scanf-Parsen zu Fehlern kommt,
sitzt man da ganz schnell in der Bredoullie.
Die Empfehlung von früher
zuerst eine komplette Zeile in einen programminternen Buffer lesen
von dort weg mit einem sscanf (oder sonst irgendwie anders) parsen.
hat auch heute noch ihre Berechtigung.
Edit: vergiss das mit dem 'nicht alles lesen' wieder. Hab zu spät
gesehen, dass ja ohnehin bis zum \n gelesen wird. Nichtsdestotrotz
bleibt noch das unangenehme Behandeln von Fehlersituationen, die einem
mit scanf den ganzen Tag versauen können.
Daher mein vorsichtiger Ratschlag mit dem Rückgabewert.
Prinzipiell gebe ich dir aber sicher recht.
Wenn man eine definitiv in Zeilen organisierte Eingabe erwartet,
ist es sinnvoll die auch so zu verarbeiten.
Ob man dafür je nach Rechner reichlich Puffer spendieren will,
hängt natürlich von den Umständen ab.
Auf einem PC ist das gar kein Thema, aber da würde ich mir
sowas gar nicht mehr in C antun, sondern C++ nehmen.
Auf einem MC dagegen will man vielleicht nicht immer
dafür Speicher veplempern. scanf() ist jetzt auch nicht
gerade ein Sparmodell, aber wenn man es an einer Stelle schon
braucht, kann man die Funktionalität auch gleich ausreizen,
anstatt sich an jeder Stelle selbst etwas zu bauen.
Klaus Wachtler schrieb:> braucht, kann man die Funktionalität auch gleich ausreizen,> anstatt sich an jeder Stelle selbst etwas zu bauen.
Schon klar.
Ich denke, dir ist es in deinen Sturm und Drang Lehrjahren auch nicht
anders gegangen als mir und so ziemlich jedem anderen C-Novizen. Man ist
begeistert von den Möglichkeiten, die einem der Format-String von scanf
so bietet und baut hoffnungsfroh seine ersten Programme mit scanf.
Funktioniert auch alles super, bis man das erste mal nicht selbst an der
Eingabe sitzt. Plötzlich krankt es hinten und vorne und nichts geht
mehr. (Die Erklärung: Als Entwickler tendiert man dazu, Eingaben die
nicht erlaubt sind auch nicht zu machen. Lieschen Müller ist das aber
egal, die tippt frei von der Leber weg). Dann fängt man an, mit dem
Returnwert von scanf zu arbeiten und irgendwie den Input Stream wieder
in einen vernünftigen Zustand zu bringen etc. Nach langen, mühevollen,
frustrierenden Versuchen kommt jeder irgendwann zum Schluss, dass es so
nicht wirklich brauchbar geht. Solange der Input machinengeneriert ist
und man nicht unbedingt mit Fehlern im Datenformat rechnen muss, gehts
ja noch. Aber ein scanf direkt auf die Benutzereingabe ist ganz schnell
eine 'Nightmare die sich gewaschen hat'.
Wollte das nur loswerden. Nicht weil ich vor den Möglichkeiten des
Formatstrings nichts halte (ganz im Gegenteil), sondern weil scanf
oftmals nicht die Lösung darstellt, sondern der Weg oft genug über
sscanf führt.