Gast
#1799741
Hallo! ich bekomme immer einen RST, mehr kann mein code nicht...?!? ATMEGA32 mit WINAVR, AVRStudio 4
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
|
Anzeige
|
RST bei Buffernutzung
Gast
#1799741
Hallo! ich bekomme immer einen RST, mehr kann mein code nicht...?!? ATMEGA32 mit WINAVR, AVRStudio 4
Bei aller Liebe. Aber was ist jetzt die Frage?
Gast
#1799748
"" entspricht doch '\0' was einem C-String-Ende entspricht. warum kann ich das nicht auch an alle stellen schreiben?
Gast
#1799749
Liegt am ungüstigen Variablennamen -> der Compiler optimiert die weiteren Durchläufe weg! ändere "ui1" zb. zu "dhka"
Gast
#1799750
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.
Gast
#1799755
meine Frage ist, warum ich einen Reset bekomme ab einer Buffergröße größer als 60
Gast
#1799759
ps: mein main hat eine for(;;) schleife in der der UART-RX-buffer abgefragt wird Timo P schrieb: > ps: > > mein main hat eine for(;;) schleife in der der UART-RX-buffer abgefragt > wird Dann zeig bitte das richtige Programm. OK?
Gast
#1799764
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?
Gast
#1799771
ok....
Gast
#1799786
@ 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...
Gast
#1799790
Ich sehe keine Interrupt-Routinen, warum aktivierst du über sei() die Interrupts? 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.
Gast
#1799796
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;
}
Gast
#1799803
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!
Gast
#1799817
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.... Oh Himmel
Da fehlts ja an allen Ecken und Enden in der Stringverarbeitung 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.
Gast
#1799825
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
nicht machen. In buffer ist zu diesem Zeitpunkt kein gültiger String. 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.
Gast
#1799830
die kommands, die ich übermittelt bekomme, werden durch ein \n terminiert. die ausgabe ..<%s>\r... in der for(;;) ist nur zu debugzwecken gedacht.
Gast
#1799832
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; Als Quick-Fix ändere das mal
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.
Gast
#1799869
DANKE! Genau das war mein Fehler, falls ich in der kill_buffer() Fkt. ausschließlich buffer[0]= '\0' setzen wollte..
Gast
#1799884
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.
Gast
#1799885
Argh ich nehm das zurück.. hat er doch, hab nicht aufgepasst. Sorry :)
Gast
#1799894
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"); Was passiert eigentlich, wenn der Benutzer
auf den Tab bei der Eingabe vergisst? Dir ist auch klar, dass der Eingabetext reset::ssid\t (für \t drück ich natürlich den Tabulator) auf diese Abfrage
passt? strncmp eignet sich für solche Auswertungen besser als strstr
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.
Gast
#1799913
Karl heinz Buchegger schrieb: > Was passiert eigentlich, wenn der Benutzer > auf den Tab bei der Eingabe vergisst? dann wird der Ram umsortiert...
Gast
#1799919
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.
Gast
#1799926
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.
Gast
#1799935
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
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)
Gast
#1800684
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....
Gast
#1800700
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.
Gast
#1800722
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?)
Gast
#1800725
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.
Gast
#1800778
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. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|