Timo P schrieb:> int main()> {> uart_puts("RST\r\n");> kill_buffer();
while(1)
{
}
> }
Da fehlt die abschließende Endlosschleife, da sonst das weitere
Verhalten des uC nicht definiert ist (Reset, Programmneustart,...)
Timo P schrieb:> "" entspricht doch '\0' was einem C-String-Ende entspricht. warum kann
Nein das tut es nicht.
"" enstpricht an dieser Stelle der Startadresse eines leeren Strings,
der irgendwo im Speicher liegt.
Strings kann man nicht einfach so zuweisen.
Die Frage ist aber eigentlich:
Was ist eigentlich genau deine Frage?
Floh schrieb:> Timo P schrieb:>> int main()>> {>> uart_puts("RST\r\n");>> kill_buffer();>> while(1)> {> }>>> }>> Da fehlt die abschließende Endlosschleife, da sonst das weitere> Verhalten des uC nicht definiert ist (Reset, Programmneustart,...)
Im Grunde hast du recht.
Allerdings schickt die gcc-Runtime nach einem return von main() den µC
in eine Endlosschleife. So gesehen ist das Verhalten (beim gcc)
definiert.
Karl heinz Buchegger schrieb:> Allerdings schickt die gcc-Runtime nach einem return von main() den µC> in eine Endlosschleife. So gesehen ist das Verhalten (beim gcc)> definiert.
Wieder was gelernt :-)
Timo P schrieb:> mein main hat eine for(;;) schleife in der der UART-RX-buffer abgefragt> wird
davon seh ich nichts im Programmausschnitt??
Wie wärs wenn du mal genau beschreibst, was du erreichen willst, und
dann, was stattdessen passiert?
@ floh:
passiert:
Ständiger Reset! sehe ich an meiner RST\r\n Ausgabe
soll passieren:
µC resettet nicht in einer Tour, ohne überhaupt in meine foreverschleife
zu gelangen...., da vor dem for(;;) der Code den µC zum Reset zwingt...
Dein Absturz wird höchst wahrscheinlich hier seinen Ursprung nehmen
sprintf(s,"<%s> \r",buffer);uart_puts(s);
dein killBuffer hinterlässt nun mal in buffer keinen leeren String.
Damit knallst du mit Sicherheit zuallererst einmal weit über die Grenzen
von s drüber.
Das es mit Buffergrößen kleiner 60 scheinbar(*) funktioniert ist Zufall.
Da erwischt du nur einfach nicht das richtige Byte um das komplette
System zum Crashen zu bringen.
Um einen Buffer, der sowieso nur einen String aufnehmen kann zu löschen,
vulgo den String auf einen Leerstring zu setzen, genügt es das erste
Byte davon auf '\0' zu setzen. Man muss nicht durch das Array durchgehen
und jedes einzelne Byte auf '\0' setzen.
(*) wie gesagt: scheinbar
Du hast trotzdem einen Fehler. Du siehst ihn nur nicht, weil du zufällig
die falschen Bytes im Speicher zerstörst.
weil ich die Interrupts nutzen möchte, aktiviere ich sie auch. Die ISR
arbeitet wunderbar, wenn ich die Buffersize kleiner als 61 wähle!
Falls es interessiert hier die ISR für den uart-empfang:
ISR (USART_RXC_vect)
{
buffer[pwrite]=UDR;
pwrite++;
if(pwrite >= BUFFER_SIZE) pwrite=0;
}
Karl heinz Buchegger schrieb:> Um einen Buffer, der sowieso nur einen String aufnehmen kann zu löschen,> vulgo den String auf einen Leerstring zu setzen, genügt es das erste> Byte davon auf '\0' zu setzen. Man muss nicht durch das Array durchgehen> und jedes einzelne Byte auf '\0' setzen.
ich überprüfe, ob ich ein config:start\n empfangen habe. dazu nutze ich
strstr(). Wenn ich aber nun den Buffer nur an [0] auf '\0' setze, sind
die anderen Zeichen nicht automatisch weg oder?
Oder sucht die Funktion strstr() nur bis zum \0 Zeichen?
Dann wäre das eine Lösung, mit kill_buffer nur die erste Stelle auf das
Stringendezeichen zu setzen...
THX für weitere antwort
Timo P schrieb:> Karl heinz Buchegger schrieb:>> Um einen Buffer, der sowieso nur einen String aufnehmen kann zu löschen,>> vulgo den String auf einen Leerstring zu setzen, genügt es das erste>> Byte davon auf '\0' zu setzen. Man muss nicht durch das Array durchgehen>> und jedes einzelne Byte auf '\0' setzen.>> ich überprüfe, ob ich ein config:start\n empfangen habe. dazu nutze ich> strstr(). Wenn ich aber nun den Buffer nur an [0] auf '\0' setze, sind> die anderen Zeichen nicht automatisch weg oder?
Richtig - Sind sie nicht.
Aber wen kümmerts?
Ein String ist mit dem ersten '\0' Zeichen zu Ende. Was dann noch
dahinter kommt interessiert keinen. Auch die str... Funktionen wissen
das und halten sich daran. So sind Strings in C nun mal definiert.
> Oder sucht die Funktion strstr() nur bis zum \0 Zeichen?
An dieser Stelle ist dann der Hinweis auf ein C-Buch angebracht
> Dann wäre das eine Lösung, mit kill_buffer nur die erste Stelle auf das> Stringendezeichen zu setzen...
Und mach dein s größer!
Wenn im Extremfall dein Buffer voll ist, dann ist da ein String der
Länge 70 drinnen. Der wird aber kaum in s (mit 22 Zeichen) reinpassen!
ok, s ist vergrößert.
ich habe nun in der kill_buffer() nur noch buffer[0] = '\0' gesetzt.
Nun empfange ich nur noch Müll! wenn ich per Terminalprogramm Zeichen
eintippe, empfange ich sie nur noch einzeln wenn ich mal ein \n drin
hatte....
Timo P schrieb:> ok, s ist vergrößert.> ich habe nun in der kill_buffer() nur noch buffer[0] = '\0' gesetzt.>> Nun empfange ich nur noch Müll!
Aber du hast keinen Absturz mehr.
Also: -> nächsten Fehler suchen! UNd du hast noch viele im Programm.
mein Programm hat ja mal gelaufen, als die Buffer kleiner waren!
Ich konnte z.B. erfolgreich eine ssid, die übergeben wurde,
interpretieren.
denken kann ich mir aber, dass hier gemeint ist, dass ich die
string-token funktion nutzen soll...
Wo hab ich denn noch Fehler?
Timo P schrieb:> ISR (USART_RXC_vect)> {> buffer[pwrite]=UDR;> pwrite++;> if(pwrite >= BUFFER_SIZE) pwrite=0;> }
Das ist deine Empfangsfunktion?
Dann kannst du das hier
Timo P schrieb:> mein Programm hat ja mal gelaufen, als die Buffer kleiner waren!
Dein Programm hat höchstens zufällig keinen Absturz produziert.
Korrekt gelaufen ist das nie. Zumindest nicht solange, solange du keine
korrekt terminierten Strings hast.
Timo P schrieb:> {
...
> if(trigger == 1)trigger = 0;> if(trigger == 0)trigger = 1;> uart_puts("00TOK\n");
Ähm.. ist das so gewollt, das trigger nicht 0 werden kann?
Oder wolltest du vielleicht schreiben
if (trigger == 1) then
trigger == 0;
else
trigger == 1;
Oder, kurzform:
trigger = (trigger) ? 0 : 1;
Hallo,
Karl heinz Buchegger schrieb:> damit hast du zumindest im Input-Buffer ständig einen insofern gültigen> C-String, als das er nach dem zuletzt empfangenen Zeichen 0-terminiert> ist.
hat er nicht (glaube ich... ;-)
Wenn USART_RXC_vect hier wieder das erste Zeichen des Buffers mit einem
gültigen Zeichen überschreibt, sieht jede String-Funktion in C wieder
den gesamten Buffer, plus das was dahinter im Speicher folgt (wenn nicht
irgendwo im Buffer wieder ein /0 steht).
Wenn man es schon so machen muß wie der TE dann vllt. so:
#define BUFFER_SIZE 70 //buffergröße in Byte
volatile unsigned char buffer[1 + BUFFER_SIZE];
...
buffer[BUFFER_SIZE] == 0;
Damit wäre der Buffer immer NULL-Terminiert.
hab ich wohl, denn, wenn der RX-Interrupt das erste Zeichen
überschreibt, hängt er automatisch ein '\0' an dank shiften des writer
pointers um genu diese Bitbreite, die die Bufferelemente auch
besitzen.....
so läuft es perfekt!
Ago hat sich ins Boxhorn jagen lassen durch deine Variablen und der
Tatsache dass du den Index am Ende des Buffers wieder auf 0 setzt. Er
dachte das wäre ein Ringbuffer. Das ist er aber nicht. Sieht nur auf den
ersten Blick so aus.
Ago schrieb:> Ähm.. ist das so gewollt, das trigger nicht 0 werden kann?>> Oder wolltest du vielleicht schreiben>> if (trigger == 1) then> trigger == 0;> else> trigger == 1;
mit dem else hat ers nicht so
if(PORTA&(1<<PIN))uart_puts("00S1\n");
if((PORTA&(1<<PIN)) == 0)uart_puts("00S0\n");
Dir ist auch klar, dass der Eingabetext
reset::ssid\t
(für \t drück ich natürlich den Tabulator)
auf diese Abfrage
1
elseif(strstr(buffer,"set:ssid\t"))
passt?
strncmp eignet sich für solche Auswertungen besser als strstr
1
elseif(strncmp(buffer,"set::ssid\t",10)==0)
jetzt muss der String mit "set::ssid\t" anfangen, nur dann gilt der Text
als erkannt. reset::ssid\t passt jetzt nicht mehr.
Vielleicht hängt ja am anderen Ende der Leitung kein Mensch, aber die
Sache mit dem \t würde ich mir insgesammt nochmal überlegen. Es sei denn
natürlich, das da ein anderes Programm deinen µC füttert und dort ist
das schon so festgelegt.
aus if...if ist längst ein if else geworden.
Mir ist auch bewusst, dass ich ein Bit aus einem 8-Bit char einzeln
toggeln könnte.
Dann müsste ich aber wieder die Bitmasken nutzen, sowohl bei der
Zuweisung, als auch bei der Abfrage des Flags...
Timo P schrieb:> aus if...if ist längst ein if else geworden.>> Mir ist auch bewusst, dass ich ein Bit aus einem 8-Bit char einzeln> toggeln könnte.
Eine Schreibweise, die mir persönlich gut gefällt
trigger = 1 - trigger;
keine Ahnung warum, aber ich finde das hat was :-)
> Dann müsste ich aber wieder die Bitmasken nutzen, sowohl bei der> Zuweisung, als auch bei der Abfrage des Flags...
na, na
trigger ^= 0x01;
so schlimm ist das auch wieder nicht.
Besser als
if(trigger == 1)trigger = 0;
else if(trigger == 0)trigger = 1;
ist es allemal.
dann frage ich aber auch das "0-te" Bit ab.... Dann gehts....
Oder ich hab mal was von Bitmasken gesehen, ein Strukt, in dem 8 Bits
sind. Diese kann ich dann über ein define nutzen, quasi ein eigenes sbit
für die AVRs, die ja keine bitadressierung haben.....
Timo P schrieb:> dann frage ich aber auch das "0-te" Bit ab.... Dann gehts....
kannst du natürlich machen.
Aber bei all den Alternativvorschlägen ging es bisher immer nur darum,
trigger zwischen 0 und 1 hin und her wechseln zu lassen. Das machen alle
bisher hervorgebrachten Alternativen. Manche der Alternativen haben noch
einen zuätzlichen Nebeneffekt bzw. zusätzliche Eigenschaften, der/die
hier bei dir nicht zum tragen kommt, da trigger offenbar sowieso nur 0
und 1 sein kann und auch das auch so sein soll.
Hier habe ich genug speicher und nutze ein komplettes byte als flag aus.
Missbrauch?!? ok, soll jeder so sehen, wie er es möchte.
Im übrigen sind alle commands, die hier zum tragen kommen, von einer GUI
am PC über USB zum µC übertragen.
Daraus erzeuge ich dann andere Commands, die ich an ein WLAN-Modul
übertrage.
Timo P schrieb:> Hier habe ich genug speicher und nutze ein komplettes byte als flag aus.> Missbrauch?!? ok, soll jeder so sehen, wie er es möchte.
Darum gehts nicht.
Das hier
1
if(trigger==1)trigger=0;
2
elseif(trigger==0)trigger=1;
ist für deinen µC so ziemlich die aufwändigste Methode, das Gewünschte
zu erreichen.
>> Im übrigen sind alle commands, die hier zum tragen kommen, von einer GUI> am PC über USB zum µC übertragen.
ok. nehm ich zur Kentniss. Also musst du nicht besondere Sorgfalt in der
Auswertung walten lassen. Du kannst davon ausgehen, dass der String
immer vollständig und wohl geformt ist (abgesehen von
Übertragungsfehlern natürlich)
ist gemeint, dass die Übertragungsfehler mindestens mit genau der selben
Entgegnung/Auswertung optimiert werden sollen, wie Fehleingaben?
Oder hieß das, dass ich drauf vertrauen könnte? Wenn die GUI mir
set:ssid\thier_die_ssid\t\n
sendet, ich aber nicht mit einem
set:ssid:OK\n
antworte, weiß die Gui, dass sie erneut senden muss. Selbstverständlich
versucht sie es nicht hunderte mal....
Timo P schrieb:> ist gemeint, dass die Übertragungsfehler mindestens mit genau der selben> Entgegnung/Auswertung optimiert werden sollen, wie Fehleingaben?
nein, das nicht. Aber dein Programm macht nach den vergessenen tab
nichts mehr sinnvollens. Du musst also den µC neu starten.
Das ist doch mal nen Argument...
strstr hätte den vorteil:
&$?=config:start\n wird von mir auch interpretiert, falls sich diese
Zeichen vor config:start\n einschleichen sollten.
das strncmp klingt auch gut. (Welcher Vorteil ergibt sich praktisch
durch das n, also die Angabe der Anzahl der zu prüfenden zeichen?)
für die \t\t fehlerabfrage würde ich eine mindestgröße von sagen wir 1
zeichen festlgegen, bei der mein code ein ...OK zurücksendet und die
Daten in das entsprechende array schreibt.
Timo P schrieb:> Das ist doch mal nen Argument...>> strstr hätte den vorteil:>> &$?=config:start\n wird von mir auch interpretiert, falls sich diese> Zeichen vor config:start\n einschleichen sollten.
die Frage ist ob du das überhaupt willst.
Falls sich da vor config::start\n ein paar Zeichen eingeschlichen haben,
die da eigentlich nicht hingehören, woher willst du dann wissen, dass
dieses config::start nicht eigentlich auch fehlerhaft ist und eigentlich
gar nicht da hingehört?
> das strncmp klingt auch gut. (Welcher Vorteil ergibt sich praktisch> durch das n, also die Angabe der Anzahl der zu prüfenden zeichen?)
Ich muss meinen String nicht in Einzelteile zerlegen
Dieser strncmp ist das Equivalent zu: Wenn die ersten n Buchstaben
(sofern es überhaupt n gibt) diesen Text hier bilden, dann ist alles
gut.
Karl heinz Buchegger schrieb:> dann ist alles> gut.
klingt doch super ;)
nein im Ernst, Danke für die Anregungen zu meinem code. Sicher, man kann
leute auf ein C-Buch verweisen. Aber irgendwie schreibt man dann doch
auch mal mist zusammen. Sehen wir ja hier. Danke für eure Anregungen,
nur so kann ich mich ja verbessern!
Weiter so im Forum!
Timo P schrieb:> auch mal mist zusammen. Sehen wir ja hier. Danke für eure Anregungen,> nur so kann ich mich ja verbessern!
Das allerwichtigste bei der Arbeit mit Strings in C:
Du musst dir bei jeder Aktion immer im klaren sein, dass es kein
Fangnetz gibt. Wenn du, aus welchem Grund auch immer, versuchst 20
Zeichen in ein char-Array der Länge 10 zu quetschen, dann wird das
grauslich schief gehen. Nicht nur das, es werden unter Umständen
seltsame Phenomäne in deinem Programm auftauchen, Dinge die bisher schon
funktioniert haben werden plötzlich nicht mehr funktionieren,
Berechnungen liefern falsche Ergebnisse, Funktionsreturns landen
plötzlich nicht mehr an der Stelle an der die Funktion aufgerufen wurde
etc.
Daher: Bei jeglicher Stringaktion lieber konservativ arbeiten. Was kann
schief gehen? Wenn du den String von einem Benutzer hast: Nicht darauf
verlassen, dass der alles richtig eingibt. Wenn Strings über eine
Leitung übertragen werden: Auch wenn es mitlerweile selten vorkommt,
aber es gibt sie noch, die Übertragungsfehler.
Das mindeste, was man immer tun sollte, so lange man im Programm nicht
sicher gestellt hat, das der String nicht zu lang sein kann:
Wenn man einen String (oder Teilstring) in ein anderes Array umkopiert,
immer die Länge des Zielarrays im Auge behalten und notfalls das
Umkopieren abwürgen, wenn man das Ziel überläuft!
Nicht wenige der frühen Hacker-Angriffe auf andere Rechner sind genau
über solche Schlupflöcher gelaufen: Man hat ins Programm einen sehr
langen String eingespielt, weil man genau wusste das dort und dort in
der Umkopierschleife keine Sicherung gegen Überlaufen enthalten ist.
Damit hat das Programm selber den Schadcode an die richtige Stelle im
Speicher kopiert und das Tor aufgemacht.